サンプル: native-activity
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
サンプル native-activity は、NDK サンプルのルートの native-activity
フォルダにあります。これは、Java ソースコードを含まない、純粋なネイティブ アプリのシンプルなサンプルです。Java ソースはありませんが、Java コンパイラは仮想マシンが実行するための実行可能なスタブを作成します。
このスタブは実際のネイティブ プログラム(.so
ファイルにある)のラッパーの役割を果たします。
このアプリ自体は、画面全体を単純に一色に塗った後、検出した動きに応じて一部の色を変える処理をします。
AndroidManifest.xml
ネイティブ コードのみのアプリの場合は、NativeActivity
フレームワーク クラスを導入した Android API レベル 9 以降を指定する必要があります。
<uses-sdk android:minSdkVersion="9" />
このアプリはネイティブ コードのみで Java を含まないため、下記の行では android:hasCode
を false
と宣言しています。
<application android:label="@string/app_name"
android:hasCode="false">
下記の行は NativeActivity
クラスを宣言しています。
<activity android:name="android.app.NativeActivity"
最後に、マニフェストで android:value
を指定します。ここには、ビルドされる共有ライブラリの名前から接頭辞 lib
と拡張子 .so
を削除したものを指定します。この値は、Android.mk
内の LOCAL_MODULE
の名前と同じにする必要があります。
<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
Android.mk
このファイルでは最初に、生成する共有ライブラリの名前を指定しています。
LOCAL_MODULE := native-activity
次に、ネイティブ ソースコードのファイル名を宣言しています。
LOCAL_SRC_FILES := main.c
次に、ビルドシステムがバイナリをビルドする際に使用する外部ライブラリの一覧を指定します。各ライブラリ名の前には -l
(リンクを示す)オプションが付いています。
log
: ロギング ライブラリです。
android
: NDK 用の Android 標準サポート API を含んでいます。Android と NDK がサポートする API の詳細については、Android NDK ネイティブ API をご覧ください。
EGL
: グラフィック API のプラットフォーム固有の部分に該当します。
GLESv1_CM
: Android 向けの OpenGL である OpenGL ES に該当します。このライブラリは EGL を使用します。
各ライブラリについて:
- 実際のファイル名には接頭辞
lib
と拡張子 .so
が付きます。たとえば、log
ライブラリの実際のファイル名は liblog.so
です。
- ライブラリは、NDK ルートのディレクトリ
<ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib/
にあります。
LOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM
次の行は静的ライブラリの名前(android_native_app_glue
)を指定しています。アプリケーションはこのライブラリを使用して NativeActivity
のライフサイクル イベントとタップ入力を管理します。
LOCAL_STATIC_LIBRARIES := android_native_app_glue
最後の行はこれを静的ライブラリとしてビルドするようにビルドシステムに伝えます。
ndk-build
スクリプトはビルドされたライブラリ(libandroid_native_app_glue.a
)を、ビルドプロセス中に生成された obj
ディレクトリに配置します。android_native_app_glue
ライブラリの詳細については、android_native_app_glue.h
ヘッダーと、対応する .c
ソースファイルをご覧ください。
$(call import-module,android/native_app_glue)
Android.mk
ファイルの詳細については、Android.mk をご覧ください。
main.c
このファイルには、実質的にプログラム全体が記述されています。
下記のインクルード文は、Android.mk
に記載されている共有ライブラリと静的ライブラリに該当します。
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <android/sensor.h>
#include <android/log.h>
#include <android_native_app_glue>
android_native_app_glue
ライブラリは次の関数を呼び出し、定義済みの state 構造体を渡します。また、NativeActivity
コールバックの処理を簡素化するラッパーとしても機能します。
void android_main(struct android_app* state) {
次に、このプログラムは glue ライブラリがキューに入れたイベントを処理します。state 構造体にイベント ハンドラをセットします。
struct engine engine;
// Suppress link-time optimization that removes unreferenced code
// to make sure glue isn't stripped.
app_dummy();
memset(&engine, 0, sizeof(engine));
state->userData = &engine;
state->onAppCmd = engine_handle_cmd;
state->onInputEvent = engine_handle_input;
engine.app = state;
アプリケーションは sensor.h
内の API を使用して、センサーのモニタリングを開始する準備を行います。
engine.sensorManager = ASensorManager_getInstance();
engine.accelerometerSensor =
ASensorManager_getDefaultSensor(engine.sensorManager,
ASENSOR_TYPE_ACCELEROMETER);
engine.sensorEventQueue =
ASensorManager_createEventQueue(engine.sensorManager,
state->looper, LOOPER_ID_USER, NULL, NULL);
ループが開始され、アプリケーションはシステムからメッセージ(センサー イベント)をポーリングします。android_native_app_glue
にメッセージが送信され、android_main
で定義された onAppCmd
イベントと一致するかどうかの確認が行われます。一致すると、処理を実行するためにハンドラにメッセージが送信されます。
while (1) {
// Read all pending events.
int ident;
int events;
struct android_poll_source* source;
// If not animating, we will block forever waiting for events.
// If animating, we loop until all events are read, then continue
// to draw the next frame of animation.
while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL,
&events,
(void**)&source)) >= 0) {
// Process this event.
if (source != NULL) {
source->process(state, source);
}
// If a sensor has data, process it now.
if (ident == LOOPER_ID_USER) {
if (engine.accelerometerSensor != NULL) {
ASensorEvent event;
while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
&event, 1) > 0) {
LOGI("accelerometer: x=%f y=%f z=%f",
event.acceleration.x, event.acceleration.y,
event.acceleration.z);
}
}
}
// Check if we are exiting.
if (state->destroyRequested != 0) {
engine_term_display(&engine);
return;
}
}
キューが空になると、プログラムはポーリングのループを抜け、OpenGL を呼び出して画面に描画します。
if (engine.animating) {
// Done with events; draw next animation frame.
engine.state.angle += .01f;
if (engine.state.angle > 1) {
engine.state.angle = 0;
}
// Drawing is throttled to the screen update rate, so there
// is no need to do timing here.
engine_draw_frame(&engine);
}
}
このページのコンテンツやコードサンプルは、コンテンツ ライセンスに記載のライセンスに従います。Java および OpenJDK は Oracle および関連会社の商標または登録商標です。
最終更新日 2025-07-26 UTC。
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["必要な情報がない","missingTheInformationINeed","thumb-down"],["複雑すぎる / 手順が多すぎる","tooComplicatedTooManySteps","thumb-down"],["最新ではない","outOfDate","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["サンプル / コードに問題がある","samplesCodeIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-07-26 UTC。"],[],[],null,["# Sample: native-activity\n\nThe native-activity sample resides under the\n[NDK samples root](https://github.com/android/ndk-samples/), in folder\n`native-activity`. It is a very simple example of a purely native\napplication, with no Java source code. In the absence of any Java source, the\nJava compiler still creates an executable stub for the virtual machine to run.\nThe stub serves as a wrapper for the actual, native program, which is located in the `.so`\nfile.\n\nThe app itself simply renders a color onto the entire screen, and\nthen changes the color partly in response to movement that it detects.\n\nAndroidManifest.xml\n-------------------\n\nAn app with only native code must not specify an Android API level lower than 9, which introduced\nthe [`NativeActivity`](/ndk/guides/concepts#naa) framework class. \n\n```xml\n\u003cuses-sdk android:minSdkVersion=\"9\" /\u003e\n```\n\nThe following line declares `android:hasCode` as `false`, as this app has only\nnative code--no Java. \n\n```xml\n\u003capplication android:label=\"@string/app_name\"\nandroid:hasCode=\"false\"\u003e\n```\n\nThe next line declares the `NativeActivity` class. \n\n```xml\n\u003cactivity android:name=\"android.app.NativeActivity\"\n```\n\nFinally, the manifest specifies `android:value` as the name of the shared library to be\nbuilt, minus the initial `lib` and the `.so` extension. This value must be the same as\nthe name of `LOCAL_MODULE` in `Android.mk`. \n\n```xml\n\u003cmeta-data android:name=\"android.app.lib_name\"\n android:value=\"native-activity\" /\u003e\n```\n\nAndroid.mk\n----------\n\nThis file begins by providing the name of the shared library to generate. \n\n```\nLOCAL_MODULE := native-activity\n```\n\nNext, it declares the name of the native source-code file. \n\n```\nLOCAL_SRC_FILES := main.c\n```\n\nNext, it lists the external libraries for the build system to use in building the binary. The\n`-l` (link-against) option precedes each library name.\n\n- `log` is a logging library.\n- `android` encompasses the standard Android support APIs for NDK. For more information about the APIs that Android and the NDK support, see [Android NDK Native\n APIs](/ndk/guides/stable_apis).\n- `EGL` corresponds to the platform-specific portion of the graphics API.\n- `GLESv1_CM` corresponds to OpenGL ES, the version of OpenGL for Android. This library depends on EGL.\n\nFor each library:\n\n- The actual file name starts with `lib`, and ends with the `.so` extension. For example, the actual file name for the `log` library is `liblog.so`.\n- The library resides in the following directory, NDK root: `\u003cndk\u003e/platforms/android-\u003csdk_version\u003e/arch-\u003cabi\u003e/usr/lib/`.\n\n```\nLOCAL_LDLIBS := -llog -landroid -lEGL -lGLESv1_CM\n```\n\nThe next line provides the name of the static library, `android_native_app_glue`, which the\napplication uses to manage `NativeActivity` lifecycle events and touch input. \n\n```\nLOCAL_STATIC_LIBRARIES := android_native_app_glue\n```\n\nThe final line tells the build system to build this static library.\nThe `ndk-build` script places the built library\n(`libandroid_native_app_glue.a`) into the `obj` directory\ngenerated during the build process. For more information about the `android_native_app_glue`\nlibrary, see its `android_native_app_glue.h` header and corresponding `.c`source file. \n\n```\n$(call import-module,android/native_app_glue)\n```\n\nFor more information about the `Android.mk` file, see\n[Android.mk](/ndk/guides/android_mk).\n\nmain.c\n------\n\nThis file essentially contains the entire progam.\n\nThe following includes correspond to the libraries, both shared and static,\nenumerated in `Android.mk`. \n\n```c++\n#include \u003cEGL/egl.h\u003e\n#include \u003cGLES/gl.h\u003e\n\n\n#include \u003candroid/sensor.h\u003e\n#include \u003candroid/log.h\u003e\n#include \u003candroid_native_app_glue\u003e\n```\n\nThe `android_native_app_glue` library calls the following function,\npassing it a predefined state structure. It also serves as a wrapper that\nsimplifies handling of `NativeActivity` callbacks. \n\n```c++\nvoid android_main(struct android_app* state) {\n```\n\nNext, the program handles events queued by the glue library. The event\nhandler follows the state structure. \n\n```c++\nstruct engine engine;\n\n\n\n// Suppress link-time optimization that removes unreferenced code\n// to make sure glue isn't stripped.\napp_dummy();\n\n\nmemset(&engine, 0, sizeof(engine));\nstate-\u003euserData = &engine;\nstate-\u003eonAppCmd = engine_handle_cmd;\nstate-\u003eonInputEvent = engine_handle_input;\nengine.app = state;\n```\n\nThe application prepares to start monitoring the sensors, using the\nAPIs in `sensor.h`. \n\n```c++\n engine.sensorManager = ASensorManager_getInstance();\n engine.accelerometerSensor =\n ASensorManager_getDefaultSensor(engine.sensorManager,\n ASENSOR_TYPE_ACCELEROMETER);\n engine.sensorEventQueue =\n ASensorManager_createEventQueue(engine.sensorManager,\n state-\u003elooper, LOOPER_ID_USER, NULL, NULL);\n```\n\nNext, a loop begins, in which the application polls the system for\nmessages (sensor events). It sends messages to\n`android_native_app_glue`, which checks to see whether they match\nany `onAppCmd` events defined in `android_main`. When a\nmatch occurs, the message is sent to the handler for execution. \n\n```c++\nwhile (1) {\n // Read all pending events.\n int ident;\n int events;\n struct android_poll_source* source;\n\n\n // If not animating, we will block forever waiting for events.\n // If animating, we loop until all events are read, then continue\n // to draw the next frame of animation.\n while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL,\n &events,\n (void**)&source)) \u003e= 0) {\n\n\n // Process this event.\n if (source != NULL) {\n source-\u003eprocess(state, source);\n }\n\n\n // If a sensor has data, process it now.\n if (ident == LOOPER_ID_USER) {\n if (engine.accelerometerSensor != NULL) {\n ASensorEvent event;\n while (ASensorEventQueue_getEvents(engine.sensorEventQueue,\n &event, 1) \u003e 0) {\n LOGI(\"accelerometer: x=%f y=%f z=%f\",\n event.acceleration.x, event.acceleration.y,\n event.acceleration.z);\n }\n }\n }\n\n\n // Check if we are exiting.\n if (state-\u003edestroyRequested != 0) {\n engine_term_display(&engine);\n return;\n }\n }\n```\n\nOnce the queue is empty, and the program exits the polling loop, the\nprogram calls OpenGL to draw the screen. \n\n```c++\n if (engine.animating) {\n // Done with events; draw next animation frame.\n engine.state.angle += .01f;\n if (engine.state.angle \u003e 1) {\n engine.state.angle = 0;\n }\n\n\n // Drawing is throttled to the screen update rate, so there\n // is no need to do timing here.\n engine_draw_frame(&engine);\n }\n}\n```"]]