静态注册和动态注册的区别
静态注册
- 命名规则:
通常是 Java_ 前缀 + Java 类的全限定名 + 方法名。 - 注册时机:
在 JVM 启动加载类时自动完成注册,Java 类中的本地方法直接通过函数名绑定。 - 注册函数的控制:
JVM 自动处理
动态注册
命名规则:
动态注册通过手动调用 JNI 提供的RegisterNatives
方法将 Java 方法与本地函数绑定。
不需要遵守特定的命名规则,开发者可以灵活地使用任意名称的 C/C++ 函数,然后在程序启动时(通常在 JNI_OnLoad 函数中)进行注册。注册时机:
注册时机由开发者控制,通常在 JNI_OnLoad 函数中调用 RegisterNatives 完成注册。注册函数的控制:
手动注册,开发者可以完全控制。
JNINativeMethod结构体
typedef struct {
const char* name; // native方法名
const char* signature; // 方法签名,例如()Ljava/lang/String;
void* fnPtr; // 函数指针
} JNINativeMethod;
方法签名
字符串,由一对小括号和若干签名符号组成,其中括号内写传入参数的签名符号,没有参数则不写,括号外写返回参数的签名符号。
签名符号 | C/C++ | java |
---|---|---|
V | void | void |
Z | jboolean | boolean |
I | jnit | int |
D | jdouble | double |
F | jfloat | float |
B | jbyte | byte |
C | jchar | char |
S | jshort | short |
[Z | jbooleanAray | boolean[] |
[I | jintArray | int[] |
[D | jdoubleArray | double[] |
[F | jfloatArray | float[] |
[B | jbyteArray | byte[] |
[C | jcharArray | char[] |
[S | jshortArray | short[] |
L+完整包名+类名 | jobject | class |
修改native代码
jstring stringFromJNI(
JNIEnv *env,
jclass clazz) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
jstring myFunc(
JNIEnv *env, jclass thiz,jint i_param){
std::string retVal = "参数是===>:";
retVal+=i_param;
return env->NewStringUTF(retVal.c_str());
}
JNI函数注册(动态注册)
jint JNI_OnLoad(JavaVM* vm,void* reserved){
JNIEnv *env = NULL;
if(vm->GetEnv((void**)&env,JNI_VERSION_1_6)!=JNI_OK){
return -1;
}
jclass clazz = env->FindClass("com/example/ndktest/MainActivity");
JNINativeMethod methods[] = {
{"stringFromJNI","()Ljava/lang/String;", (void*)stringFromJNI},
{"myFunc", "(I)Ljava/lang/String;", (void*)myFunc}
};
env->RegisterNatives(clazz,methods,sizeof(methods)/sizeof (methods[0]));
return JNI_VERSION_1_6;
}
JNI函数调用(动态注册)
Toast.makeText(this,myFunc(97),Toast.LENGTH_SHORT).show();
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());