Von NativeActivity migrieren   Teil des Android Game Development Kits.

Auf dieser Seite wird beschrieben, wie Sie in Ihrem Android-Spielprojekt von NativeActivity zu GameActivity migrieren.

GameActivity basiert auf NativeActivity aus dem Android-Framework mit Verbesserungen und neuen Funktionen:

  • Unterstützt Fragment von Jetpack.
  • Unterstützung für TextInput hinzugefügt, um die Integration der Soft-Tastatur zu erleichtern.
  • Verarbeitet Touch- und Tastenereignisse in der GameActivity Java-Klasse und nicht über die NativeActivity onInputEvent-Schnittstelle.

Bevor Sie mit der Migration beginnen, empfehlen wir Ihnen, den Einstiegsleitfaden zu lesen. Dort wird beschrieben, wie Sie GameActivity in Ihrem Projekt einrichten und einbinden.

Aktualisierungen des Java-Build-Scripts

GameActivity wird als Jetpack-Bibliothek verteilt. Führen Sie die Schritte zum Aktualisieren des Gradle-Scripts aus, die im Einstiegsleitfaden beschrieben sind:

  1. Aktivieren Sie die Jetpack-Bibliothek in der Datei gradle.properties Ihres Projekts:

    android.useAndroidX=true
    
  2. Optional können Sie in derselben gradle.properties-Datei eine Prefab-Version angeben, z. B.:

    android.prefabVersion=2.0.0
    
  3. Aktivieren Sie die Prefab-Funktion in der Datei build.gradle Ihrer App:

    android {
        ... // other configurations
        buildFeatures.prefab true
    }
    
  4. Fügen Sie Ihrer Anwendung die Abhängigkeit GameActivity hinzu:

    1. Fügen Sie die Bibliotheken core und games-activity hinzu.
    2. Wenn das derzeit unterstützte Mindest-API-Level unter 16 liegt, aktualisieren Sie es auf mindestens 16.
    3. Aktualisieren Sie die kompilierte SDK-Version auf die Version, die die games-activity-Bibliothek benötigt. Für Jetpack ist in der Regel die neueste SDK-Version erforderlich, die zum Zeitpunkt der Buildzeit der Veröffentlichung verfügbar ist.

    Ihre aktualisierte build.gradle-Datei könnte in etwa so aussehen:

    android {
        compiledSdkVersion 33
        ... // other configurations.
        defaultConfig {
            minSdkVersion 16
        }
        ... // other configurations.
    
        buildFeatures.prefab true
    }
    dependencies {
        implementation 'androidx.core:core:1.9.0'
        implementation 'androidx.games:games-activity:1.2.2'
    }
    

Aktualisierungen des Kotlin- oder Java-Codes

NativeActivity kann als Startaktivität verwendet werden und erstellt eine Vollbildanwendung. Derzeit kann „GameActivity“ nicht als Startaktivität verwendet werden. Apps müssen eine Klasse von GameActivity ableiten und diese als Startaktivität verwenden. Außerdem müssen Sie zusätzliche Konfigurationsänderungen vornehmen, um eine Vollbild-App zu erstellen.

Bei den folgenden Schritten wird davon ausgegangen, dass Ihre Anwendung NativeActivity als Startaktivität verwendet. Andernfalls können Sie die meisten davon überspringen.

  1. Erstellen Sie eine Kotlin- oder Java-Datei, um die neue Startaktivität zu hosten. Mit dem folgenden Code wird beispielsweise MainActivity als Startaktivität erstellt und die Haupt-native Bibliothek der Anwendung, libAndroidGame.so, geladen:

    Kotlin

    class MainActivity : GameActivity() {
       override fun onResume() {
           super.onResume()
           // Use the function recommended from the following page:
           // https://d.android.com/training/system-ui/immersive
           hideSystemBars()
       }
       companion object {
           init {
               System.loadLibrary("AndroidGame")
           }
       }
    }

    Java

      public class MainActivity extends GameActivity {
          protected void onResume() {
              super.onResume();
              // Use the function recommended from
              // https://d.android.com/training/system-ui/immersive
              hideSystemBars();
          }
          static {
              System.loadLibrary("AndroidGame");
          }
      }
  2. Erstellen Sie in der Datei res\values\themes.xml ein Vollbild-App-Design:

    <resources xmlns:tools="http://schemas.android.com/tools">
        <!-- Base application theme. -->
        <style name="Application.Fullscreen" parent="Theme.AppCompat.Light.NoActionBar">
            <item name="android:windowFullscreen">true</item>
            <item name="android:windowContentOverlay">@null</item>"
        </style>
    </resources>
    
  3. Wenden Sie das Design auf die Anwendung in der Datei AndroidManifest.xml an:

    <application  android:theme=”@style/Application.Fullscreen”>
         <!-- other configurations not listed here. -->
    </application>
    

    Eine ausführliche Anleitung für den Vollbildmodus finden Sie im Leitfaden für immersive Inhalte und in der Beispielimplementierung im Repository „games-samples“.

