美文网首页
NDK 动态注册学习总结

NDK 动态注册学习总结

作者: mrwangyong | 来源:发表于2018-04-08 17:17 被阅读37次

    1. 什么是NDK动态注册:

    1. 不用再用静态注册般,需要方法名一一对应,不然找不到方法,动态注册能够摆脱这一限制,

    2. 不用所有的JNI方法都写到一个类文件中,项目较大的时候类无限膨胀,Android系统源码中JNI基本全部都是动态注册,比如最简单的MediaPlayer

    3. 由于是将函数映射表注册到JVM中,所以函数的调用速度更快。

    2. 动态注册怎么写?

    1. 编写Java的文件

      public class NdkLoad {
      
          static {
              System.loadLibrary("native-lib");
          }
        //JNI方法
          public native String stringFromJNI();
      }
      
      

    2. native-lib.cpp中重写JNI_OnLoad方法,此方法是JNI加载的时候,第一个调用的方法

      JNIEXPORT jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
          JNIEnv *env;
          //需要通过JVM动态的获取JNIEnv来提供JNI 版本 如果低于1.6则返回错误
          if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
              return JNI_ERR;
          }
      
          //需要调用这些函数的类
          //一定要注意名称的正确性:包名 + 类名
          jclass clz = env->FindClass("com/mrwang/ndkdynamic/NdkLoad");
          if(clz == NULL){
              LOGE("类名不对");
          } else {
              LOGE("类加载成功");
          }
      
          jint method_size = sizeof(nativeMethod) / sizeof(nativeMethod[0]);
          /**
            * 注册函数表
            * @param1 需要关联到那个【Java】类,Kotlin类不行
            * @param2 方法数组
            * @param3 方法数
            */
          env->RegisterNatives(clz, nativeMethod, method_size);
          //返回使用的JNI版本
          return JNI_VERSION_1_6;
      }
      
    3. 可以看到 具体顺序为

      1. 先确定JNI版本,因为JNI各个版本不兼容,确保JNI版本为JNI_VERSION_1_6
      2. 利用JNI环境 JNIEnv查找对应的JavaClass文件(利用反射),注意传入的参数,Java类型的书写方式
      3. 计算JNI方法数,具体注册几个方法
      4. 最终,调用JNIEnvRegisterNatives方法来把方法动态注册到JVM
    4. nativeMethod的结构

      // Java和JNI函数的绑定表  最后一个为JNI函数名字
      static JNINativeMethod nativeMethod[] = {
              {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromC},//绑定
      };
      
      1. 绑定表,第一个为Java中native方法名,第二个为方法签名,第三个为JNI中的方法
      2. JNI方法名任意,方法签名请对照JNI描述符相关规则
    5. 解注册,因JVM中注册的方法数是有数量限制的,所以建议注册一定要有解注册的操作,一般,解注册放在JNI_OnUnload方法中,此方法是JNI完全退出的时候调用的方法

      JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved)
      {
          JNIEnv *env;
          //需要通过JVM动态的获取JNIEnv来提供Java介质
          if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
              return;
          }
          jclass clz = env->FindClass("com/example/xingxinyu/cppdemo/JNIHelper");
          // 解注册函数表
          env->UnregisterNatives(clz);
      }
      

      很简单 UnregisterNatives即可

    相关文章

      网友评论

          本文标题:NDK 动态注册学习总结

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