JNI Hello World
距离上一次写博客已经很久很久了,上班有无尽的需求,下班又忙着打王者。完全没有自主学习的时间了。今天先水一篇,慢慢找回学习的欲望。

JNI能用来做什么

  1. 性能敏感逻辑。如绘图渲染,高精度计算。
  2. 平台相关逻辑,如调用系统原生API。
  3. 有商业价值的逻辑,native层比java层反编译和分析破解难度更高。

使用JNI将逻辑写到native层并不一定会提高性能,因为现代JVM虚拟机本身优化已经很好,少量代码性能差距不大,而调用JNI方法本身有不少的性能损耗。

在Android上使用JNI

最新版Android Studio提供了创建一个使用JNI的项目模板,项目类型选择 Native C++ 即可。

观察项目结构,发现

  • 源码下有一个 cpp 目录,其中有hello world和一个CMakeList.txt——native部分使用cmake构建
  • build.gradle.kts 下有一个配置块配置了使用上述CMakeList.txt进行构建
  • MainActivity 下使用 java.lang.System#loadLibrary 方法加载native库,其中一个方法名与cpp中的非常对应。
class MainActivity : AppCompatActivity() {
    ...

    external fun stringFromJNI(): String

    companion object {
        init {
            System.loadLibrary("testjni")
        }
    }
}
extern "C" JNIEXPORT jstring JNICALL
Java_top_ntutn_testjni_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

JNI方法的动态加载

jstring say_hello_2(JNIEnv *env, jobject thiz) {
    std::string hello2 = "我来自JNI动态注册";
    return env ->NewStringUTF(hello2.c_str());
}

static const JNINativeMethod gMethods[] = {
        "string2FromJNI",
        "()Ljava/lang/String;",
        (jstring *) say_hello_2
};

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    __android_log_print(ANDROID_LOG_INFO, "native", "Jni_OnLoad");
    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        __android_log_print(ANDROID_LOG_ERROR, "native", "jni error");
        return -1;
    }
    jclass clazz = env ->FindClass("top/ntutn/testjni/MainActivity");
    if (!clazz) {
        __android_log_print(ANDROID_LOG_ERROR, "native", "cannot find class");
        return -1;
    }
    if (env ->RegisterNatives(clazz, gMethods, (sizeof gMethods) / (sizeof gMethods[0]))) {
        __android_log_print(ANDROID_LOG_ERROR, "native", "register method error");
        return -1;
    }
    return JNI_VERSION_1_6;
}

据网上说与静态注册的区别是,静态注册要在第一次调用native方法时查找native实现,影响性能。但我看完疑问很大,因为动态注册看上去在更早的时候去做方法的注册,难道不是更影响性能吗?疑问先留下,今天到这里。

jnidemo


最后修改于 2023-08-08