In dieser Migrationsanleitung wird der Name der nativen Bibliothek nicht geändert. Wenn Sie ihn ändern, achten Sie darauf, dass die Namen der nativen Bibliotheken an den folgenden drei Stellen übereinstimmen:

  • Kotlin- oder Java-Code:

    System.loadLibrary(AndroidGame)
    
  • AndroidManifest.xml:

    <meta-data android:name="android.app.lib_name"
            android:value="AndroidGame" />
    
  • In der C/C++-Build-Scriptdatei, z. B. CMakeLists.txt:

    add_library(AndroidGame ...)
    

Aktualisierungen des C/C++-Build-Scripts

In der Anleitung in diesem Abschnitt wird cmake als Beispiel verwendet. Wenn Ihre Anwendung ndk-build verwendet, müssen Sie sie den entsprechenden Befehlen zuordnen, die auf der Dokumentationsseite für ndk-build beschrieben sind.

Die C/C++-Implementierung von GameActivity wurde mit einem Quellcode veröffentlicht. Ab Version 1.2.2 wird ein Release als statische Bibliothek bereitgestellt. Die statische Bibliothek ist der empfohlene Release-Typ.

Die Version wird mit dem Dienstprogramm prefab in das AAR verpackt. Der native Code umfasst die C/C++-Quellen von GameActivity und den native_app_glue-Code. Sie müssen zusammen mit dem C/C++-Code Ihrer Anwendung erstellt werden.

