在这里有个小技巧,在每次创建 Cpp
方法的时候,都要这样写:
Java_top_jowanxu_jnidemo_MainActivity_stringFromJNI
当你方法多的时候,要改名的时候,就很麻烦了,所以我们可以将前面共有的提取出来,使用宏定义来实现。
首先,创建一个头文件,并且在里面定义宏:
// file name package-func-name #ifndef JNIDEMO_PACKAGE_FUNC_NAME_H #define JNIDEMO_PACKAGE_FUNC_NAME_H #define PKFUNC(name) Java_top_jowanxu_jnidemo_##name #endif //JNIDEMO_PACKAGE_FUNC_NAME_H
然后在我们需要使用的时候,先导入头文件,然后使用方法:
extern "C" JNIEXPORT jstring JNICALL PKFUNC(MainActivity_stringFromJNI)( JNIEnv *env, jobject thiz) { return env->NewStringUTF("Hello from JNI !"); }
这样就很方便了,在这里感谢李哥提供的帮助。
开始
在这里先介绍Java类型对应Jni层数据描述的关系:
基本类型:
Java类型 | JNI类型 | C/C++类型 | 大小 |
---|---|---|---|
boolean | jboolean | unsigned char | 无符号 8位 |
byte | jbyte | char | 有符号 8位 |
char | jchar | unsigned short | 无符号 16位 |
short | jshort | short | 有符号 16位 |
int | jint | int | 有符号 32位 |
long | jlong | long long | 有符号 64位 |
float | jfloat | float | 32位 |
double | jdouble | double | 64位 |
引用类型:
Java类型 | JNI类型 |
---|---|
void | void |
java.lang.Class | jclass |
java.lang.Throwable | jthrowable |
java.lang.String | jclass |
Object | jobject |
type[] | jtypeArray |
type表示基本类型和Object。
我们来写一个最大公约数的方法,先定义一个方法:
external fun gcd(m: Int, n: Int): Int
然后在Cpp里面创建对应的方法:
#include "package-func-name.h" extern "C" JNIEXPORT jint JNICALL PKFUNC(MainActivity_gcd)(JNIEnv *env, jobject, jint m, jint n) { jint c; for (; m > 0;) { c = n % m; n = m; m = c; } return n; }
在Cpp里面定义的函数的第一个参数都是 JNIEnv *env
,这是什么东西呢?
JNIEnv
就是 JNI Environmont
,JNI的环境。
再举个例子,当我们用一个引用类型参数的时候,比如一个int数组:
extern "C" JNIEXPORT jint JNICALL PKFUNC(MainActivity_gcd)(JNIEnv *env, jobject, jintArray _data) { }
_data
其实是一个指向 JVM
里面对应该数组的内存的指针,你可以通过它获取数组的元素等操作,但它本身和数组无关,所以你不能对他进行操作。
只能通过 JNIEnv
指针来获取数组本身的指针,然后进行各种操作。
extern "C" JNIEXPORT void JNICALL PKFUNC(MainActivity_getArray)( JNIEnv *env, jobject, jintArray _data) { jint *data = env->GetIntArrayElements(_data, NULL); for (int i = 0; i < env->GetArrayLength(_data); ++i) { LOGE("------:%d", data[i]); } env->ReleaseIntArrayElements(_data, data, JNI_ABORT); // ReleaseIntArrayElements释放资源: // JNI_ABORT表示不复制,释放资源 // JNI_OK表示复制回到JVM中,释放资源 // JNI_COMMIT表示复制,不释放资源 }
打印内容:
E/CUSTOMER_NDK_JNI: ------:1 E/CUSTOMER_NDK_JNI: ------:2 E/CUSTOMER_NDK_JNI: ------:3 E/CUSTOMER_NDK_JNI: ------:4