NativeActivity
NDK 的适用场景官方给出三点:
- 平台间的 App 移植
- 复用现有库
- 对软件性能要求较高的场合比如游戏等
有两种方式可以实现 native activity。
- native_activity.h
- android_native_app_glue
由于第二种方法启用另一个线程处理回调和输入事件,NDK 的例子中就采用了这个实现方式。
工程初始化
创建 NDK 工程
NDK 工程创建完成会生成一个带有 JNI 调用 c++ 返回 HelloWorld 字符串的一个初始化工程
配置 NativeActivity
首先在 AndroidManifest.xml 文件中添加 Name 为 android.app.lib_name(不可更改) 的 MetaData
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.lib_name" android:value="OpenGLDemo" />
</activity>
将我们 MainActivity 改为继承 NativeActivity,并加载 native 生成的 OpenGLDemo.so
import android.app.NativeActivity
class MainActivity : NativeActivity() {
companion object {
init {
System.loadLibrary("OpenGLDemo")
}
}
}
配置 CMakeList 文件
cmake_minimum_required(VERSION 3.22.1)
# 与之前在 Manifest 文件中配置的一样
project("OpenGLDemo")
# 添加 native_app_glue
set(APP_GLUE_DIR ${ANDROID_NDK}/sources/android/native_app_glue)
include_directories(${APP_GLUE_DIR})
add_library(app-glue STATIC ${APP_GLUE_DIR}/android_native_app_glue.c)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
# 添加源码和头文件
file(GLOB LOCAL_SOURCE "${CMAKE_SOURCE_DIR}/*.cpp")
file(GLOB LOCAL_HEADER "${CMAKE_SOURCE_DIR}/*.h")
add_library(${CMAKE_PROJECT_NAME} SHARED
${LOCAL_HEADERS}
${LOCAL_SOURCE})
# 指定 CMake 应链接到您的目标库的库
target_link_libraries(${CMAKE_PROJECT_NAME}
android
EGL
GLESv3
jnigraphics
app-glue
log)
创建 main.cpp 的 native 入口文件
#include <android_native_app_glue.h>
#include <jni.h>
static int32_t handle_input(struct android_app* app, AInputEvent* event) {
return 0;
}
static void handle_cmd(struct android_app *app, int32_t cmd) {
switch (cmd) {
case APP_CMD_RESUME: {
break;
}
case APP_CMD_PAUSE: {
break;
}
default:
break;
}
}
void android_main(struct android_app *app) {
app->onAppCmd = handle_cmd;
app->onInputEvent = handle_input;
// 循环等待要做的事情。
while (!app->destroyRequested) {
int events;
struct android_poll_source *source;
// 获取需要处理的事件
if (ALooper_pollAll(0, nullptr, &events, (void **) &source) >= 0) {
if (source) {
source->process(app, source);
}
}
}
}
至此我们的 native 工程就配置完成了,运行后你会看到一个纯黑的窗口,那是因为我们没有为当前 MainActivity 创建的 Window 绘制任何东西
要想绘制东西,需要初始化 OpenGL ,创建对应的 Display 与 Surface 与当前的 window 进行绑定
详见 Android OpenGL 教程——窗口初始化
OpenGLDemo 源码的 init_native_activity 分支