所谓动态注册,就是不用像静态注册那样按规则严格的命名native方法,而是在加载so库的时候完成这个从Java方法到native方法的匹配工作,而这个匹配工作,需要我们写native代码来完成。下面直入正题看看怎么写。
涉及的几个函数和实体(结构体)
-
JavaVM *
指针,指向加载当前动态库的java虚拟机 -
JNIEnv *
指针,指向当前使用的JNI版本,JNI中已定义的方法可以通过它来调用 -
jint JNI_OnLoad(JavaVM *vm, void *reserved)函数
动态库加载的入口,调用System.loadLibrary()方法加载动态库后会回调该函数 -
jclass FindClass(JNIEnv *env, const char *name)函数
根据name中传入的Java全路径类名,找到某个Java类(包路径用'/'分割) -
jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods)函数
注册native方法 -
JNINativeMethod结构体
typedef struct { char *name; char *signature; void *fnPtr; } JNINativeMethod;
定义一个Java中声明的方法和native中实现的方法的对应关系
-
jint GetEnv(JavaVM *vm, void **env, jint version)函数
获取当前jvm环境的JNI环境指针
具体实现
废话不多见代码:
// native方法实现 void nativeDynamicLog(JNIEnv *evn, jobject obj){ } // 声明待注册的native方法数组,结构体三个参数分别表示Java文件中声明的方法名、方法特征、native中的方法的指针 JNINativeMethod nativeMethod[] = {{"dynamicLog", "()V", (void*)nativeDynamicLog},}; // 重载jni.h中的JNI_OnLoad方法 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { JNIEnv *env; // JNI_VERSION_1_4是jni.h中定义好的常量,根据使用的sdk版本不同已定义的常量有所差异,具体见jni.h代码 if (jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } jclass clz = env->FindClass("com/example/zhanghaiqiang/hellojni/HelloJni"); env->RegisterNatives(clz, nativeMethod, sizeof(nativeMethod)/sizeof(nativeMethod[0])); return JNI_VERSION_1_4; }