jni理解
- 定义 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)); // 输出 3System.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 方法的场景。