Von NativeActivity migrieren Teil des Android Game Development Kit.
Auf dieser Seite wird beschrieben, wie Sie in Ihrem Android-Spielprojekt von NativeActivity
zu GameActivity
migrieren.
GameActivity
basiert auf NativeActivity
aus dem Android-Framework und bietet Verbesserungen und neue Funktionen:
- Unterstützt
Fragment
aus Jetpack. - Fügt
TextInput
-Unterstützung hinzu, um die Integration der Bildschirmtastatur zu erleichtern. - Verarbeitet Touch- und Tastaturereignisse in der Java-Klasse
GameActivity
anstelle der SchnittstelleNativeActivity
onInputEvent
.
Vor der Migration empfehlen wir Ihnen, die Anleitung für den Einstieg zu lesen. Dort wird beschrieben, wie Sie GameActivity
in Ihrem Projekt einrichten und einbinden.
Aktualisierungen des Java-Build-Skripts
GameActivity
wird als Jetpack-Bibliothek verteilt. Achten Sie darauf, dass Sie die im Startleitfaden beschriebenen Schritte zum Aktualisieren des Gradle-Skripts ausführen:
Aktivieren Sie die Jetpack-Bibliothek in der Datei
gradle.properties
Ihres Projekts:android.useAndroidX=true
Optional können Sie in derselben
gradle.properties
-Datei eine Prefab-Version angeben, z. B.:android.prefabVersion=2.0.0
Aktivieren Sie die Prefab-Funktion in der Datei
build.gradle
Ihrer App:android { ... // other configurations buildFeatures.prefab true }
Fügen Sie Ihrer Anwendung die Abhängigkeit
GameActivity
hinzu:- Fügen Sie die Bibliotheken
core
undgames-activity
hinzu. - Wenn Ihr aktuelles Mindest-API-Level unter 16 liegt, aktualisieren Sie es auf mindestens 16.
- Aktualisieren Sie die kompilierte SDK-Version auf die Version, die für die
games-activity
-Bibliothek erforderlich ist. Für Jetpack ist in der Regel die neueste SDK-Version zum Zeitpunkt des Release-Builds erforderlich.
Ihre aktualisierte
build.gradle
-Datei könnte 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' }
- Fügen Sie die Bibliotheken
Aktualisierungen von Kotlin- oder Java-Code
NativeActivity
kann als Startaktivität verwendet werden und erstellt eine Vollbildanwendung. Derzeit kann GameActivity nicht als Start-Activity 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. Wenn das nicht der Fall ist, können Sie die meisten überspringen.
Erstellen Sie eine Kotlin- oder Java-Datei für die neue Startaktivität. Mit dem folgenden Code wird beispielsweise
MainActivity
als Startaktivität erstellt und die native Hauptbibliothek 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"); } }
Erstellen Sie in der Datei
res\values\themes.xml
ein Design für eine Vollbild-App:<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>
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 detaillierte Anleitung für den Vollbildmodus finden Sie in diesem Leitfaden und eine Beispielimplementierung in diesem Repository.
Der Name der nativen Bibliothek wird durch diesen Migrationsleitfaden nicht geändert. Wenn Sie den Namen ändern, müssen 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-Skriptdatei, z. B.
CMakeLists.txt
:add_library(AndroidGame ...)
Aktualisierungen des C/C++-Build-Skripts
In den Anleitungen 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 zu ndk-build beschrieben sind.
Die C/C++-Implementierung von GameActivity wurde als Quellcode veröffentlicht. Ab Version 1.2.2 ist ein Release als statische Bibliothek verfügbar. Die statische Bibliothek ist der empfohlene Release-Typ.
Das Release ist im AAR mit dem Dienstprogramm prefab
enthalten. 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 GameActivity-Version von native_app_glue
ersetzen. Ansonsten gelten alle in der Anleitung für den Einstieg dokumentierten cmake
-Schritte:
Importieren Sie die statische C/C++-Bibliothek oder den C/C++-Quellcode wie unten beschrieben in Ihr Projekt.
Statische Bibliothek
Importieren Sie in der Datei
CMakeLists.txt
Ihres Projekts die statische Bibliothekgame-activity
in das Prefab-Modulgame-activity_static
:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)
Quellcode
Importieren Sie in der Datei
CMakeLists.txt
Ihres Projekts das Paketgame-activity
und fügen Sie es Ihrem Ziel hinzu. Für das Paketgame-activity
istlibandroid.so
erforderlich. Wenn es fehlt, müssen Sie es also 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 Quellcode-Version verwenden, fügen Sie die
GameActivity
-Quelldateien ein. 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)
Das Problem „UnsatisfiedLinkError“ umgehen
Wenn Sie einen UnsatsifiedLinkError
für die Funktion com.google.androidgamesdk.GameActivity.initializeNativeCode()
erhalten, fügen Sie diesen Code in Ihre CMakeLists.txt
-Datei ein:
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u \
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")
Aktualisierungen des C/C++-Quellcodes
So ersetzen Sie NativeActivity
-Verweise in Ihrer Anwendung durch GameActivity
:
Verwenden Sie die
native_app_glue
, die mitGameActivity
veröffentlicht wurde. Suchen Sie nach allen Verwendungen vonandroid_native_app_glue.h
und ersetzen Sie sie durch:#include <game-activity/native_app_glue/android_native_app_glue.h>
Stelle sowohl den Filter für Bewegungsereignisse als auch den Filter für Schlüsselereignisse auf
NULL
ein, damit deine App Eingabeereignisse von allen Eingabegeräten empfangen kann. Normalerweise geschieht dies in der Funktionandroid_main()
: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
AInputEvent
-bezogenen Code und ersetzen Sie ihn durch dieInputBuffer
-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 an
AInputEvent
von NativeActivity angehängt ist. Wie im vorherigen Schritt gezeigt, erfolgt die Verarbeitung vonInputBuffer
GameActivityALooper_pollOnce()
außerhalb derALooper_pollOnce()
-Schleife.Ersetzen Sie die Verwendung von
android_app::activity->clazz
durchandroid_app:: activity->javaGameActivity
. Mit GameActivity wird die Java-InstanzGameActivity
umbenannt.
Zusätzliche Schritte
Die vorherigen Schritte decken die Funktionen von NativeActivity ab. GameActivity
bietet jedoch zusätzliche Funktionen, die Sie möglicherweise verwenden möchten:
- TextInput
- Controller
- Fragment.
- Neue InSets-Befehle für Fenster, die in NativeAppGlueAppCmd definiert sind.
Wir empfehlen Ihnen, diese Funktionen auszuprobieren und sie gegebenenfalls in Ihre Spiele zu integrieren.
Wenn Sie Fragen oder Empfehlungen zu GameActivity oder anderen AGDK-Bibliotheken haben, erstellen Sie einen Fehlerbericht, um uns darüber zu informieren.