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=true
- Optionally, specify a Prefab version, in the same - gradle.propertiesfile, for example:- android.prefabVersion=2.0.0
- Enable 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 the- game-activitystatic library into the- game-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 the- game-activitypackage and add it to your target. The- game-activitypackage requires- libandroid.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 with- GameActivity. Search and replace all- android_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 inside- android_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’s- InputBufferimplementation:- 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’s- InputBufferprocessing is outside the- ALooper_pollOnce()loop.
- Replace - android_app::activity->clazzusage with- android_app:: activity->javaGameActivity. GameActivity renames the Java- GameActivityinstance.
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.
