示例:native-activity

native-activity 示例位于 NDK 示例根目录 中的 native-activity 文件夹中。这是一个非常简单的纯原生应用程序示例,没有 Java 源代码。在没有任何 Java 源代码的情况下,Java 编译器仍然会为虚拟机创建一个可执行存根以运行。存根充当实际原生程序的包装器,该程序位于 .so 文件中。

应用程序本身只是在整个屏幕上渲染一种颜色,然后根据检测到的移动部分更改颜色。

AndroidManifest.xml

仅包含原生代码的应用程序不能指定低于 9 的 Android API 级别,因为该级别引入了 NativeActivity 框架类。

<uses-sdk android:minSdkVersion="9" />

以下行将 android:hasCode 声明为 false,因为此应用程序仅包含原生代码 - 没有 Java。

<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 对应于 OpenGL ES,它是 Android 的 OpenGL 版本。此库依赖于 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 库调用以下函数,并将预定义的状态结构传递给它。它还充当包装器,简化了 NativeActivity 回调的处理。

void android_main(struct android_app* 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);
    }
}