1. 什么是NDK动态注册:
-
不用再用静态注册般,需要方法名一一对应,不然找不到方法,动态注册能够摆脱这一限制,
-
不用所有的JNI方法都写到一个类文件中,项目较大的时候类无限膨胀,Android系统源码中JNI基本全部都是动态注册,比如最简单的MediaPlayer
-
由于是将函数映射表注册到JVM中,所以函数的调用速度更快。
2. 动态注册怎么写?
-
编写
Java
的文件public class NdkLoad { static { System.loadLibrary("native-lib"); } //JNI方法 public native String stringFromJNI(); }
-
在native-lib.cpp中重写
JNI_OnLoad
方法,此方法是JNI
加载的时候,第一个调用的方法JNIEXPORT jint JNI_OnLoad(JavaVM *jvm, void *reserved) { JNIEnv *env; //需要通过JVM动态的获取JNIEnv来提供JNI 版本 如果低于1.6则返回错误 if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } //需要调用这些函数的类 //一定要注意名称的正确性:包名 + 类名 jclass clz = env->FindClass("com/mrwang/ndkdynamic/NdkLoad"); if(clz == NULL){ LOGE("类名不对"); } else { LOGE("类加载成功"); } jint method_size = sizeof(nativeMethod) / sizeof(nativeMethod[0]); /** * 注册函数表 * @param1 需要关联到那个【Java】类,Kotlin类不行 * @param2 方法数组 * @param3 方法数 */ env->RegisterNatives(clz, nativeMethod, method_size); //返回使用的JNI版本 return JNI_VERSION_1_6; }
-
可以看到 具体顺序为
- 先确定JNI版本,因为JNI各个版本不兼容,确保JNI版本为
JNI_VERSION_1_6
- 利用JNI环境
JNIEnv
查找对应的JavaClass
文件(利用反射),注意传入的参数,Java类型的书写方式 - 计算JNI方法数,具体注册几个方法
- 最终,调用
JNIEnv
的RegisterNatives
方法来把方法动态注册到JVM
中
- 先确定JNI版本,因为JNI各个版本不兼容,确保JNI版本为
-
nativeMethod
的结构// Java和JNI函数的绑定表 最后一个为JNI函数名字 static JNINativeMethod nativeMethod[] = { {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromC},//绑定 };
- 绑定表,第一个为Java中native方法名,第二个为方法签名,第三个为JNI中的方法
- JNI方法名任意,方法签名请对照JNI描述符相关规则
-
解注册,因JVM中注册的方法数是有数量限制的,所以建议注册一定要有解注册的操作,一般,解注册放在
JNI_OnUnload
方法中,此方法是JNI完全退出的时候调用的方法JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) { JNIEnv *env; //需要通过JVM动态的获取JNIEnv来提供Java介质 if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return; } jclass clz = env->FindClass("com/example/xingxinyu/cppdemo/JNIHelper"); // 解注册函数表 env->UnregisterNatives(clz); }
很简单
UnregisterNatives
即可
网友评论