美文网首页
JNI Native动态注册演练

JNI Native动态注册演练

作者: Felix_lin | 来源:发表于2018-06-23 13:46 被阅读41次

    前言:

    前几天分享了一篇关于TS流解析的文章,有朋友在问,你怎么不使用动态注册呀,什么是JN动态注册呢?今天给大家介绍使用一下。

    一、JNI Native注册介绍

    jni native注册主要有2种,静态注册和动态注册,其中静态注册是我们常用的,因为部分项目用到jni的接口很少,通过静态注册就能很方便快速的实现,不过当接口多起来时就会略显麻烦,并且静态注册的包名关联,很容易导致错误,排版也不好看,而动态注册就很好的解决了这一问题。

    1. 静态注册:
      • 特点:实现快速,但是函数名也非常长,不适合管理

      • 它的编译形式是根据函数名来遍历查找java和jni函数之间的关联,然后静态调用

          extern "C" JNIEXPORT jstring JNICALL
          Java_com_blur_blurbyjnidemo_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {
              std::string hello = "Hello from C++";
              return env->NewStringUTF(hello.c_str());
          }
        
    2. 动态注册:
      • 特点:每个方法一一映射,简单明了,不容易出错,便于管理

      • 它通过在jvm中注册jni函数映射表,再根据函数映射表去调用对应名称和参数的函数,

              /*
               * used in RegisterNatives to describe native method name, signature,
               * and function pointer.from jni.h
               */
              typedef struct {
                  const char* name;//java方法名称
                  const char* signature;//jni对应的函数参数和返回值的描述值,具体参考第三节
                  void* fnPtr;//fnPtr是函数指针,指向C函数
              } JNINativeMethod;
        

    二、动态注册的具体事例

    1. 动态注册的几个步骤:

      • 绑定对应的方法映射表
      • 在JNI_OnLoad时注册映射表中的方法
      • 下面是demo代码

      native-lib.cpp:

           #include <jni.h>
           #include "mDebug.h"
           #include <string>
           #ifndef NELEM
           #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
           #endif
           //c测试方法
           static jstring j_hello(JNIEnv* env, jobject thiz )
           {
                    const char* hello  = "Hello from C++";
                    return env->NewStringUTF(hello);
           }
           static jstring j_hello2(JNIEnv* env, jobject thiz )
           {
                    const char* hello  = "test-----------------------------2";
                    return env->NewStringUTF(hello);
           }
           
           /**
            * 1. 绑定对应的方法映射表
            */
           static const JNINativeMethod jniMethods[] = {
                   {"stringFromJNI", "()Ljava/lang/String;", (void*)j_hello},
                   {"stringFromJNI2", "()Ljava/lang/String;", (void*)j_hello2},
           };
           /**注册方法*/
           static int  registerMethods(JNIEnv * env, const char* className ,const JNINativeMethod* gMethods, int numMethods) {
                    jclass clazz;
                    clazz =env->FindClass( className);
                    if (clazz == NULL) {
                             return JNI_FALSE;
                    }
                    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
                             return JNI_FALSE;
                    }
                    return JNI_TRUE;
           }
           
           /**
            * 注册所有方法
            */
           static int registerAllMethods(JNIEnv* env) {
                    const char* kClassName = "com/blur/blurbyjnidemo/NativeLib";//指定要注册的类
                    return registerMethods(env, kClassName,jniMethods,  NELEM(jniMethods));
           }
           
           /***
            * 2. jni_onload加载时注册映射表中的方法
            */
           JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
                    JNIEnv* env = NULL;
                    if (vm->GetEnv( (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
                             return -1;
                    }
                    mInfo("JNI_OnLoad");
                    if (!registerAllMethods(env)) {//注册所有方法
                             return -1;
                    }
                    return JNI_VERSION_1_4;
           }
      

      mDebug.h:

           #ifndef __MDEBUG_H__
           #define __MDEBUG_H__
           #include <jni.h>
           #include <android/log.h>
           #ifndef BASETYPES
           #define BASETYPES
           
           //typedef _Null_terminated_ char *PSZ;
           #endif  /* !BASETYPES */
           #ifndef CAMERA_LOG_TAG
           #define CAMERA_LOG_TAG  "debug"
           #define mDebug(format, ...) __android_log_print(ANDROID_LOG_ERROR,CAMERA_LOG_TAG, format" [File:%s, Line:%d, Function:%s]",##__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__)
           #define mInfo(format, ...)  __android_log_print(ANDROID_LOG_INFO,CAMERA_LOG_TAG, format" [File:%s, Line:%d, Function:%s]",##__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__)
           #define mMsg(...)  __android_log_print(ANDROID_LOG_INFO,CAMERA_LOG_TAG, __VA_ARGS__)
           #endif
           
           #endif
      

      NativeLib.java:

           package com.blur.blurbyjnidemo;
           public class NativeLib {
                    // Used to load the 'native-lib' library on application startup.
                    static {
                             System.loadLibrary("native-lib");
                    }
           
                    /**
                     * A native method that is implemented by the 'native-lib' native library,
                     * which is packaged with this application.
                     */
                    public  native String stringFromJNI();
                    public static native String stringFromJNI2();
           }
      

    三、jni对应参数映射表

    上面动态注册结构第二项参数,需要填入参数和方法返回的映射值:

    这个字符串的结构是一个括号后面再接字符串:

    1. "()"中的描述的是函数的传入参数描述

    2. 括号后面接的是返回值描述
    比如:"()V":表示 void function(); (JF)Z":表示 boolean function(long l,float f);等
    基本类型类型对照表

        V      void            void
        Z       jboolean     boolean
        I        jint              int
        J       jlong            long
        D      jdouble       double
        F      jfloat            float
        B      jbyte            byte
        C      jchar           char
        S      jshort          short
    
        数组在前面加"[",如:
            [I       jintArray      int[]
    

    非基本类型,比如class类型的,以"L"开头,通过"/"隔开包名与类名,以";"结尾,比如:

        Ljava/lang/String; String jstring
    

    以上就是JNI动态注册的正常使用步骤,当然在项目中还可以更具体的封装,掌握动态注册是进行大型项目开发的必修课~

    相关文章

      网友评论

          本文标题:JNI Native动态注册演练

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