本示例将指导您了解 hello-jni,这是一个使用 NDK 构建的最小 C/C++ 应用。此示例位于 ndk-samples 代码库的 hello-jni 目录中,在 android-mk 分支内。
Android.mk
以下两行提供了原生源文件的名称以及要构建的共享库的名称。构建系统添加 lib 前缀和 .so 扩展名后,构建的库的完整名称是 libhello-jni.so。
LOCAL_SRC_FILES := hello-jni.c LOCAL_MODULE := hello-jni
如需详细了解 Android.mk 文件的作用以及如何使用它,请参阅Android.mk。
Application.mk
此行告知构建系统要构建的 CPU 和架构。在此示例中,构建系统会为所有支持的架构构建。
APP_ABI := all
如需详细了解 Application.mk 文件以及如何使用它,请参阅Application.mk。
Java 端的实现
helloJNI.java 文件位于 hellojni/src/com/example/hellojni/ 中。它调用一个函数从原生端检索字符串,然后将其显示在屏幕上。
源代码中包含 NDK 用户特别感兴趣的三行。此处按其使用顺序(而非行顺序)呈现这些代码。
此函数调用在应用启动时加载 .so 文件。
Kotlin
System.loadLibrary("hello-jni")
Java
System.loadLibrary("hello-jni");
此方法声明中的 native 关键字会告知虚拟机该函数位于共享库中(即在原生端实现)。
Kotlin
external fun stringFromJNI(): String
Java
public native String stringFromJNI();
Android 框架会调用前述步骤中加载和声明的函数,并在屏幕上显示字符串。
Kotlin
tv.text = stringFromJNI()
Java
tv.setText( stringFromJNI() );
C 端的实现
hello-jni.c 文件位于 hello-jni/jni/ 中。它包含一个函数,该函数返回 Java 端请求的字符串。函数声明如下所示:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
此声明对应于 Java 源代码中声明的原生函数。返回类型 jstring 是 Java 原生接口规范中定义的数据类型。它实际上不是字符串,而是指向 Java 字符串的指针。
在 jstring 之后是函数名称,该名称基于 Java 函数名称和包含该文件的路径。根据以下规则构建它:
- 在其前面加上
Java_。 - 描述相对于顶级源目录的文件路径。
- 使用下划线代替正斜杠。
- 省略
.java文件扩展名。 - 在最后一个下划线之后,附加函数名称。
遵循这些规则,本示例使用的函数名称为 Java_com_example_hellojni_HelloJni_stringFromJNI。此名称是指名为 stringFromJNI() 的 Java 函数,该函数位于 hellojni/src/com/example/hellojni/HelloJni.java 中。
JNIEnv* 是指向 VM 的指针,jobject 是指向从 Java 端传递的隐式 this 对象的指针。
以下行调用 VM API (*env),并向其传递返回值:即 Java 端的函数请求的字符串。
return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI ".");