- 定义 JNI 方法映射表(注册表)
对应原文件中的 sScreenCaptureMethods 数组,用于声明 Java native 方法与 C++ 函数的映射关系:
// ... 其他代码(如结构体定义、工具函数)...
// ----------------------------------------------------------------------------
// JNI 方法映射表(动态注册核心)
static const JNINativeMethod sMyDynamicMethods[] = {
// { Java层native方法名, 方法签名, C++函数指针 }
{"nativeAddNumbers", "(II)I", (void*)nativeAddNumbers}, // 示例1:两数相加
{"nativeGetDeviceInfo", "()Ljava/lang/String;", (void*)nativeGetDeviceInfo}, // 示例2:获取设备信息
};
// ... 后续注册函数 ...
- 实现 C++ 函数
// ... 其他代码 ...
// 示例1:两数相加(对应 Java 的 nativeAddNumbers(int a, int b))
static jint nativeAddNumbers(JNIEnv* env, jclass clazz, jint a, jint b) {
return a + b; // 简单业务逻辑
}
// 示例2:获取设备信息(对应 Java 的 nativeGetDeviceInfo())
static jstring nativeGetDeviceInfo(JNIEnv* env, jclass clazz) {
std::string info = "Model: RK3576; SDK: 33"; // 模拟设备信息
return env->NewStringUTF(info.c_str()); // 返回 Java String
}
// ... JNI 方法映射表(见步骤1)...
- 实现注册函数
对应原文件中的 register_android_window_ScreenCapture 函数,将映射表注册到 JVM:
// ... JNI 方法映射表(见步骤1)...
// 注册函数:将 sMyDynamicMethods 映射表注册到 Java 类
int register_com_example_MyDynamicJni(JNIEnv* env) {
// 1. 指定 Java 类全路径(需与 Java 层包名+类名一致)
const char* javaClassName = "com/example/MyDynamicJni";
// 2. 注册映射表(通过 RegisterMethodsOrDie 完成注册)
int err = RegisterMethodsOrDie(
env,
javaClassName, // Java 类名
sMyDynamicMethods, // JNI 方法映射表
NELEM(sMyDynamicMethods) // 映射表长度(自动计算元素个数)
);
// 3. (可选)初始化 Java 类的字段/方法 ID(如原文件中的 gCaptureArgsClassInfo)
jclass myClass = FindClassOrDie(env, javaClassName);
// ... (如需操作 Java 对象字段,可在此获取 fieldID/methodID)...
return err; // 返回注册结果(0 表示成功)
}
} // namespace android
- Java 层配套代码(需手动编写)
动态注册需对应 Java 类中声明 native 方法,例如 MyDynamicJni.java
package com.example;
public class MyDynamicJni {
// 加载 native 库(对应编译生成的 libxxx.so)
static {
System.loadLibrary("my_dynamic_jni"); // 库名需与 Android.bp 中定义一致
}
// 声明 native 方法(方法名、参数、返回值需与 JNI 映射表完全匹配)
public native int nativeAddNumbers(int a, int b);
public native String nativeGetDeviceInfo();
// 测试调用
public static void main(String[] args) {
MyDynamicJni jni = new MyDynamicJni();
System.out.println("1+2=" + jni.nativeAddNumbers(1, 2)); // 输出 3
System.out.println("Device Info: " + jni.nativeGetDeviceInfo()); // 输出设备信息
}
}
原文件关键元素 | 示例对应部分 | 作用说明 |
---|---|---|
sScreenCaptureMethods |
sMyDynamicMethods |
定义 Java 方法名与 C++ 函数的映射关系,无需依赖 Java_xxx 命名规则 |
nativeCaptureDisplay |
nativeAddNumbers |
C++ 业务逻辑的具体实现,函数名可自定义(通过映射表与 Java 方法关联) |
register_android_window_ScreenCapture |
register_com_example_MyDynamicJni |
将映射表注册到虚拟机,完成 Java 与 C++ 方法的绑定 |
为什么需要动态注册?
灵活命名:C++ 函数名无需遵循冗长的
Java_包名_类名_方法名
格式(如原文件中直接使用nativeCaptureDisplay
,而非Java_android_window_ScreenCapture_nativeCaptureDisplay
)。批量管理:通过映射表统一管理所有 native 方法,便于维护(如原文件中
sScreenCaptureMethods
集中声明了 6 个方法映射)。性能优化:动态注册比静态注册(依赖虚拟机查找函数名)效率更高,尤其适合系统框架层存在大量 JNI 方法的场景。