JNI Hello World
距离上一次写博客已经很久很久了,上班有无尽的需求,下班又忙着打王者。完全没有自主学习的时间了。今天先水一篇,慢慢找回学习的欲望。
JNI能用来做什么
- 性能敏感逻辑。如绘图渲染,高精度计算。
- 平台相关逻辑,如调用系统原生API。
- 有商业价值的逻辑,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实现,影响性能。但我看完疑问很大,因为动态注册看上去在更早的时候去做方法的注册,难道不是更影响性能吗?疑问先留下,今天到这里。
最后修改于 2023-08-08