樣例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數組中對應相應的方法關係即可。