JNI代碼兩種註冊編寫方式

樣例java類
HelloJni.java

package com.example.test;

public class HelloJni {

    public native String  stringFromJNI();

    static {
        System.loadLibrary("helloJni");
    }
}

方法一:靜態註冊

遵守JNI標準規函數命名方式, JNI中方法命名爲 Java_包名_類名_方法名, 可以使用javah生成簽名頭文件, 靠這種方式實現Native方法與JNI方法之間的映射關係,即應用直接與框架層進行交互,這種規範常用與應用開發;

javah -jni 自動生成.h文件

<project>\bin\classes目錄下執行

javah -classpath .;<sdkPath>\sdk\platforms\android-19\android.jar -jni com.pachong.test.Hello(pakageName.className)

即可生成對應的.h頭文件,在這個頭文件中就有我們需要實現的c&c++方法了,這裏加上<sdkPath>\sdk\platforms\android-19\android.jar是因爲我們的類中有引用到系統相關的一些類或方法需要加上android.jar才能生成對應.h文件。
這裏寫圖片描述
com_example_test_HelloJni.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_test_HelloJni */

#ifndef _Included_com_example_test_HelloJni
#define _Included_com_example_test_HelloJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_test_HelloJni
 * Method:    stringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_test_HelloJni_stringFromJNI
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

在項目根目錄下新建jni文件夾,將剛剛生成的.h文件拷貝到這個目錄下,同時新建一個對應的.cpp文件和Android.mk文件用於編譯生成so文件。

com_example_test_HelloJni.cpp

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "com_example_test_HelloJni.h"
/* Header for class com_example_test_HelloJni */

/*
 * Class:     com_example_test_HelloJni
 * Method:    stringFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_test_HelloJni_stringFromJNI
  (JNIEnv *, jobject) {
    return env->NewStringUTF("Hello from JNI !");
}

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libhelloJni
LOCAL_SRC_FILES := com_example_test_HelloJni.cpp

include $(BUILD_SHARED_LIBRARY)

注:LOCAL_MODULE := libhelloJni要和System.loadLibrary(“helloJni”);對應起來。
這裏寫圖片描述

javap -s -p 查看函數簽名

-s: 顯示簽名(只顯示public類型的簽名) -p:顯示所有函數、成員變量的簽名

javap -classpath .;<sdkPath>\sdk\platforms\android-19\android.jar -s -p com.pachong.test.Hello(pakageName.className)

(注:<sdkPath>\sdk\platforms\android-19\android.jar是可選項),通過簽名我們就可以在寫jni相關的代碼時寫入相應的簽名即可。
這裏寫圖片描述

方法二:動態註冊

這是Android自定義的一種規範, 應用框架層採用該規範, 即應用框架層 與 框架層 進行交互, 底層源碼開發多使用該規範;

動態註冊是通過調用JNI_OnLoad方法,去註冊相關類的方法來實現的,來看下具體的實現。
customHelloJni.cpp

#include <jni.h>

static jstring  hello(JNIEnv* evn, jobject thiz) {
    return env->NewStringUTF("Hello from JNI !");
}

//需要調用實現JNI的類
static const char* classPathName = "com/example/test/HelloJni";

//綁定相應的方法
static JNINativeMethod methods[] = {
        {"stringFromJNI", "()Ljava/lang/String",(void*)hello},
};

//註冊指定類的相關方法
static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) {
    jclass clazz;

    clazz = env->FindClass(className);
    if (class == NULL) {
        return JNI_FALSE;
    }

    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

static int registerNatives(JNIEnv* env) {
    if (!registerNativeMethods(env, classPathName, methods, sizeof(methods)/sizeof(methods[0]))) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

//註冊JNI方法入口
jint JNI_OnLoad(JavaVM* vm, void* reserved) {

    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv(&env, JNI_VERSION_1_4) != JNI_OK) {
        return result;
    }

    if (registerNatives(env) != JNI_TRUE) {
        return result;
    }

    result = JNI_VERSION_1_4;
    return result;
}

通過上面的代碼實現,我們知道動態註冊比靜態註冊在實現函數命名上更加自由,我們不需要按照JNI的那套標準規則來命名相關方法,只需要在綁定方法函數時與Java類中方法對應即可,即JNINativeMethod數組中對應相應的方法關係即可。

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