前言
这次总结一下jni数据交互(通讯)的方式,本篇侧重应用,native层主要用C++编写。掌握数据交互方式,对入门jni及理解java与C++的数据类型映射起到四两拨千斤的作用。本编着重jni数据传递实现,跳过jni开发环境搭建及jni基础知识(网上基本可以找到对应解决方案)。
平时为了实现某个功能(RFID编解码库),如果C++开发那边已经有现成的C++类库,再用java进行重复的工作就没必要了。我们只需提供接口java层调用即可,如果C++大佬没空,接口层代码自己也可以实现,最后在编译成Android平台调用的so库。so库可以自己使用,也可以给客户使用,不用担心代码被反编译的问题。
本次实现jni数据交互方式(jni静态注册)如图所示:
jni编译的方式
- 使用Cmake文件编译
- 使用mk文件编译(这次使用mk文件编译)
环境(知识jni开发的环境)准备:
这两种方式都可以编译调试 ,如果只是调试native与java层代码,是不需要执行ndk-build命令(生成不同cpu架构的so库)。
jni开发流程
- 编写java本地方法
- 生成.h头文件 , 使用java命令是javah(必须在包名外使用javah命令)
- 创建jni目录,引入头文件,根据头文件实现C/C++代码
- 编写Android.mk、Application.mk文件
- Ndk编译生成动态库
- Java代码load动态库,调用native代码
知识准备
java方法签名查看
查看系统java系统方法
javap -s java.lang.String
查看自定义类(在class目录下执行):
javap -s com.sjl.jnidata.JniDataTransfer
C和C++函数时的JNI使用区别
jni.h头文件中对于*.c & *.cpp采用不同的定义,在C的定义中,env是二级指针,C需要对env指针进行双重deferencing,而且须将env作为第一个参数传给jni函数;而在C++的定义中,env是一级指针。
- 在 C 中,JNI 函数调用由“(*env)->”作前缀,目的是为了取出函数指针所引用的值;
- 在 C++ 中,JNIEnv 类拥有处理函数指针查找的内联成员函数。
举栗子:
C 语法(.c文件):jsize len = (*env)->GetArrayLength(env,array);
C++ 语法( .cpp文件):jsize len =env->GetArrayLength(array);
常见错误
1. javah生成头文件报错:编码GBK的不可映射字符
解决方法:javah -jni -encoding UTF-8 类名
2.运行项目报错:
解决方法:
退出应用或者点击终止项目或者清理项目。
jni数据传递
native层处理java层数据,简单说就是C++仿java的写法,java几行代码实现,在native实现可能需要多行实现。举个例子简单说明一下,分别用java构造器,java反射,C++三种方式创建同一个对象作为对比。
假设有这么一个类Simple:
package com.sjl.jnidata;
public class Simple {
private String a;
private int b;
public Simple() {
}
public Simple(String a, int b) {
this.a = a;
this.b = b;
}
//省略get,set方法...
}
使用java构造器:
Simple simple = new Simple("李四",99);
使用java反射:
try {
Class<?> clz = Class.forName("com.sjl.jnidata.Simple");
Constructor<?> constructor = clz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("李四", 99);
Simple simple = (Simple) obj;
} catch (Exception e) {
e.printStackTrace();
}
使用C++:
jclass simpleClz = env->FindClass("com/sjl/jnidata/Simple");
jmethodID constructorMID = env->GetMethodID(simpleClz, "<init>", "(Ljava/lang/String;I)V");//获取Simple的构造器
jstring str = env->NewStringUTF("李四");
jobject object = env->NewObject(simpleClz, constructorMID, str, 99);//object就是Simple对象
从上面发现C++创建对象与java的反射创建对象类似 。
回到正题,介绍jni数据传递,下面所有native方法所在类名为:JniDataTransfer
1.java传递基本类型数据到C++(带参数且有返回值)
java native:
/**
* 测试基本类型
*
* @param b
* @param i
* @param c
* @param d
* @param str
* @return
*/
public static native String testPrimitiveType(byte b, int i, char c, double d, String str);
C++实现:
/*
* 带参数且有返回值
*/
JNIEXPORT jstring JNICALL Java_com_sjl_jnidata_JniDataTransfer_testPrimitiveType
(JNIEnv *env, jclass clz, jbyte b, jint i, jchar c, jdouble d, jstring str) {
int index = (int) (b + i + c + d);
LOGI("index=%d", index);
const char *strContent = env->GetStringUTFChars(str, JNI_FALSE);
env->ReleaseStringUTFChars(str, strContent);
return env->NewStringUTF(strContent);
}
测试示例:
String hello = JniDataTransfer.testPrimitiveType((byte) 0x1, 2, '3', 4.5, "hello world");
此处返回hello world.
2.java传递基本类型数据到C++(无参数且有返回值)
java native:
/**
* 获取当前时间戳
*
* @return
*/
public static native long getCurrentTime();
C++实现:
/**
* 获取当前时间
* @return
*/
long long getCurrentTime() {
struct timeval tv;
gettimeofday(&tv, NULL);
long long ts = (long long) tv.tv_sec * 1000 + tv.tv_usec / 1000;//64位,不加在64位系统会溢出,导致时间不准
return ts;
}
/*
* 无参数且有返回值
*/
JNIEXPORT jlong JNICALL Java_com_sjl_jnidata_JniDataTransfer_getCurrentTime
(JNIEnv *env, jclass clz) {
long long time = getCurrentTime();
return time;
}
测试示例:
long currentTime = JniDataTransfer.getCurrentTime();
输出结果:
3.java传递基本类型数据到C++(用byte[]接收数据,并返回数据长度)
java native:
/**
* 这个实际用的比较多
*
* @param sendData
* @param resultData
* @return
*/
public static native int testBytes(byte[] sendData, byte[] resultData);
C++实现:
/*
*用byte[]接收数据
*/
JNIEXPORT jint JNICALL Java_com_sjl_jnidata_JniDataTransfer_testBytes
(JNIEnv *env, jclass clz, jbyteArray sendData, jbyteArray resultData) {
jbyte *send = env->GetByteArrayElements(sendData, NULL);
int nLength = env->GetArrayLength(sendData);//字节数组长度
jbyte *result = env->GetByteArrayElements(resultData, NULL);
int nLength2 = env->GetArrayLength(resultData);//字节数组长度
if (nLength > nLength2) {
env->ReleaseByteArrayElements(sendData, send, 0);//释放
env->ReleaseByteArrayElements(resultData, result, 0);//释放
return -1;
}
for (int i = 0; i < nLength; i++) {
result[i] = send[i];
}
env->ReleaseByteArrayElements(sendData, send, 0);//释放
env->ReleaseByteArrayElements(resultData, result, 0);//释放
return nLength;
}
测试示例:
byte[] sendData = new String("hello world").getBytes();
byte[] resultData = new byte[32];
int length = JniDataTransfer.testBytes(sendData, resultData);
resultData转成字符串就是hello world
4.java传据递引用数类型到C++(传递简单对象数据)
java native:
/**
* 测试传递简单对象
*
* @param simple
* @return
*/
public static native void testObj(Simple simple);
Simple类:
package com.sjl.jnidata;
/**
* TODO
*
* @author Kelly
* @version 1.0.0
* @filename Simple.java
* @time 2019/7/31 11:32
* @copyright(C) 2019 song
*/
public class Simple {
public Simple() {
}
/**
* native层使用
* @param a
* @param b
*/
public Simple(String a, int b) {
this.a = a;
this.b = b;
}
private String a;
private int b;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
@Override
public String toString() {
return "Simple{" +
"a='" + a + '\'' +
", b=" + b +
'}';
}
}
C++实现:
/*
* 传递简单对象
*/
JNIEXPORT void JNICALL Java_com_sjl_jnidata_JniDataTransfer_testObj
(JNIEnv *env, jclass clz, jobject obj) {
jclass simple_cls = env->GetObjectClass(obj);
if (simple_cls == NULL) {
LOGW("GetObjectClass failed");
return;
}
//获得属性字段
jfieldID field_a = env->GetFieldID(simple_cls, "a", "Ljava/lang/String;");
jfieldID field_b = env->GetFieldID(simple_cls, "b", "I");
//获得属性值
jstring a = (jstring) env->GetObjectField(obj, field_a);
jint b = env->GetIntField(obj, field_b);
const char *c_name = env->GetStringUTFChars(a, NULL);
//释放引用
env->ReleaseStringUTFChars(a, c_name);
LOGI("print simple obj:a=%s,b=%d", c_name, b);
}
测试示例:
Simple simple = new Simple();
simple.setA("李四");
simple.setB(99);
JniDataTransfer.testObj(simple);
输出结果:
5.java传据递引用数类型到C++(传递复杂对象数据)
java native:
/**
* 测试传递复杂对象
*
* @param person
* @return
*/
public static native void testComplexObj(Person person);
Person类:
package com.sjl.jnidata;
import java.util.List;
import java.util.Map;
/**
* TODO
*
* @author Kelly
* @version 1.0.0
* @filename Person.java
* @time 2019/7/31 11:11
* @copyright(C) 2019 song
*/
public class Person {
private String name;//姓名
private int age;//年龄
private List<String> label;//个性标签
private List<Woman> womanList;//女人
private Map<String,Woman> womanMap;//女人映射
public Person() {
}
/***
* native层使用
* @param name
* @param age
* @param label
* @param womanList
* @param womanMap
*/
public Person(String name, int age, List<String> label, List<Woman> womanList, Map<String, Woman> womanMap) {
this.name = name;
this.age = age;
this.label = label;
this.womanList = womanList;
this.womanMap = womanMap;
}
public static class Woman {
private String name;
public Woman() {
}
public Woman(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Woman{" +
"name='" + name + '\'' +
'}';
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getLabel() {
return label;
}
public void setLabel(List<String> label) {
this.label = label;
}
public List<Woman> getWomanList() {
return womanList;
}
public void setWomanList(List<Woman> womanList) {
this.womanList = womanList;
}
public Map<String, Woman> getWomanMap() {
return womanMap;
}
public void setWomanMap(Map<String, Woman> womanMap) {
this.womanMap = womanMap;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", label=" + label +
", womanList=" + womanList +
", womanMap=" + womanMap +
'}';
}
}
C++实现:
/*
*
*
* 传递复杂对象
*/
void JNICALL Java_com_sjl_jnidata_JniDataTransfer_testComplexObj
(JNIEnv *env, jclass clz, jobject obj) {
jclass complex_cls = env->GetObjectClass(obj);
if (complex_cls == NULL) {
LOGW("GetObjectClass failed");
return;
}
//获得属性字段
jfieldID field_name = env->GetFieldID(complex_cls, "name", "Ljava/lang/String;");
jfieldID field_age = env->GetFieldID(complex_cls, "age", "I");
jfieldID field_label = env->GetFieldID(complex_cls, "label", "Ljava/util/List;");
jfieldID field_woman = env->GetFieldID(complex_cls, "womanList", "Ljava/util/List;");
jfieldID field_womanMap = env->GetFieldID(complex_cls, "womanMap", "Ljava/util/Map;");
//特别注意:如果java传过来对象字段没有赋值,Get***Field是空的
//捕获异常
try {
//获得属性值
jstring name = (jstring) env->GetObjectField(obj, field_name);
jint age = env->GetIntField(obj, field_age);
const char *c_name = env->GetStringUTFChars(name, NULL);
//释放引用
env->ReleaseStringUTFChars(name, c_name);
LOGI("=========print complex obj start:");
LOGI("name=%s,age=%d", c_name, age);
//处理label List<String>
jobject labelObj = (jobject) env->GetObjectField(obj, field_label);
checkNull(labelObj, "labelObj is null.");
//获取List class
jclass labelCls = env->GetObjectClass(labelObj);
//获取List的MethodID
jmethodID label_get = env->GetMethodID(labelCls, "get", "(I)Ljava/lang/Object;");
jmethodID label_size = env->GetMethodID(labelCls, "size", "()I");
int labelSize = env->CallIntMethod(labelObj, label_size);
for (int i = 0; i < labelSize; i++) {
jobject label_obj = env->CallObjectMethod(labelObj, label_get, i);
jstring str = (jstring) label_obj;
const char *name = env->GetStringUTFChars(str, NULL);//拿到标签名字
if (name == NULL) {
continue;
}
env->ReleaseStringUTFChars(str, name);
LOGI("print label list 第%d个标签:name=%s", i + 1, name);
}
//处理woman List<Woman>
jobject womanObj = env->GetObjectField(obj, field_woman);
checkNull(womanObj, "womanObj is null.");
//获取List class
jclass womanCls = env->GetObjectClass(womanObj);
//获取List的MethodID
jmethodID woman_get_id = env->GetMethodID(womanCls, "get", "(I)Ljava/lang/Object;");
jmethodID woman_size_id = env->GetMethodID(womanCls, "size", "()I");
int womanSize = env->CallIntMethod(womanObj, woman_size_id);
for (int i = 0; i < womanSize; i++) {
//通过get方法获取
jobject woman_obj = env->CallObjectMethod(womanObj, woman_get_id, i);
jclass woman_cls = env->GetObjectClass(woman_obj);
jmethodID nameId = env->GetMethodID(woman_cls, "getName", "()Ljava/lang/String;");
jstring nameStr = (jstring) env->CallObjectMethod(woman_obj, nameId);
const char *name = env->GetStringUTFChars(nameStr, NULL);//拿到名字
if (name == NULL) {
continue;
}
env->ReleaseStringUTFChars(nameStr, name);
env->DeleteLocalRef(woman_obj);
env->DeleteLocalRef(nameStr);
LOGI("print woman list 第%d个女人:name=%s", i + 1, name);
}
jobject womanMapObj = env->GetObjectField(obj, field_womanMap);
checkNull(womanMapObj, "womanMapObj is null.");
//这样也可以获取
jclass womanMapCls = env->FindClass("java/util/Map");
jmethodID methodID_womanMap = env->GetMethodID(womanMapCls, "size", "()I");
int womanMapSize = env->CallIntMethod(womanMapObj, methodID_womanMap);//map
//使用iterator遍历
if (womanMapSize > 0) {
jmethodID entrySetMID = env->GetMethodID(womanMapCls, "entrySet", "()Ljava/util/Set;");
jobject setObj = env->CallObjectMethod(womanMapObj, entrySetMID);
jclass setClass = env->FindClass("java/util/Set");
jmethodID iteratorMID = env->GetMethodID(setClass, "iterator",
"()Ljava/util/Iterator;");
jobject iteratorObj = env->CallObjectMethod(setObj, iteratorMID);
jclass iteratorClz = env->FindClass("java/util/Iterator");
jmethodID hasNextMID = env->GetMethodID(iteratorClz, "hasNext", "()Z");
jmethodID nextMID = env->GetMethodID(iteratorClz, "next", "()Ljava/lang/Object;");
//内部类使用$符号表示
jclass entryClass = env->FindClass("java/util/Map$Entry");
jmethodID getKeyMID = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
jmethodID getValueMID = env->GetMethodID(entryClass, "getValue",
"()Ljava/lang/Object;");
while (env->CallBooleanMethod(iteratorObj, hasNextMID)) {
jobject entryObj = env->CallObjectMethod(iteratorObj,
nextMID);//这个对应 Map.Entry<String, Person.Woman>
jstring key = (jstring) env->CallObjectMethod(entryObj, getKeyMID);
if (key == NULL) {
continue;
}
const char *keyStr = env->GetStringUTFChars(key, NULL);
jobject woman_obj = env->CallObjectMethod(entryObj, getValueMID);
if (woman_obj == NULL) {
continue;
}
jclass label_cls = env->GetObjectClass(woman_obj);
jmethodID nameId = env->GetMethodID(label_cls, "getName", "()Ljava/lang/String;");
jstring name = (jstring) env->CallObjectMethod(woman_obj, nameId);
const char *nameStr = env->GetStringUTFChars(name, NULL);//拿到名字
// 释放UTF字符串资源
env->ReleaseStringUTFChars(key, keyStr);
env->ReleaseStringUTFChars(name, nameStr);
// 释放JNI局部引用资源
env->DeleteLocalRef(entryObj);
env->DeleteLocalRef(woman_obj);
env->DeleteLocalRef(key);
LOGI("print woman map 我与女人的映射关系:key=%s,name=%s", keyStr, nameStr);
}
}
env->DeleteLocalRef(labelObj);
env->DeleteLocalRef(womanObj);
env->DeleteLocalRef(womanMapObj);
LOGI("=========print complex obj end");
} catch (NullException err) {
LOGE("print complex obj error:%s", err.what());
} catch (exception err) {//其它异常
LOGE("print complex obj error:%s", err.what());
}
}
细心的你可能会发现这与java的反射类似。
测试示例:
Person person = new Person();
person.setName("李四");
person.setAge(99);
List<String> label = Arrays.asList("唱", "跳", "rap", "篮球");
List<Person.Woman> womanList = new ArrayList<>();
Person.Woman woman1 = new Person.Woman();
woman1.setName("恭喜");
Person.Woman woman2 = new Person.Woman();
woman2.setName("发财");
womanList.add(woman1);
womanList.add(woman2);
Map<String, Person.Woman> womanMap = new HashMap<>();
for (Person.Woman woman : womanList) {
womanMap.put(person.getName() + ":" + woman.getName(), woman);
}
person.setLabel(label);
person.setWomanList(womanList);
person.setWomanMap(womanMap);
JniDataTransfer.testComplexObj(person);
输出结果:
6.java调用C++,native层操作java数据(返回简单对象数据)
java native:
/**
* 测试返回简单对象
*
* @return
*/
public static native Simple testGetObj();
C++实现:
/*
*返回简单对象
*/
JNIEXPORT jobject JNICALL Java_com_sjl_jnidata_JniDataTransfer_testGetObj
(JNIEnv *env, jclass clz) {
jclass simpleClz = env->FindClass("com/sjl/jnidata/Simple");
//获得构造函数,函数名为 <init> 返回类型必须为 void 即 V
jmethodID constructorMID = env->GetMethodID(simpleClz, "<init>", "(Ljava/lang/String;I)V");
char buff[100] = {0};
char *pos = buff;
int strLen = sprintf(pos, "%s:", "hello world from c++");
pos += strLen;
sprintf(pos, "%lli", getCurrentTime());
jstring str = env->NewStringUTF(buff);
jobject object = env->NewObject(simpleClz, constructorMID, str, 123456);
env->DeleteLocalRef(str);
return object;
}
测试示例:
Simple simple = JniDataTransfer.testGetObj();
输出结果:
7.java调用C++,native层操作java数据(返回复杂对象数据)
java native:
/**
* 测试返回复杂对象
*
* @return
*/
public static native Person testGetComplexObj();
C++实现:
/*
* 返回复杂对象
*/
JNIEXPORT jobject JNICALL Java_com_sjl_jnidata_JniDataTransfer_testGetComplexObj
(JNIEnv *env, jclass clz) {
jclass personClz = env->FindClass("com/sjl/jnidata/Person");
//获得构造函数,函数名为 <init> 返回类型必须为 void 即 V
//如果不通过构造器赋值,可以选择set赋值
jmethodID constructorMID = env->GetMethodID(personClz, "<init>",
"(Ljava/lang/String;ILjava/util/List;Ljava/util/List;Ljava/util/Map;)V");
jstring p_name = env->NewStringUTF("李四");
jint p_age = 26;
jclass list_cls = env->FindClass("java/util/ArrayList");
jmethodID listConstructorMID = env->GetMethodID(list_cls, "<init>", "()V");
//处理List<Label>
jobject label_list_obj = env->NewObject(list_cls, listConstructorMID);
jmethodID label_list_add = env->GetMethodID(list_cls, "add", "(Ljava/lang/Object;)Z");
env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("唱"));
env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("跳"));
env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("rap"));
env->CallBooleanMethod(label_list_obj, label_list_add, env->NewStringUTF("篮球"));
//处理List<Woman>
jobject woman_list_obj = env->NewObject(list_cls, listConstructorMID);
jmethodID woman_list_add = env->GetMethodID(list_cls, "add", "(Ljava/lang/Object;)Z");
jclass woman_cls = env->FindClass("com/sjl/jnidata/Person$Woman");//获得Woman类
jmethodID woman_constructor = env->GetMethodID(woman_cls, "<init>", "(Ljava/lang/String;)V");
jstring woman1 = env->NewStringUTF("恭喜");
jobject woman_obj1 = env->NewObject(woman_cls, woman_constructor, woman1);
env->CallBooleanMethod(woman_list_obj, woman_list_add, woman_obj1);
jstring woman2 = env->NewStringUTF("发财");
jobject woman_obj2 = env->NewObject(woman_cls, woman_constructor, woman2);
env->CallBooleanMethod(woman_list_obj, woman_list_add, woman_obj2);
//处理Map<String,Woman>
jclass map_cls = env->FindClass("java/util/HashMap");
jmethodID mapConstructorMID = env->GetMethodID(map_cls, "<init>", "()V");
jobject woman_map_obj = env->NewObject(map_cls, mapConstructorMID);
jmethodID woman_map_put = env->GetMethodID(map_cls, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
env->CallObjectMethod(woman_map_obj, woman_map_put, env->NewStringUTF("李四:恭喜"), woman_obj1);
env->CallObjectMethod(woman_map_obj, woman_map_put, env->NewStringUTF("李四:发财"), woman_obj2);
jobject object = env->NewObject(personClz, constructorMID, p_name, p_age, label_list_obj,
woman_list_obj, woman_map_obj);
env->DeleteLocalRef(woman1);
env->DeleteLocalRef(woman2);
env->DeleteLocalRef(label_list_obj);
env->DeleteLocalRef(woman_list_obj);
env->DeleteLocalRef(woman_map_obj);
return object;
}
测试示例:
Person testGetComplexObj = JniDataTransfer.testGetComplexObj();
输出结果:
从上面可以看出C++层解析java对象比构建java对象稍微复杂一些,总之,实现思路和java思想一致。
8.java调用C++,native层操作java数据(C++对java对象变量设置值)
java native:
private String name = "java";
/**
* C++赋值java变量
*/
public native void setFieldValue();
public String getName() {
return name;
}
C++实现:
/*
* C++修改java字段值
*/
JNIEXPORT void JNICALL Java_com_sjl_jnidata_JniDataTransfer_setFieldValue
(JNIEnv *env, jobject obj) {//如果是静态方法,第二个参数是class
jclass cls = env->GetObjectClass(obj);
jfieldID nameFieldId = env->GetFieldID(cls, "name", "Ljava/lang/String;");
char new_name[] = "C++设置java字段值成功";
jstring cName = env->NewStringUTF(new_name);
env->SetObjectField(obj, nameFieldId, cName);//修改对象实例值
}
测试示例:
JniDataTransfer jniDataTransfer = new JniDataTransfer();
String name1 = jniDataTransfer.getName();
jniDataTransfer.setFieldValue();
String name2 = jniDataTransfer.getName();
输出结果:
9.java调用C++,native层操作java数据(C++回调java接口方法)
java native:
private JniDataListener jniDataListener;
/**
* 回调成功还是异常控制标志
*
* @param flag
*/
public native void setFlag(boolean flag);
/**
* C++回调java成功
*/
public void callSuccess(String msg) {
if (jniDataListener != null) {
jniDataListener.onSuccess(msg);
}
}
/**
* C++回调java异常
*/
public void callError(Exception e) {
if (jniDataListener != null) {
jniDataListener.onError(e);
}
}
public interface JniDataListener {
void onSuccess(String msg);
void onError(Exception e);
}
public void setJniDataListener(JniDataListener jniDataListener) {
this.jniDataListener = jniDataListener;
}
C++实现:
/*
* C++回调java
*/
JNIEXPORT void JNICALL Java_com_sjl_jnidata_JniDataTransfer_setFlag
(JNIEnv *env, jobject obj, jboolean b) {
jclass cls = env->GetObjectClass(obj);
jmethodID callSuccessFieldId = env->GetMethodID(cls, "callSuccess", "(Ljava/lang/String;)V");
jmethodID callErrorFieldId = env->GetMethodID(cls, "callError", "(Ljava/lang/Exception;)V");
if (b) {
jstring msg = env->NewStringUTF("来自C++回调,成功");
//回调成功方法,并传递参数
env->CallVoidMethod(obj , callSuccessFieldId , msg);
} else {
jstring msg = env->NewStringUTF("来自C++回调,异常");
jclass exceptionClz = env->FindClass("java/lang/Exception");
jmethodID constructorMID = env->GetMethodID(exceptionClz, "<init>", "(Ljava/lang/String;)V");
jobject object = env->NewObject(exceptionClz, constructorMID, msg);
env->CallVoidMethod(obj, callErrorFieldId , object);
}
}
测试示例:
boolean callbackFlag = true;
public void callbackJava(View view) {
JniDataTransfer jniDataTransfer = new JniDataTransfer();
//设置监听
jniDataTransfer.setJniDataListener(new JniDataTransfer.JniDataListener() {
@Override
public void onSuccess(String msg) {
showMsg("回调成功:" + msg + "");
callbackFlag = false;
}
@Override
public void onError(Exception e) {
showMsg("回调异常:" + e.getMessage());
callbackFlag = true;
}
});
jniDataTransfer.setFlag(callbackFlag);
}
demo地址
https://github.com/kellysong/jni-data-transfer
总结
本文章举例了多种jni数据传递方式,实际开发中涉及业务逻辑,更复杂,开发中需要注意java类包名和方法签名是否正确,避免出现比必要的麻烦,希望这篇文章能够帮助有jni开发需求的人。