靜態(tài)注冊(cè)
靜態(tài)注冊(cè)的格式如下:
extern "C" JNIEXPORT [JNI參數(shù)類型] JNICALL Java_[包名]_[類名]_[方法名](JNIEnv* env, jobject, [JNI參數(shù)類型,參數(shù)名])
包名也用 _ 分隔。
包名、類名、方法名必須和 Java 中的一模一樣。
例子:
extern "C" JNIEXPORT jstring JNICALL Java_com_sample_MainActivity_stringFromJNI(JNIEnv* env, jobject this_obj) {
std::string hello = "Hello World from C++";
return env->NewStringUTF(hello.c_str());
}
缺點(diǎn):
- 方法名很長(zhǎng)
- 效率低。首次調(diào)用 Java native 方法時(shí)需要根據(jù)方法名在 JNI 中查找對(duì)應(yīng)的本地 C++ 函數(shù)并建立對(duì)應(yīng)關(guān)系,這個(gè)過(guò)程是比較耗時(shí)的。
優(yōu)點(diǎn):
- 編寫不方便的缺點(diǎn) Android Studio 已經(jīng)幫我們解決,可以先編寫 Java native 方法,然后根據(jù)提示自動(dòng)生成對(duì)應(yīng)的本地 C++ 方法。
- 閱讀代碼方便,本地 C++ 方法和 Java native 方法可以互相跳轉(zhuǎn)查看。
動(dòng)態(tài)注冊(cè)
在調(diào)用 System.loadLibrary 加載庫(kù)文件時(shí),系統(tǒng)回調(diào) JNI_OnLoad() 函數(shù)。
可以在 JNI_OnLoad 中做一些初始化操作,可以用 RegisterNatives 方法注冊(cè) Java native 方法。
jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);
這樣的話,提前建立 Java native 方法和本地 C++ 方法的關(guān)系,在調(diào)用 Java native 方法的時(shí)候無(wú)需再查找并建立關(guān)系,就會(huì)比較快。
例子:
jstring stringFromJNI(JNIEnv* env, jobject this_obj) {
std::string hello = "Hello World from C++";
return env->NewStringUTF(hello.c_str());
}
static int registerNatives(JNIEnv *env) {
// 要注冊(cè)的 java 類的路徑(完整的包名和類名)
const char *className = "com/teletian/sample/MainActivity";
/*
* 要注冊(cè)的函數(shù)列表
* 參數(shù):
* 1. java 中用 native 關(guān)鍵字聲明的函數(shù)名
* 2. 函數(shù)簽名,格式:(參數(shù)類型)返回類型
* 3. C/C++ 中對(duì)應(yīng)函數(shù)的函數(shù)名(地址)
* */
const JNINativeMethod nativeMethods[] = {
{"stringInJava", "()Ljava/lang/String;", (void *) stringFromJNI},
};
jclass clazz = env->FindClass(className);
if (clazz == nullptr) {
return JNI_FALSE;
}
int methodsCount = sizeof(nativeMethods) / sizeof(nativeMethods[0]);
//注冊(cè)函數(shù) 參數(shù):java 類名,要注冊(cè)的函數(shù)數(shù)組,要注冊(cè)函數(shù)的數(shù)量
if (env->RegisterNatives(clazz, nativeMethods, methodsCount) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = nullptr;
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
assert(env != nullptr);
//registerNatives -> env->RegisterNatives
if (!registerNatives(env)) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
缺點(diǎn):
- 代碼不夠簡(jiǎn)潔
- 閱讀代碼不方便,本地 C++ 方法和 Java native 方法無(wú)法互相跳轉(zhuǎn)查看。
優(yōu)點(diǎn):
- 流程清洗可控
- 效率高。提前建立關(guān)系,首次調(diào)用方法時(shí)速度快