【Android】JNI静态与动态注册介绍
JNI的两种注册机制:静态注册和动态注册.
JNI介绍JNI介绍
JNI(Java Native Interface),即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互.
方式:
- 静态注册
- 动态注册:需要提供Java中Native方法的方法签名和Native层中对应的实现函数。
静态注册静态注册
要求C/C++层的函数名符合某种特定的要求:包含Java中Native方法的目录信息和方法名。
Example
Java
package cn.com.codingce.ndkpractice; public native String stringFromJNI();
C++
extern "C" JNIEXPORT jstring JNICALL Java_cn_com_codingce_ndkpractice_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) { std::string hello = "Hello from C++"; //crashTest(); return env->NewStringUTF(hello.c_str()); }
按照以上规则进行命名,在调用到Native的方法时,JVM会去查找是否存在对应函数名的函数,以此实现静态注册。
动态注册动态注册
动态注册相对于静态注册,优点是不再根据特定路径查找函数的实现,带来两个好处:
- 没有了冗杂的函数名,适用于大型项目开发。
- 由于不再根据Native函数查找对应的JNI层函数,所以首次调用速度比静态注册快。
开发者需要自行提供Java层和C/C++层中的映射关系。
一种可行的方法是基于JNI重载JNI_OnLoad(),在其中对函数进行动态注册。
Example
Java
package cn.com.codingce.ndkpractice.utils; public static native void logInit(String logFilePath, String logName, int logfileLevel, int logScreenLevel);
C++
此步骤涉及到如何获取Java函数。
static JNINativeMethod nativeUtilsMethods[] = { {"logInit", "(Ljava/lang/String;Ljava/lang/String;II)V", (void *) localLogInit}, {"logJni", "(ILjava/lang/String;)V", (void *) logJni}, {"logClose", "()V", (void *) logClose}, }; static void nativeLogUtilsRegisterNatives(JNIEnv *jniEnv) { if (jniEnv == nullptr) { return; } jclass clazz = nullptr; do { clazz = jniEnv->FindClass("cn/com/codingce/ndkpractice/utils/LogUtils"); if (clazz == nullptr) { diagnosis_assert(!"FindClass LogUtils error!"); break; } if (jniEnv->RegisterNatives(clazz, nativeUtilsMethods, std::extent<decltype(nativeUtilsMethods)>::value) != 0) { diagnosis_assert(!"RegisterNatives error!"); break; } } while (false); if (jniEnv->ExceptionCheck() == JNI_TRUE) { jniEnv->ExceptionClear(); } if (clazz != nullptr) { jniEnv->DeleteLocalRef(clazz); } }
重载JNI_OnLoad函数,并在其中调用nativeLogUtilsRegisterNatives函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *jniEnv{nullptr}; if (vm->GetEnv((void **) &jniEnv, JNI_VERSION_1_6) != JNI_OK) { diagnosis_assert(!"JNI version error!"); return JNI_EVERSION; } nativeLogUtilsRegisterNatives(jniEnv); return JNI_VERSION_1_6; }