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原理分析