Skip to content

Commit cc2621e

Browse files
committed
Expand documentation for native-activity sample.
This expands the docs and comments in the native-activity sample to be something closer to a proper guide. There isn't a very clear flow to it since the documentation is necessarily spread out into multiple files, and sometimes the order of the code requires explaining things out of order, but it's better than nothing. If we wanted to turn this into an actual guide that could be written in a clear order without duplicating code snippets into the docs, which would surely be quickly out of date, we could use something like sphinx (possibly through readthedocs) to generate something closer to a literate code sample.
1 parent 371c261 commit cc2621e

File tree

5 files changed

+221
-77
lines changed

5 files changed

+221
-77
lines changed

native-activity/README.md

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,69 @@
11
# Native Activity
22

3+
> [!WARNING]
4+
> **Most apps should not use the app development model shown in this sample**.
5+
> Instead, use a Java or Kotlin `AppCompatActivity` and connect your native code
6+
> using JNI like the other samples in this repository. `NativeActivity` and
7+
> `GameActivity` attempt to translate the Android [activity lifecycle] into a
8+
> desktop style `main()` function with a polled event loop. That is not how
9+
> Android apps work, and while it may help you get your prototype running more
10+
> quickly, as your app matures you will likely end up retranslating the
11+
> `native_app_glue` model to again look like `Activity`.
12+
313
This is an Android sample that uses [NativeActivity] with `native_app_glue`,
414
which enables building NDK apps without having to write any Java code. In
515
practice most apps, even games which are predominantly native code, will need to
6-
call some Java APIs or customize their app's activity further.
16+
call some Java APIs or customize their app's activity further. While it may save
17+
you a small amount of effort during prototyping, it may result in a difficult
18+
migration later. It's also worth noting that some of the code in this sample is
19+
spent undoing the work of `native_app_glue` to create a class very similar to
20+
`Activity`.
721

822
The more modern approach to this is to use [GameActivity], which has all the
923
same benefits as `NativeActivity` and `native_app_glue`, while also making it
1024
easier to include Java code in your app without a rewrite later. It's also
11-
source compatible. This sample will likely migrate to `GameActivity` in the
12-
future.
25+
source compatible. However, it still has all the problems explained in the
26+
warning above, and in practice neither `NativeActivity` nor `GameActivity` is
27+
the recommended app development model.
1328

1429
The app here is intentionally quite simple, aiming to show the core event and
1530
draw loop necessary for an app using `native_app_glue` without any extra
1631
clutter. It uses `AChoreographer` to manage the update/render loop, and uses
1732
`ANativeWindow` and `AHardwareBuffer` to update the screen with a simple color
1833
clear.
1934

