簡介
在開發(fā)NDK 工程的時(shí)候,我們在java層調(diào)用一個native方法的時(shí)候,虛擬機(jī)怎樣知道應(yīng)該調(diào)用到so里面的哪個方法呢?這里就用到了另外一個概念注冊
诅迷,通過注冊,可以將指定的native
方法和so里面對應(yīng)的方法綁定起來众旗。注冊
分為靜態(tài)注冊
和動態(tài)注冊
罢杉。一般我們用到的都是靜態(tài)注冊
。
靜態(tài)注冊
通過JNIEXPORT和JNICALL這兩個宏進(jìn)行定義聲明贡歧,在虛擬機(jī)加載so的時(shí)候滩租,跟根據(jù)定義的函數(shù)找到對應(yīng)的native方法。
extern "C" JNIEXPORT jstring JNICALL
Java_com_canter_ndkdemo4_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
nullPointCrash();
return env->NewStringUTF(hello.c_str());
}
譬如上面的例子利朵,因?yàn)楹瘮?shù)的定義律想,是根據(jù)對應(yīng)的native方法的類路徑和類名來生成的,所以能夠直接映射找到對應(yīng)的native方法绍弟。
動態(tài)注冊
通過 registerNatives 方法手動完成 native 方法和 so 中的方法的綁定技即,這樣虛擬機(jī)就可以通過這個函數(shù)映射表直接找到相應(yīng)的方法。
動態(tài)注冊好處是不需要寫很長的方法名樟遣,用jni_onload方法實(shí)現(xiàn)預(yù)注冊 即當(dāng)執(zhí)行system.loadLibrary()方法時(shí)候就把需要調(diào)用的方法給注冊了而叼,運(yùn)行效率上會比較高郭脂。
注冊步驟:
- 重寫
JNI_OnLoad
方法; - 注冊Java端的方法 以及本地相對應(yīng)的方法
- 注冊相應(yīng)的類以及方法
- 聲明并實(shí)現(xiàn)對應(yīng)的c層對應(yīng)的方法
具體代碼如下
//替換java端的testVoid
void native_void() {
LOGV("調(diào)用了native_void澈歉,是java 層對應(yīng)的testVoid方法");
}
//替換java端的testInt
int native_testInt() {
return 200;
}
//注冊Java端的方法 以及本地相對應(yīng)的方法
JNINativeMethod method[] = {{"testVoid", "()V", (void *) native_void},
{"testInt", "()I", (int *) native_testInt}};
//注冊相應(yīng)的類以及方法
jint registerNativeMeth(JNIEnv *env) {
jclass cl = env->FindClass("com/canter/ndkdemo5/MainActivity");
if ((env->RegisterNatives(cl, method, sizeof(method) / sizeof(method[0]))) < 0) {
return -1;
}
return 0;
}
//實(shí)現(xiàn)jni_onload 動態(tài)注冊方法
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
if (registerNativeMeth(env) != JNI_OK) {//注冊方法
return -1;
}
return JNI_VERSION_1_4;//必須返回這個值
}
源碼詳見 github里面的NDKDemo5