• 【Android】JNI静态与动态注册介绍


    【Android】JNI静态与动态注册介绍

    JNI的两种注册机制:静态注册和动态注册

    JNI介绍

    JNI(Java Native Interface),即Java本地接口,JNI是Java调用Native 语言的一种特性。通过JNI可以使得Java与C/C++机型交互.

    方式

    • 静态注册
    • 动态注册:需要提供Java中Native方法的方法签名和Native层中对应的实现函数。

    静态注册

    要求C/C++层的函数名符合某种特定的要求:包含Java中Native方法的目录信息和方法名。

    Example

    Java

    package cn.com.codingce.ndkpractice;
    
    public native String stringFromJNI();
    
    • 1
    • 2
    • 3

    C++

    extern "C"
    JNIEXPORT jstring JNICALL
    Java_cn_com_codingce_ndkpractice_MainActivity_stringFromJNI(JNIEnv *env, jobject thiz) {
        std::string hello = "Hello from C++";
        //crashTest();
    
        return env->NewStringUTF(hello.c_str());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    按照以上规则进行命名,在调用到Native的方法时,JVM会去查找是否存在对应函数名的函数,以此实现静态注册。

    动态注册

    动态注册相对于静态注册,优点是不再根据特定路径查找函数的实现,带来两个好处:

    • 没有了冗杂的函数名,适用于大型项目开发。
    • 由于不再根据Native函数查找对应的JNI层函数,所以首次调用速度比静态注册快。

    开发者需要自行提供Java层和C/C++层中的映射关系。

    一种可行的方法是基于JNI重载JNI_OnLoad(),在其中对函数进行动态注册。

    Example

    Java

    package cn.com.codingce.ndkpractice.utils;
    
    public static native void logInit(String logFilePath, String logName, int logfileLevel, int logScreenLevel);
    
    • 1
    • 2
    • 3

    C++

    此步骤涉及到如何获取Java函数。

    static JNINativeMethod nativeUtilsMethods[] = {
            {"logInit",  "(Ljava/lang/String;Ljava/lang/String;II)V", (void *) localLogInit},
            {"logJni",   "(ILjava/lang/String;)V",                    (void *) logJni},
            {"logClose", "()V",                                       (void *) logClose},
    };
    
    static void nativeLogUtilsRegisterNatives(JNIEnv *jniEnv) {
        if (jniEnv == nullptr) {
            return;
        }
    
        jclass clazz = nullptr;
        do {
            clazz = jniEnv->FindClass("cn/com/codingce/ndkpractice/utils/LogUtils");
            if (clazz == nullptr) {
                diagnosis_assert(!"FindClass LogUtils error!");
                break;
            }
            if (jniEnv->RegisterNatives(clazz, nativeUtilsMethods,
                                        std::extent<decltype(nativeUtilsMethods)>::value) != 0) {
                diagnosis_assert(!"RegisterNatives error!");
                break;
            }
        } while (false);
        if (jniEnv->ExceptionCheck() == JNI_TRUE) {
            jniEnv->ExceptionClear();
        }
        if (clazz != nullptr) {
            jniEnv->DeleteLocalRef(clazz);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    重载JNI_OnLoad函数,并在其中调用nativeLogUtilsRegisterNatives函数

    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
        JNIEnv *jniEnv{nullptr};
        if (vm->GetEnv((void **) &jniEnv, JNI_VERSION_1_6) != JNI_OK) {
            diagnosis_assert(!"JNI version error!");
            return JNI_EVERSION;
        }
    
        nativeLogUtilsRegisterNatives(jniEnv);
        return JNI_VERSION_1_6;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    更多内容:

    Github:https://github.com/xzMhehe
    Gitee:https://gitee.com/codingce

  • 相关阅读:
    软考中级电子商务设计师主要考点?
    关于工作方法和高效工作的建议
    第56篇-某创网加速乐cookie值分析【2023-09-15】
    神秘的Java集合与UML
    第08章 中文分词
    消息队列——消息队列入门
    【javascript】内部引入与外部引入javascript
    ssm+vue+elementUI 电子资源管理系统-#毕业设计
    反编译正常回编译出现问题自己解决办法
    windows安装MySQL详细步骤
  • 原文地址:https://blog.csdn.net/weixin_43874301/article/details/128129892