JNI动态注册

2019-09-25  本文已影响0人  凌烟醉卧

在此之前我们一直在jni中使用Java_PACKAGENAME_CLASSNAME_METHODNAME 来进行与java方法的匹配,这种方式我们称之为静态注册。
而动态注册则意味着方法名可以不用这么长了,在android aosp源码中就大量的使用了动态注册的形式。
MainActivity.java

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dynamicJavaTest();
        dynamicJavaTest2(5);
    }

    native  void dynamicJavaTest();
    native  int dynamicJavaTest2(int i);
}

static {
        System.loadLibrary("native-lib");
    }

这句执行,会立刻调用native-lib.cpp中的JNI_OnLoad这个方法

native-lib.cpp

#include <jni.h>
#include <string>

#include <android/log.h>
#define LOG_TAG "atguigu"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGE(...) __android_log_print(ERROR,LOG_TAG ,__VA_ARGS__) // 定义LOGD类型

JavaVM *_vm;

void dynamicTest(){
    LOGI("JNI dynamicTest");
}

jint dynamicTest2(JNIEnv *env, jobject instance,jint i){
    LOGI("JNI dynamicTest2:%d",i);
    return 100;
}

static const JNINativeMethod method[] = {
        {"dynamicJavaTest","()V",(void*)dynamicTest},
        {"dynamicJavaTest2","(I)I",(int*)dynamicTest2}
};
static const char *mClassName = "com/example/myapplication/MainActivity";

int JNI_OnLoad(JavaVM *vm,void  *re){
    LOGI("JNI_Onload方法初始化");

    _vm = vm;
    //获得JNIEnv
    JNIEnv *env = 0;
    int r = vm->GetEnv((void**)&env,JNI_VERSION_1_6);
    //小于0失败,等于0成功
    if(r != JNI_OK){
        return -1;
    }

    //获得class对象
    jclass jcls =  env->FindClass(mClassName);
    //动态注册
    env->RegisterNatives(jcls,method, sizeof(method)/ sizeof(JNINativeMethod));
    return JNI_VERSION_1_6;
}

代码详解:
我们使用RegisterNatives这个方法来进行动态注册,RegisterNatives的原型为:

jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,
        jint nMethods)

第二个参数为JNINativeMethod,它是一个结构体:

typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;

然后我们来使用一个数组来构造这个结构体:

static const JNINativeMethod method[] = {
        {"dynamicJavaTest","()V",(void*)dynamicTest},
        {"dynamicJavaTest2","(I)I",(int*)dynamicTest2}
};

dynamicJavaTest和dynamicJavaTest2为Java中的native方法。
()V 和 (I)I分别为两个方法的签名
(void)dynamicTest和(int)dynamicTest2为JNI中对应的两个方法,这两个方法都是Java调用C的方法。

要注意的是JNI中的这两个方法的参数JNIEnv *env在什么时候传递:

void dynamicTest(){//无参数时不用加JNIEnv *env, jobject instance
    LOGI("JNI dynamicTest");
}
//有参数时如jint i时需要加上JNIEnv *env, jobject instance,否则会把参数当作JNIEnv
jint dynamicTest2(JNIEnv *env, jobject instance,jint i){
    LOGI("JNI dynamicTest2:%d",i);
    return 100;
}
上一篇下一篇

猜你喜欢

热点阅读