NativeActivity-Anwendungen verwenden bereits den native_app_glue-Code, der im NDK enthalten ist. Sie müssen sie durch die Version von native_app_glue für GameActivity ersetzen. Ansonsten gelten alle cmake Schritte, die in der Anleitung für den Einstieg beschrieben sind:

  • Importieren Sie entweder die C/C++-Static-Library oder den C/C++-Quellcode in Ihr Projekt. Gehen Sie dazu so vor:

    Statische Bibliothek

    Importieren Sie in der Datei CMakeLists.txt Ihres Projekts die statische Bibliothek game-activity in das PreFab-Modul game-activity_static:

    find_package(game-activity REQUIRED CONFIG)
    target_link_libraries(${PROJECT_NAME} PUBLIC log android
    game-activity::game-activity_static)
    

    Quellcode

    Importieren Sie das game-activity-Paket in die CMakeLists.txt-Datei Ihres Projekts und fügen Sie es dem Ziel hinzu. Für das game-activity-Paket ist libandroid.so erforderlich. Wenn es fehlt, müssen Sie es auch importieren.

    find_package(game-activity REQUIRED CONFIG)
    ...
    target_link_libraries(... android game-activity::game-activity)
    
  • Entfernen Sie alle Verweise auf den native_app_glue-Code des NDK, z. B.:

    ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c
        ...
    set(CMAKE_SHARED_LINKER_FLAGS
        "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
    
  • Wenn Sie die Quellcodeversion verwenden, fügen Sie die GameActivity-Quelldateien hinzu. Andernfalls überspringen Sie diesen Schritt.

    get_target_property(game-activity-include
                        game-activity::game-activity
                        INTERFACE_INCLUDE_DIRECTORIES)
    add_library(${PROJECT_NAME} SHARED
        main.cpp
        ${game-activity-include}/game-activity/native_app_glue/android_native_app_glue.c
        ${game-activity-include}/game-activity/GameActivity.cpp
        ${game-activity-include}/game-text-input/gametextinput.cpp)
    

Problem „UnsatisfiedLinkError“ umgehen

Wenn Sie für die Funktion com.google.androidgamesdk.GameActivity.initializeNativeCode() ein UnsatsifiedLinkError sehen, fügen Sie der Datei CMakeLists.txt diesen Code hinzu:

set(CMAKE_SHARED_LINKER_FLAGS
    "${CMAKE_SHARED_LINKER_FLAGS} -u \
    Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")

Aktualisierungen des C/C++-Quellcodes

So ersetzen Sie Verweise auf NativeActivity in Ihrer Bewerbung durch GameActivity:

  • Verwenden Sie die native_app_glue, die mit GameActivity veröffentlicht wurde. Suche nach allen Verwendungen von android_native_app_glue.h und ersetzte sie durch:

    #include <game-activity/native_app_glue/android_native_app_glue.h>
    
  • Legen Sie sowohl den Bewegungsereignisfilter als auch den Schlüsselereignisfilter auf NULL fest, damit Ihre App Eingabeereignisse von allen Eingabegeräten empfangen kann. Normalerweise geschieht dies in der android_main()-Funktion:

    void android_main(android_app* app) {
        ... // other init code.
    
        android_app_set_key_event_filter(app, NULL);
        android_app_set_motion_event_filter(app, NULL);
    
        ... // additional init code, and game loop code.
    }
    
  • Entfernen Sie den Code im Zusammenhang mit AInputEvent und ersetzen Sie ihn durch die InputBuffer-Implementierung von GameActivity:

    while (true) {
        // Read all pending events.
        int events;
        struct android_poll_source* source;
    
        // If not animating, block forever waiting for events.
        // If animating, loop until all events are read, then continue
        // to draw the next frame of animation.
        while ((ALooper_pollOnce(engine.animating ? 0 : -1, nullptr, &events,
                                (void**)&source)) >= 0) {
           // Process this app cycle or inset change event.
           if (source) {
               source->process(source->app, source);
           }
    
              ... // Other processing.
    
           // Check if app is exiting.
           if (state->destroyRequested) {
               engine_term_display(&engine);
               return;
           }
        }
        // Process input events if there are any.
        engine_handle_input(state);
    
       if (engine.animating) {
           // Draw a game frame.
       }
    }
    
    // Implement input event handling function.
    static int32_t engine_handle_input(struct android_app* app) {
       auto* engine = (struct engine*)app->userData;
       auto ib = android_app_swap_input_buffers(app);
       if (ib && ib->motionEventsCount) {
           for (int i = 0; i < ib->motionEventsCount; i++) {
               auto *event = &ib->motionEvents[i];
               int32_t ptrIdx = 0;
               switch (event->action & AMOTION_EVENT_ACTION_MASK) {
                   case AMOTION_EVENT_ACTION_POINTER_DOWN:
                   case AMOTION_EVENT_ACTION_POINTER_UP:
                       // Retrieve the index for the starting and the ending of any secondary pointers
                       ptrIdx = (event->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
                                AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
                   case AMOTION_EVENT_ACTION_DOWN:
                   case AMOTION_EVENT_ACTION_UP:
                       engine->state.x = GameActivityPointerAxes_getAxisValue(
                           &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X);
                       engine->state.y = GameActivityPointerAxes_getAxisValue(
                           &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y);
                       break;
                    case AMOTION_EVENT_ACTION_MOVE:
                    // Process the move action: the new coordinates for all active touch pointers
                    // are inside the event->pointers[]. Compare with our internally saved
                    // coordinates to find out which pointers are actually moved. Note that there is
                    // no index embedded inside event->action for AMOTION_EVENT_ACTION_MOVE (there
                    // might be multiple pointers moved at the same time).
                        ...
                       break;
               }
           }
           android_app_clear_motion_events(ib);
       }
    
       // Process the KeyEvent in a similar way.
           ...
    
       return 0;
    }
    
  • Prüfen und aktualisieren Sie die Logik, die mit der AInputEvent von NativeActivity verknüpft ist. Wie im vorherigen Schritt gezeigt, erfolgt die InputBuffer-Verarbeitung von GameActivity außerhalb der ALooper_pollOnce()-Schleife.

  • Ersetzen Sie android_app::activity->clazz durch android_app:: activity->javaGameActivity. GameActivity benennt die Java-GameActivity-Instanz um.

Weitere Schritte

In den vorherigen Schritten wurden die Funktionen von NativeActivity beschrieben. GameActivity bietet jedoch zusätzliche Funktionen, die Sie möglicherweise verwenden möchten:

Wir empfehlen Ihnen, diese Funktionen zu testen und sie nach Bedarf für Ihre Spiele zu verwenden.

Wenn Sie Fragen oder Empfehlungen zu GameActivity oder anderen AGDK-Bibliotheken haben, erstellen Sie einen Fehlerbericht.