直击大厂-NDK/JNI-C++静态注册与动态注册

271 阅读2分钟

代码比较简单就不放链接了。

静态注册和动态注册的不同点都在C++层,使用示例用的java代码是一样的。

废话不多说,直接发车。

静态注册

实现步骤:

1、在java层中写native函数,Alt+Enter 即可生成对应的C++函数,IDEA会直接帮你注册好方法。

2、在C++函数里面实现逻辑

//--------------------------------java层---------------------------------
static {
    System.loadLibrary("native-lib");
}
 public native void printLog(String str);
//--------------------------------c++层--------------------------------
extern "C"
JNIEXPORT void JNICALL
Java_com_example_jni_1thread_MainActivity_printLog(JNIEnv *env, jobject thiz, jstring str) {
    const char * myLog = env->GetStringUTFChars(str, nullptr);
    LOGE("JNISTUD:在C++层中打印日志:%s", myLog);
}
//--------------------------------运行日志--------------------------------
JNISTUDY:在C++层中打印日志:hello C++

动态注册

实现步骤:

1、在java层中写native函数。(PS:下面java层的演示代码和静态注册的方法一致)

2、重写C/C++的JNI_Onload()函数

3.通过JavaVM获得JNIEnv(JNIEnv可以看成java和C++之间的控制器,一些交互操作都需要该类来实现)

4.编写JNINativeMethod数组,里面需要java层函数名、函数签名、C++层对应函数的具体实现。

5.使用JNIEnvd的RegisterNatives函数进行动态注册

//--------------------------------java层---------------------------------
//步骤一
    static {
        System.loadLibrary("native-lib");//此处会调用native-lib的JNI_OnLoad函数,类似java中的构造函数
    }
    public native void printLog(String str);
//--------------------------------C++层---------------------------------

//对应函数的具体实现
void printCLog(JNIEnv *env, jobject thiz, jstring str) {
    const char * myLog = env->GetStringUTFChars(str, nullptr);
    LOGE("JNISTUD:在C++层中打印日志:%s", myLog);
}

//步骤四
static const JNINativeMethod jniNativeMethod [] = {
        {"printLog",              //函数名 
        "(Ljava/lang/String;)V",  //函数签名
        (void *)(printCLog)}      //函数指针
};

//步骤二
JNIEXPORT jint JNI_OnLoad(JavaVM * javaVm, void *) {
    //步骤三
    JNIEnv *jniEnv = nullptr;
    int result = javaVm->GetEnv(reinterpret_cast<void **>(&jniEnv), JNI_VERSION_1_6); //给JNIEnv赋值
    if (result != JNI_OK) { //JNI_OK为0
        return -1;
    }
    
    //步骤五
    const char * mainActivityClassName = "com/example/jni_thread/MainActivity";

    jclass mainActivityClass = jniEnv->FindClass(mainActivityClassName);
    jniEnv->RegisterNatives(mainActivityClass, //需要注册的函数所在的java类
                            jniNativeMethod,   //需要注册的函数的数组
                            sizeof(jniNativeMethod) / sizeof(JNINativeMethod)); //数组长度
    return JNI_VERSION_1_6;
}

//--------------------------------运行日志--------------------------------
JNISTUDY:在C++层中打印日志:hello C++

java方法签名查找表:签名表查阅链接

总结

静态注册

  • 优点:不难看出使用静态注册时比较方便(代码自动生成),便于使用与理解。
  • 缺点:在java层调用native函数时,需要去匹配C++层的函数名,因此性能上可能会出现一定的影响,而且在修改函数名的时候比较麻烦,灵活性较低。

动态注册

  • 优点:在System.loadLib的时候就完成了加载,所以源码层都是动态注册(为了性能),修改函数名、类名、包名啥的,只需要少量修改代码,灵活性还是相对比较高的。
  • 缺点:麻烦,不利于理解,,开发的时候一般不会用动态注册,因为确实麻烦.......(偷懒 嘿嘿嘿嘿)