Android中,通常创建native的方法是在java层写一个native的方法声明,然后通过Alt+enter进行自动生成jni的方法,或者在命令行中使用javah生成头问题然后对照头问题的函数名,在c文件中创建函数。这种属于静态注册方法,虽然在AS中使用非常方法,但是有一下几个弊端:
- 在调用该方法时,有额外的查找方法的性能开销
- 在后期需要重构代码时,jni中的函数名需要手动修改,比较麻烦
- 在程序运行时,无法动态更换
所以,在NDK开发时,可以使用动态注册Native方法来规避上面的问题。
动态注册方法是通过jni中的JNI_OnLoad方法实现的:
1 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved); |
JNI_OnLoad()方法在虚拟机加载C库是被执行(当System.loadLibrary("native-lib")时)。
在JNI_OnLoad()中使用
1 | jint RegisterNatives(jclass clazz, const JNINativeMethod* methods, |
对native方法进行注册。RegisterNatives()中需要三个参数:
clazz指的是native方法所在的类,可以使用env->FindClass()获取;
1
jclass clazz = env->FindClass("com/example/jni/MainActivity");
methods指的是需要动态注册的方法(这是一个指向数组的指针),
JNINativeMethod是一个结构体:1
2
3
4
5typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;- name是java层的方法名;
- signature是方法的出参入参的类型
- fnPtr是jni层的函数指针
nMethods指的是需要动态注册的方法的个数,就是methods的长度:
sizeof(g_methods) / sizeof(g_methods[0])
最终的实现:
Java层:
1 | public native String _test(); |
jni层:
1 | extern "C" JNIEXPORT jstring JNICALL |