35+
[activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle
2036
[GameActivity]: https://developer.android.com/games/agdk/game-activity
2137
[NativeActivity]: http://developer.android.com/reference/android/app/NativeActivity.html
38+
39+
## Walkthrough
40+
41+
The interesting sections of code in this sample are in three files:
42+
[AndroidManifest.xml], [CMakeLists.txt], and [main.cpp]. Each of those files has
43+
code comments explaining the portions relevant to using `NativeActivity`, but
44+
the high level details of the app are explained here.
45+
46+
This app uses `NativeActivity` rather than its own child class of `Activity` or
47+
`AppCompatActivity`. This is specified in the `<activity />` declaration in [the
48+
manifest].
49+
50+
Apps which use `NativeActivity` are typically written using `native_app_glue`,
51+
which adapts the Android activity lifecycle code to look more like a desktop
52+
program with a `main()` function and an event loop. This is set up in the app's
53+
[CMakeLists.txt file].
54+
55+
When using `native_app_glue` with a [version script], you must export
56+
`ANativeActivity_onCreate`. This sample does this in
57+
[libnative-activity.map.txt].
58+
59+
This is a fairly simple application, so all of the code is in a single file,
60+
[main.cpp]. The entry point for an app using `native_app_glue` is
61+
`android_main()`. That function is the best place to start reading in this file
62+
to learn how the sample works, then follow through to the definition of
63+
`engine_handle_cmd` and `Engine`.
64+
65+
[CMakeLists.txt file]: app/src/main/cpp/CMakeLists.txt
66+
[libnative-activity.map.txt]: app/src/main/cpp/libnative-activity.map.txt
67+
[main.cpp]: app/src/main/cpp/main.cpp
68+
[the manifest]: app/src/main/AndroidManifest.xml
69+
[version script]: https://developer.android.com/ndk/guides/symbol-visibility

native-activity/app/src/main/AndroidManifest.xml

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,44 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<!-- BEGIN_INCLUDE(manifest) -->
32
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
43
android:versionCode="1"
5-
android:versionName="1.0">
4+
android:versionName="1.0">
65

7-
<!--
8-
This .apk has no Java/Kotlin code, so set hasCode to false.
6+
<!--
7+
This .apk has no Java/Kotlin code, so set hasCode to false.
98
10-
If you copy from this sample and later add Java/Kotlin code, or add a
11-
dependency on a library that does (such as androidx), be sure to set
12-
`android:hasCode` to `true` (or just remove it, since that's the default).
13-
-->
14-
<application
15-
android:allowBackup="false"
16-
android:fullBackupContent="false"
17-
android:icon="@mipmap/ic_launcher"
18-
android:label="@string/app_name"
19-
android:hasCode="false">
20-
21-
<!-- Our activity is the built-in NativeActivity framework class.
22-
This will take care of integrating with our NDK code. -->
23-
<activity android:name="android.app.NativeActivity"
24-
android:label="@string/app_name"
25-
android:configChanges="orientation|keyboardHidden"
26-
android:exported="true">
27-
<!-- Tell NativeActivity the name of our .so -->
28-
<meta-data android:name="android.app.lib_name"
29-
android:value="native-activity" />
30-
<intent-filter>
31-
<action android:name="android.intent.action.MAIN" />
32-
<category android:name="android.intent.category.LAUNCHER" />
33-
</intent-filter>
34-
</activity>
35-
</application>
9+
If you copy from this sample and later add Java/Kotlin code, or add a
10+
dependency on a library that does (such as androidx), be sure to set
11+
`android:hasCode` to `true` (or just remove it, since that's the default).
12+
-->
13+
<application
14+
android:allowBackup="false"
15+
android:fullBackupContent="false"
16+
android:icon="@mipmap/ic_launcher"
17+
android:label="@string/app_name"
18+
android:hasCode="false">
3619

20+
<!--
21+
This app uses android.app.NativeActivity rather than its own child class of
22+
Activity or AppCompatActivity. The advantage of this is that we do not have
23+
to write any Java code of our own. The Java portion of the app is provided
24+
by the OS.
25+
-->
26+
<activity
27+
android:name="android.app.NativeActivity"
28+
android:configChanges="orientation|keyboardHidden"
29+
android:exported="true">
30+
<!--
31+
This property tells NativeActivity which of our app's libraries
32+
provide the definition of ANativeActivity_onCreate, which is the
33+
entry point for apps using ANativeActivity.
34+
-->
35+
<meta-data
36+
android:name="android.app.lib_name"
37+
android:value="native-activity" />
38+
<intent-filter>
39+
<action android:name="android.intent.action.MAIN" />
40+
<category android:name="android.intent.category.LAUNCHER" />
41+
</intent-filter>
42+
</activity>
43+
</application>
3744
</manifest>
38-
<!-- END_INCLUDE(manifest) -->

native-activity/app/src/main/cpp/CMakeLists.txt

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
1-
#
2-
# Copyright (C) The Android Open Source Project
3-
#
4-
# Licensed under the Apache License, Version 2.0 (the "License");
5-
# you may not use this file except in compliance with the License.
6-
# You may obtain a copy of the License at
7-
#
8-
# http://www.apache.org/licenses/LICENSE-2.0
9-
#
10-
# Unless required by applicable law or agreed to in writing, software
11-
# distributed under the License is distributed on an "AS IS" BASIS,
12-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
# See the License for the specific language governing permissions and
14-
# limitations under the License.
15-
#
16-
1+
# Copyright (C) 2010 The Android Open Source Project
2+
# SPDX-License-Identifier: Apache-2.0
173
cmake_minimum_required(VERSION 4.1.0)
184
project(NativeActivity LANGUAGES C CXX)
195

206
include(AppLibrary)
21-
include(AndroidNdkModules)
227

8+
# This includes the AndroidNdkModules.cmake file, which is shipped with the
9+
# NDK's CMake distribution. Including this file defines
10+
# android_ndk_import_module_native_app_glue(), which defines the
11+
# native_app_glue target when called.
12+
include(AndroidNdkModules)
2313
android_ndk_import_module_native_app_glue()
2414

2515
add_app_library(native-activity SHARED main.cpp)
2616

17+
# Linking the native_app_glue target with our native-activity target (the
18+
# library which contains the main app code) includes native_app_glue in the app.
2719
target_link_libraries(native-activity
2820
android
21+
# We have to use $<LINK_LIBRARY:WHOLE_ARCHIVE,native_app_glue> rather than
22+
# the simpler native_app_glue spelling to instruct the linker that the
23+
# entire native_app_glue static library should be included in
24+
# libnative-activity.so, even if the linker does not find any calls in our
25+
# code to native_app_glue. This is because native_app_glue is a static
26+
# library rather than a shared library, and normally the linker will only
27+
# include code from static libraries when it has found a call to that code.
28+
# This is usually a good thing because it reduces the size of the app, but
29+
# in this case the calls to native_app_glue, specifically the
30+
# ANativeActivity_onCreate function, don't come from us, but instead come
31+
# from ANativeActivity, which the linker cannot detect.
2932
$<LINK_LIBRARY:WHOLE_ARCHIVE,native_app_glue>
3033
log
3134
)

native-activity/app/src/main/cpp/libnative-activity.map.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
LIBNATIVEACTIVITY {
22
global:
3+
# When using NativeActivity and you don't need any of your own JNI
4+
# functions this is the only symbol that should be exported. If your app
5+
# needs additional JNI functions (and most apps will), then you'll need to
6+
# include JNI_OnLoad (or your individual Java_... functions if you're not
7+
# using RegisterNatives) here.
38
ANativeActivity_onCreate;
49
local:
510
*;

0 commit comments

Comments
 (0)