JNI 静态注册和动态注册
静态注册
- 注册函数说明
java 层声明 native 关键字修饰的函数,再使用 javah 编译得到 c/c++ 的头文件(.h),其包含java_完整包名_类名_方法名
命名规则的桥接层函数。
以下展示生成的头文件代码:#include <jni.h> #ifndef _JNI_DEMO_GREET_H // 避免头文件重复引用 #define _JNI_DEMO_GREET_H #ifdef __cplusplus // c++ 支持函数重载,会在编译阶段把入参类型拼接在函数名后,这里注明使用 c 的编译方式. extern "C" { #endif JNIEXPORT jstring JNICALL Java_com_jnidemo_Greet_sayHello(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_com_jnidemo_Greet_sayBye(JNIEnv *env, jclass clazz); #ifdef __cplusplus } #endif #endif // _JNI_DEMO_GREET_H
- 静态注册的痛点
- java 层包名/类名/函数名,任一处有改动,头文件及其实现函数的函数名称都会失效,需手动修改维护,查找繁琐且易出错。
- 所有包含 native 函数的 java 类都需要编写 JNI头文件,且函数名过长。
- 初次运行时需要建立 java与native 的jni函数映射关系, 影响运行效率。
动态注册
-
注册流程
Java-System.loadLibrary(libname) —>
C-JNI_OnLoad —>
Env->FindClass(classname) —>
Env->RegisterNatives(JNINativeMethod[] - 函数映射表). -
注册函数说明
以下展示 c/c++ 层桥接层代码:#include <jni.h> /** * JNINativeMethod 结构体描述 * const char* name; native函数名,之后java层函数名修改时同步修改该字段,包名类名修改时同步修改classname. * const char* signature; JNI 函数签名,需遵循桥接层签名规则。 * void* fnPtr; c层实现函数的函数指针。 */ static JNINativeMethod gMethods1[] = { {"sayHello", "()Ljava/lang/String;", (void *) JniSayHello}, {"sayBye", "()V", (void *) JniSayBye} }; static int registerNativesMethods(JNIEnv *env, const char *className, JNINativeMethod *gMethods, int numMethods) { jclass clazz = env->FindClass(className); if (clazz == NULL) return JNI_FALSE; if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) return JNI_FALSE; return JNI_TRUE; } static int registerNatives(JNIEnv *env) { // 这里可以注册多个包含native函数的Java类 int ret1 = registerNativesMethods(env, classname1, gMethods1, sizeof(gMethods1) / sizeof(gMethods1[0])); int ret2 = registerNativesMethods(env, classname2, gMethods2, sizeof(gMethods2) / sizeof(gMethods2[0])); return (ret1 && ret2) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) return -1; assert(env != NULL); if (!registerNatives(env)) return -1; return JNI_VERSION_1_6; }
参考文章:
JNI原理分析