JNI開發(一) 靜態註冊與動態註冊

靜態註冊

原理:
根據函數名來建立 java 方法與 JNI 函數的一一對應關係;

實現流程:

編寫 java 代碼;
利用 javah 指令生成對應的 .h 文件;
對 .h 中的聲明進行實現;
弊端:

編寫不方便,JNI 方法名字必須遵循規則且名字很長;
編寫過程步驟多,不方便;
程序運行效率低,因爲初次調用native函數時需要根據根據函數名在JNI層中搜索對應的本地函數,然後建立對應關係,這個過程比較耗時;

JNIEXPORT jstring JNICALL
Java_com_example_efan_jni_1learn2_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

動態註冊

原理:
利用 RegisterNatives 方法來註冊 java 方法與 JNI 函數的一一對應關係;

實現流程:

利用結構體 JNINativeMethod 數組記錄 java 方法與 JNI 函數的對應關係;
實現 JNI_OnLoad 方法,在加載動態庫後,執行動態註冊;
調用 FindClass 方法,獲取 java 對象;
調用 RegisterNatives 方法,傳入 java 對象,以及 JNINativeMethod 數組,以及註冊數目完成註冊;
優點:

流程更加清晰可控;
效率更高;

jstring stringFromJNI(JNIEnv *env, jobject thiz){
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

static const JNINativeMethod gMethods[] = {
        {"stringFromJNI", "()Ljava/lang/String;", (jstring*)stringFromJNI}
};

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){

    __android_log_print(ANDROID_LOG_INFO, "native", "Jni_OnLoad");
    JNIEnv* env = NULL;
    if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) //從JavaVM獲取JNIEnv,一般使用1.4的版本
        return -1;
    jclass clazz = env->FindClass("com/example/efan/jni_learn2/MainActivity");
    if (!clazz){
        __android_log_print(ANDROID_LOG_INFO, "native", "cannot get class: com/example/efan/jni_learn2/MainActivity");
        return -1;
    }
    if(env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])))
    {
        __android_log_print(ANDROID_LOG_INFO, "native", "register native method failed!\n");
        return -1;
    }
    return JNI_VERSION_1_4;
}

JNINativeMethod

在動態註冊的過程中使用到了結構體 JNINativeMethod 用於記錄 java 方法與 jni 函數的對應關係

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;

結構體的第一個參數 name 是java 方法名;

第二個參數 signature 用於描述方法的參數與返回值;

第三個參數 fnPtr 是函數指針,指向 jni 函數;

其中,第二個參數 signature 使用字符串記錄方法的參數與返回值,具體格式形如“()V”、“(II)V”,其中分爲兩部分,括號內表示的是參數,括號右側表示的是返回值;

數據類型映射

1.基本數據類型

2. 數組引用類型

如果是一維數組則遵循下表,如果是二維數組或更高維數組則對應的 native 類型爲 jobjectArray,域描述符中使用 ‘[’ 的個數表示維數

3. 對象引用類型

對於其它引用類型,即 java 中的對象,其映射規則爲

4. 對象數組引用類型

如果是一維數組則遵循下表,如果是二維數組或更高維數組則對應的 native 類型爲 jobjectArray,域描述符中使用 ‘[’ 的個數表示維數

jni 函數默認參數

在 jni 函數中有兩個默認參數

JNIEnv *env, jobject thiz

其中 JNIEnv 指代的是當前 java 環境,可以利用 JNIEnv 可以操作 java 層代碼;jobject 指代的是 jni 函數對應的 java native 方法的類實例,如果 java 方法是 static,則代表的是 class 對象;

出自:https://blog.csdn.net/qq_20404903/article/details/80662316

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章