Android NDK- JNI 注册 Native 方法

Posted teletian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android NDK- JNI 注册 Native 方法相关的知识,希望对你有一定的参考价值。

静态注册

静态注册的格式如下:
extern "C" JNIEXPORT [JNI参数类型] JNICALL Java_[包名]_[类名]_[方法名](JNIEnv* env, jobject, [JNI参数类型,参数名])
包名也用 _ 分隔。
包名、类名、方法名必须和 Java 中的一模一样。

例子:

extern "C" JNIEXPORT jstring JNICALL Java_com_sample_MainActivity_stringFromJNI(JNIEnv* env, jobject this_obj) 
    std::string hello = "Hello World from C++";
    return env->NewStringUTF(hello.c_str());

缺点:

  • 方法名很长
  • 效率低。首次调用 Java native 方法时需要根据方法名在 JNI 中查找对应的本地 C++ 函数并建立对应关系,这个过程是比较耗时的。

优点:

  • 编写不方便的缺点 android Studio 已经帮我们解决,可以先编写 Java native 方法,然后根据提示自动生成对应的本地 C++ 方法。
  • 阅读代码方便,本地 C++ 方法和 Java native 方法可以互相跳转查看。

动态注册

在调用 System.loadLibrary 加载库文件时,系统回调 JNI_OnLoad() 函数。
可以在 JNI_OnLoad 中做一些初始化操作,可以用 RegisterNatives 方法注册 Java native 方法。

jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);

这样的话,提前建立 Java native 方法和本地 C++ 方法的关系,在调用 Java native 方法的时候无需再查找并建立关系,就会比较快。

例子:

jstring stringFromJNI(JNIEnv* env, jobject this_obj) 
    std::string hello = "Hello World from C++";
    return env->NewStringUTF(hello.c_str());


static int registerNatives(JNIEnv *env) 

    // 要注册的 java 类的路径(完整的包名和类名)
    const char *className = "com/teletian/sample/MainActivity";

    /*
     * 要注册的函数列表
     * 参数:
     * 1. java 中用 native 关键字声明的函数名
     * 2. 函数签名,格式:(参数类型)返回类型
     * 3. C/C++ 中对应函数的函数名(地址)
     * */
    const JNINativeMethod nativeMethods[] = 
            "stringInJava", "()Ljava/lang/String;", (void *) stringFromJNI,
    ;

    jclass clazz = env->FindClass(className);
    if (clazz == nullptr) 
        return JNI_FALSE;
    
    int methodsCount = sizeof(nativeMethods) / sizeof(nativeMethods[0]);
    //注册函数 参数:java 类名,要注册的函数数组,要注册函数的数量
    if (env->RegisterNatives(clazz, nativeMethods, methodsCount) < 0) 
        return JNI_FALSE;
    
    return JNI_TRUE;


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) 
    JNIEnv *env = nullptr;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) 
        return JNI_ERR;
    
    assert(env != nullptr);
    //registerNatives -> env->RegisterNatives
    if (!registerNatives(env)) 
        return JNI_ERR;
    

    return JNI_VERSION_1_6;

缺点:

  • 代码不够简洁
  • 阅读代码不方便,本地 C++ 方法和 Java native 方法无法互相跳转查看。

优点:

  • 流程清洗可控
  • 效率高。提前建立关系,首次调用方法时速度快

以上是关于Android NDK- JNI 注册 Native 方法的主要内容,如果未能解决你的问题,请参考以下文章

Android NDK 从入门到精通

Android Studio NDK 入门教程--JNI动态注册本地方法

JNI_OnLoad通常用于Android NDK吗?

Android 使用 jni Demo示例

Android 使用 jni Demo示例

Android JNI——NDK与JNI基础