很多人并不清楚JNI和NDK的区别,JNI是Java中的概念,NDK是Android中的概念。JNI全名Java Native Interface(Java本地接口或Java原生接口),原生是什么意思?你的腿是原生的吧,不会是假腿吧。你可以理解成一个系统内部最核心的部分。JNI用来让Java和其他编程语言进行通信,主要是C和C++。而NDK是基于JNI的一套用于原生应用开发的工具包,全名为Native Development Kit。
JNI都有哪些数据类型
| Java类型 | JNI类型 | 函数签名对应的类型 |
|---|---|---|
| byte | jbyte | B |
| short | jshort | S |
| int | jint | I |
| long | jlong | J |
| float | jfloat | F |
| double | jdouble | D |
| boolean | jboolean | Z |
| char | jchar | C |
| void | jvoid | V |
| Object | jobject | Ljava/lang/Object; |
创建Native项目
选择Native C++。我们再看一下创建出来的示例代码都写了些什么。
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
这里包含了jni的头文件,这个jni.h文件很重要,里面定义了很多跨语言调用的函数。JNI函数名称必须按照这个规则,Java_包名替换点为下划线_类名_方法名。返回值jstring,表示我们在Java层定义的方法返回一个String,env为JNI的一些基础环境,jobject这里代表MainActivity,即当前对象。env->NewStringUTF(hello.c_str());我们创建一个Java层支持的字符串返回给Java层。
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// Example of a call to a native method
binding.sampleText.text = stringFromJNI()
}
/**
* A native method that is implemented by the 'myapplication' native library,
* which is packaged with this application.
*/
external fun stringFromJNI(): String
companion object {
// Used to load the 'myapplication' library on application startup.
init {
System.loadLibrary("myapplication")
}
}
}
native方法在Java中使用native关键字,而在Kotlin中使用external关键字,是一个意思。在调用JNI函数之前,我们需要加载动态库so文件,可以使用loadLibrary和load两种方式,loadLibrary是直接指定库名称,而load则是指定so文件的名称,必须为以lib开头并以.so结尾的文件。
在app模块中的build.gradle中,我们需要配置CMake的配置文件
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.18.1'
}
}
使用CMake这种方式,我们可以在编译Java代码的时候也顺便着把动态库也编译出来,并依赖上。我们也可以将编译好的so文件引入进来直接使用,本文暂不讲解。
示例程序就是一个简单的返回一个native层的字符串给Java层来使用的案例。它只是抛砖引玉,我们是可以通过Android NDK开发很多更加强大的功能的。