JNI的 静态注册与动态注册

简介: JNI的 静态注册与动态注册

静态注册

按照JNI规范的命名规则进行查找,这种方式叫静态注册

JNI规范书写函数名 Java_定义native方法的全路径_方法名

extern "C" JNIEXPORT jint JNICALL Java_com_example_opentr069_OpenTR069Native_getNatDetected(JNIEnv * env,
       jclass clazz){
    return sk_get_nat_stun_flag();
}

动态注册

调用JNI提供的RegisterNatives函数,将本地函数注册到JVM中,这种方式叫动态注册。


在库加载时会自动调用JNI_OnLoad()函数,开发者经常会JNI_OnLoad()函数做一些初始化操作,动态注册就是在这里进行的。调用API是env->RegisterNatives(clazz, gMethods, numMethods)。


env->RegisterNatives(clazz, gMethods, numMethods)是一个接受三个参数的函数,第一个参数是Java对应的类,第二个参数是JNINativeMethod数组,第三个参数是JNINativeMethod数组的长度,也就是需要注册的方法的个数。


其中JNINativeMethod表示的是方法方法的映射关系,它包括Java中的方法名,对应的方法签名和Native映射的函数方法。


相比静态注册,动态注册的灵活性更高,如果修改了java native函数所在类的包名或类名,仅调整Java native函数的签名信息即可。


// 类库加载时自动调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reversed)
{
    JNIEnv *env = NULL;
    // 初始化JNIEnv
    if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
        return JNI_FALSE;
    }
    // 找到需要动态动态注册的Jni类
    jclass jniClass = env->FindClass("com/fly/jnitest/MainActivity");
    if(nullptr == jniClass){
        return JNI_FALSE;
    }
    // 动态注册
    env->RegisterNatives(jniClass,nativeMethod,sizeof(JNINativeMethod)/sizeof(nativeMethod));
    // 返回JNI使用的版本
    return JNI_VERSION_1_6;
}
 
jstring stringFromJNI(JNIEnv *jniEnv,jobject jobj){
    return jniEnv->NewStringUTF("hello from C++ string");
}
 
static const JNINativeMethod nativeMethod[] = {
        // Java中的函数名
        {"stringFromJNI",
            // 函数签名信息
            "()Ljava/lang/String;",
            // native的函数指针
            (void *) (stringFromJNI)
        }
};

JNI属性描述

JNI属性描述符也就是变量类型在JNI中的表示方式,它是由属性的声明类型决定的。例如使用"I"表示int属性,使用"F"表示float属性,使用"D"表示double属性,使用"Z"表示boolean属性等。


对于引用各类型属性的描述符,比如java.lang.String,需要以字母"L"开头, 解析来是JNI类描述符并使用一个分号结束,Java中完整类名中的".“被”/"替换掉了。因此,对于java.lang.String类型需要使用以下形式的属性描述符:


Ljava/lang/String;


数组类型的描述符由"["以及数组元素类型的描述符组成,例如,[I表示整型数组的属性描述符

函数描述符

通常我们又称为函数签名,一个函数描述符由他的参数类型和返回值类型组成,参数类型在前,且使用一对括号括起来,参数类型是以他们在函数声明中的顺序罗列的,多个参数类型之间是没有分隔符,如果一个方法没有参数,使用一对空的括号表示即可。函数的返回值类型紧跟在包裹参数类型的右括号后边。


例如(I)V代指接收一个整型参数且返回值为空的函数。()D代指的是没有输入参数,返回值是一个double类型的函数。


注意:不要被C函数中像"int f(void)“这样的函数原型误导,误认为”(V)I"是它的方法描述符,其实"()I"才函数f的函数描述符

 


目录
相关文章
|
9月前
|
Java API Android开发
Android 静态注册广播接收者和动态注册广播接收者(Android8.0之前和之后)
Android 静态注册广播接收者和动态注册广播接收者(Android8.0之前和之后)
238 0
|
10月前
|
Java Android开发 C++
[Android JNI] --- 静态注册和动态注册实现java和native相互调用
[Android JNI] --- 静态注册和动态注册实现java和native相互调用
118 0
|
Java API Android开发
|
Java Android开发 C++
【Android NDK 开发】JNI 动态注册 ( 动态注册流程 | JNI_OnLoad 方法 | JNINativeMethod 结构体 | GetEnv | RegisterNatives )
【Android NDK 开发】JNI 动态注册 ( 动态注册流程 | JNI_OnLoad 方法 | JNINativeMethod 结构体 | GetEnv | RegisterNatives )
603 0
|
Java Android开发 C++
【Android】JNI静态与动态注册介绍
【Android】JNI静态与动态注册介绍
250 4
【Android】JNI静态与动态注册介绍
|
存储 IDE Java
NDK 系列(6):说一下注册 JNI 函数的方式和时机
NDK 系列(6):说一下注册 JNI 函数的方式和时机
86 0
NDK 系列(6):说一下注册 JNI 函数的方式和时机
|
Java C++
JNI全局回调java方法
JNI全局回调java方法
|
消息中间件 存储 Android开发
Android 四大组件之一:BroadCastReceiver动态注册广播流程
Android 四大组件之一:BroadCastReceiver动态注册广播流程
245 0
Android 四大组件之一:BroadCastReceiver动态注册广播流程
|
网络协议 Oracle 关系型数据库