Migrate from NativeActivity Part of Android Game Development Kit.
This page describes how to migrate from
NativeActivity to
GameActivity in your Android game project.
GameActivity is based on NativeActivity from the Android
framework, with enhancements and new features:
- Supports
Fragmentfrom Jetpack. - Adds
TextInputsupport to facilitate soft keyboard integration. - Handles touch and key events in the
GameActivityJava class rather than theNativeActivityonInputEventinterface.
Before migrating, we recommend reading the
get started guide, which describes how
to set up and integrate GameActivity in your project.
Java build script updates
GameActivity is distributed as a
Jetpack library. Make sure to apply the Gradle script updating steps described
in the get started guide:
Enable Jetpack library in your project’s
gradle.propertiesfile:android.useAndroidX=trueOptionally, specify a Prefab version, in the same
gradle.propertiesfile, for example:android.prefabVersion=2.0.0Enable Prefab feature in your app’s
build.gradlefile:android { ... // other configurations buildFeatures.prefab true }Add the
GameActivitydependency to your application:- Add the
coreandgames-activitylibraries. - If your current minimum supported API level is less than 16, update it to at least 16.
- Update the compiled SDK version to the one that the
games-activitylibrary requires. Jetpack typically requires the latest SDK version at the release build time.
Your updated
build.gradlefile might look something like this: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' }- Add the
Kotlin or Java code updates
NativeActivity can be used as a startup activity and creates a full screen
application. At present, GameActivity cannot be used as the startup
activity. Apps must derive a class from GameActivity and use that as
the startup activity. You must also make additional configuration changes to
create a full screen app.
The following steps assume your application uses NativeActivity as the startup
activity. If that is not the case, you can skip most of them.
Create a Kotlin or Java file to host the new startup activity. For example, the following code creates the
MainActivityas the startup activity and loads the application’s main native library,libAndroidGame.so: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"); } }
Create a full screen app theme in the
res\values\themes.xmlfile:<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>Apply the theme to the application in the
AndroidManifest.xmlfile:<application android:theme=”@style/Application.Fullscreen”> <!-- other configurations not listed here. --> </application>For detailed instructions for full screen mode, see to the immersive guide and example implementation in the games-samples repo.
This migration guide does not change the native library name. If you do change it, ensure the native library names are consistent in the following three locations:
Kotlin or Java code:
System.loadLibrary(“AndroidGame”)AndroidManifest.xml:<meta-data android:name="android.app.lib_name" android:value="AndroidGame" />Inside the C/C++ build script file, for example
CMakeLists.txt:add_library(AndroidGame ...)
C/C++ build script updates
The instructions in this section use cmake as the example. If your application
uses ndk-build, you need to map them to the equivalent commands described in
ndk-build documentation page.
GameActivity’s C/C++ implementation has been providing a source code release. For version 1.2.2 a later, a static library release is provided. The static library is the recommended release type.
The release is packed inside the AAR with the
prefab
utility. The native code includes GameActivity’s C/C++ sources and the
native_app_glue code. They need to be built together with your
application's C/C++ code.
NativeActivity applications already use the native_app_glue
code shipped inside NDK. You must replace it with GameActivity’s version
of native_app_glue. Other than that, all cmake steps documented inside
the getting started guide apply:
Import either the C/C++ static library or the C/++ source code into your project as follows.
Static library
In your project's
CMakeLists.txtfile, import thegame-activitystatic library into thegame-activity_staticprefab module:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)Source code
In your project's
CMakeLists.txtfile, import thegame-activitypackage and add it to your target. Thegame-activitypackage requireslibandroid.so, so if it's missing, you must also import it.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)Remove all references to NDK’s
native_app_gluecode, such as:${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ... set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")If you are using the source code release, include the
GameActivitysource files. Otherwise, skip this step.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)
Work around the UnsatisfiedLinkError issue
If you encounter an UnsatsifiedLinkError for the
com.google.androidgamesdk.GameActivity.initializeNativeCode() function, add
this code to your CMakeLists.txt file:
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u \
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")
C/C++ source code updates
Follow these steps to replace NativeActivity references in your
application with GameActivity:
Use the
native_app_gluereleased withGameActivity. Search and replace allandroid_native_app_glue.husage with:#include <game-activity/native_app_glue/android_native_app_glue.h>Set both motion event filter and key event filter to
NULLso your app can receive input events from all input devices. You typically do this insideandroid_main()function: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. }Remove
AInputEventrelated code, and replace it with GameActivity’sInputBufferimplementation: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; }Review and update logic that attached to NativeActivity’s
AInputEvent. As shown in the previous step, GameActivity’sInputBufferprocessing is outside theALooper_pollOnce()loop.Replace
android_app::activity->clazzusage withandroid_app:: activity->javaGameActivity. GameActivity renames the JavaGameActivityinstance.
Additional steps
The previous steps cover NativeActivity's functionality, but GameActivity has
additional features that you might want to use:
- TextInput.
- Game Controller.
- Fragment.
- New window InSets commands defined in NativeAppGlueAppCmd.
We recommend exploring these features and adopting them as appropriate for your games.
If you have any questions or recommendations for GameActivity or other AGDK libraries, create a bug to let us know.