记录一些 jni 中的函数使用与静态注册相关知识。
# 可执行程序编译
首先准备 Android.mk 文件,文件内容如下所示:
1 | $ LOCAL_PATH := $(call my-dir) |
准备 Application.mk 文件,文件内代码如下所示:
1 | $ APP_API := x86 armeabi-v7a |
在以上文件存储处打开 cmd,执行 ndk-build 指令生成 linux 下的可执行程序。
# 相关函数
jni 中的函数可以在 /java/include 下的 jni.h 文件中查询,以下只列举了一些可能使用到的函数。
# 调用 java 层普通方法
1 | $ (*CallObjectMethod) (JNIEnv*, jobject, jmethodID, ...); |
前两个为默认参数,第三个参数由以下方法获取。
# 获取 java 层实例方法的值
1 | $ jmethodID (*GetMethodID) (JNIEnv*, jclass, const char*, const char*); |
其中,第一个 const char * 为 java 层方法名称,第二个 const char * 为 java 层方法的签名 (即方法返回类型),而 jclass 由以下方法获取:
1 | $ jclass (*FindClass) (JNIEnv*, const char*) |
其中,const char * 为目标所在 class 的路径 (使用 \ 代替.)。
# 获取 java 层实例字段的值
1 | $ jobject (*GetObjectField) (JNIEnv*, jobject , jfieldID); |
其中,jfieldID 由以下代码获取:
1 | $ jfieldID (*GetFieldID) (JNIenv*, jclass, const char*, const char*); |
第一个 const char * 为实例字段的名称,第二个 const char * 为实例字段签名 (即实例字段类型)。
# 设置 java 层实例字段的值
1 | $ void (*SetObjectField) (JNIEnv*, jobject, jfieldID, jobject); |
第二个 jobject 为 java 层实例字段设置的值。
# 静态注册
# 生成 jni 头文件
在 class 代码中声明 native 方法,之后在 cmd 窗口中切换到源码目录处,执行以下代码生成 jni 头文件:
1 | $ javah -jni com.example.main.class |
# 编写 c 代码
在 c 文件中 include 之前生成的头文件,之后便能在 c 文件中具体实现在头文件中声明的函数。
# 生成动态链接库
将之前的两个 mk 文件同.c 与.h 文件放在同一文件夹下,使用 ndk-build 生成动态链接库文件。
# 调用动态链接库
在 java 代码中使用以下代码调用生成的动态链接库:
1 | $ System.loadLibrary ("Module") |
# 总结
将以上个部分内容相结合,即可实现在 native 层调用 java 函数或获取 java 变量值。