JNI Native動態註冊演練

前幾天分享了一篇關於TS流解析的文章,有朋友在問,你怎麼不使用動態註冊呀,什麼是JN動態註冊呢?今天給你們介紹使用一下。java

1、JNI Native註冊介紹

jni native註冊主要有2種,靜態註冊和動態註冊,其中靜態註冊是咱們經常使用的,由於部分項目用到jni的接口不多,經過靜態註冊就能很方便快速的實現,不過當接口多起來時就會略顯麻煩,而且靜態註冊的包名關聯,很容易致使錯誤,排版也很差看,而動態註冊就很好的解決了這一問題。android

  1. 靜態註冊:
    • 特色:實現快速,可是函數名也很是長,不適合管理數組

    • 它的編譯形式是根據函數名來遍歷查找java和jni函數之間的關聯,而後靜態調用app

      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

    • 它經過在jvm中註冊jni函數映射表,再根據函數映射表去調用對應名稱和參數的函數,ide

      /* * 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;

2、動態註冊的具體事例

  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:this

    #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:spa

    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();
         }

3、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動態註冊的正常使用步驟,固然在項目中還能夠更具體的封裝,掌握動態註冊是進行大型項目開發的必修課~

相關文章
相關標籤/搜索