美文网首页
JNI动态注册

JNI动态注册

作者: 凌烟醉卧 | 来源:发表于2019-09-25 19:27 被阅读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;
    }
    

    相关文章

      网友评论

          本文标题:JNI动态注册

          本文链接:https://www.haomeiwen.com/subject/aslsyctx.html