Android JNI之动态注册

所谓动态注册,就是不用像静态注册那样按规则严格的命名native方法,而是在加载so库的时候完成这个从Java方法到native方法的匹配工作,而这个匹配工作,需要我们写native代码来完成。下面直入正题看看怎么写。

涉及的几个函数和实体(结构体)

  1. JavaVM * 
    指针,指向加载当前动态库的java虚拟机
  2. JNIEnv * 
    指针,指向当前使用的JNI版本,JNI中已定义的方法可以通过它来调用
  3. jint JNI_OnLoad(JavaVM *vm, void *reserved)函数 
    动态库加载的入口,调用System.loadLibrary()方法加载动态库后会回调该函数
  4. jclass FindClass(JNIEnv *env, const char *name)函数 
    根据name中传入的Java全路径类名,找到某个Java类(包路径用'/'分割)
  5. jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods)函数
    注册native方法
  6. JNINativeMethod结构体
    typedef struct { 
    
        char *name; 
    
        char *signature; 
    
        void *fnPtr; 
    
    } JNINativeMethod; 

    定义一个Java中声明的方法和native中实现的方法的对应关系

  7. jint GetEnv(JavaVM *vm, void **env, jint version)函数
    获取当前jvm环境的JNI环境指针

具体实现

废话不多见代码:

// native方法实现
void nativeDynamicLog(JNIEnv *evn, jobject obj){

}

// 声明待注册的native方法数组,结构体三个参数分别表示Java文件中声明的方法名、方法特征、native中的方法的指针
JNINativeMethod nativeMethod[] = {{"dynamicLog", "()V", (void*)nativeDynamicLog},};

// 重载jni.h中的JNI_OnLoad方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {

    JNIEnv *env;
    // JNI_VERSION_1_4是jni.h中定义好的常量,根据使用的sdk版本不同已定义的常量有所差异,具体见jni.h代码
    if (jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    
    jclass clz = env->FindClass("com/example/zhanghaiqiang/hellojni/HelloJni");

    env->RegisterNatives(clz, nativeMethod, sizeof(nativeMethod)/sizeof(nativeMethod[0]));


    return JNI_VERSION_1_4;
}

 

posted @ 2017-09-04 17:30  行走的段子  阅读(278)  评论(0编辑  收藏  举报