So相关知识学习
JNI函数的静态注册
-
必须遵循一定的命名规则,一般是
Java_包名_类名_方法名
-
系统会通过
dlopen
加载对应的 SO,通过dlsym
来获取指定名字的函数地址,然后调用静态注册的 JNI 函数,必然在导出表里 -
编译 SO 的时候不会给对应 JNI 函数具体地址,在 第一次调用 的时候才会有具体地址
JNI函数的动态注册
-
通过
env->RegisterNatives
注册函数,通常在JNI_OnLoad
中注册JNINativeMethod
-
函数签名
-
可以给同一个 Java 函数注册多个 native 函数,以最后一次为准
|
|
JNI_Onload定义
|
|
SO之间的相互调用
-
使用
dlopen
,dlsym
,dlclose
获取函数地址,然后调用。需要导入dlfcn.h
-
dlopen
第一个参数为要加载的 SO 的 绝对路径,第二个参数为 符号解析的时机,返回值为该 SO 的一个 句柄 -
dlsym
第一个参数为dlopen
返回的 库句柄,第二个参数为要查找的 符号的名字,返回值为 该符号的指针 -
reinterpret_cast<void (*)(char *)
为 C++ 中的一个方法,用于两个不同类型指针的强制转换
|
|
- extern 函数声明
SO路径的动态获取
- 32 和 64 的 SO 存放路径不一样,为了更加通用,可以用代码动态获取 SO 路径
|
|
通过JNI创建Java对象
-
NewObject
创建对象1 2 3 4
jclass clazz = env->FindClass("com/Jeremiah/ndk/NDKDemo"); jmethodID methodID = env->GetMethodID(clazz, "<init>", "()V"); jobject ReflectDemoObj = env->NewObject(clazz, methodID); LOGD("ReflectDemoObj %p", ReflectDemoObj);
-
AllocObject
创建对象1 2 3 4 5
jclass clazz = env->FindClass("com/Jeremiah/ndk/NDKDemo"); jmethodID methodID2 = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;I)V"); jobject ReflectDemoObj2 = env->AllocObject(clazz); jstring jstr = env->NewStringUTF("from jni str"); env->CallNonvirtualVoidMethod(ReflectDemoObj2, clazz, methodID2, jstr, 100);
通过JNI访问Java属性
-
获取静态字段
1 2 3 4 5 6 7 8
jfieldID privateStaticStringField = env->GetStaticFieldID(clazz, "privateStaticStringField", "Ljava/lang/String;"); jstring privateStaticString = static_cast<jstring>(env->GetStaticObjectField(clazz, privateStaticStringField)); const char* privatecstr = env->GetStringUTFChars(privateStaticString, nullptr); LOGD("privateStaticString: %s", privatecstr); env->ReleaseStringUTFChars(privateStaticString, privatecstr);
-
获取对象字段
1 2 3 4 5 6 7
jfieldID publicStringField = env->GetFieldID(clazz, "publicStringField", "Ljava/lang/String;"); jstring publicString = static_cast<jstring>(env->GetObjectField(ReflectDemoObj, publicStringField)); const char* publiccstr = env->GetStringUTFChars(publicString, nullptr); LOGD("publicStringField: %s", publiccstr);
-
设置字段
1
env->SetObjectField(ndkobj, privateStringFieldID, env->NewStringUTF("Jeremiah"));
通过JNI访问Java数组
-
获取数组字段ID
1 2 3 4
jfieldID byteArrayID = env->GetFieldID(clazz, "byteArray", "[B"); jbyteArray byteArray = static_cast<jbyteArray>(env->GetObjectField(ReflectDemoObj, byteArrayID)); int _byteArrayLength = env->GetArrayLength(byteArray); // 得到数组长度
-
修改数组字段
1 2 3 4 5 6
char javaByte[10]; for(int i = 0; i < 10; i++){ javaByte[i] = static_cast<char>(100 - i); } const jbyte *java_array = reinterpret_cast<const jbyte *>(javaByte); env->SetByteArrayRegion(byteArray, 0, _byteArrayLength, java_array);
-
获取数组字段
1 2 3 4 5 6 7
byteArray = static_cast<jbyteArray>(env->GetObjectField(ReflectDemoObj, byteArrayID)); _byteArrayLength = env->GetArrayLength(byteArray); char* str = reinterpret_cast<char *>(env->GetByteArrayElements(byteArray, nullptr)); for(int i = 0; i < _byteArrayLength; i++){ LOGD("str[%d]=%d", i, str[i]); } env->ReleaseByteArrayElements(jbyteArray, reinterpret_cast<jbyte *>(cbyteArray), 0);