首页 > Personal > cocos2d-x > cocos2d-x: jni c++ java相互通信
2013
12-24

cocos2d-x: jni c++ java相互通信

昨天为了在android上添加一个页面显示OAuth2认证,研究了下jni,让java和c++之间可以相互调用,遇到和很多坑,记录一下留作备忘。jni的帮助文档可以参考jni完全手册,android的java接口api可以在android官网找到,java的api可以在Oracle官网找到。

c++调用java,需要包含头文件
#include “platform/android/jni/JniHelper.h”

使用JniHelper来获取相应接口
JniMethodInfo info;
bool have_info = JniHelper::getStaticMethodInfo(info, “com/domain/pack/filename”, “api_name”, “()Lcom/domain/pack/filename;”);
bool have_info = JniHelper::getMethodInfo(info, “com/domain/pack/filename”, “api_name”, “()V;”);
可以获取static和成员函数,第二个参数是包名加文件名,第三个参数是接口名字,第四个接口是参数类型和返回类型。类型的话可以使用缩写
Z boolean
B byte
C char
S short
I int
J long
F float
D double
[ 表示数组
还有类名,如String就是”Ljava/lang/String;”,比如”(IFLjava/lang/Object;)[Ljava/util/String;”,一个int参数,一个float参数,一个Object参数,返回String数组。
JNIEnv*是线程相关的,要获取当前线程的env需要先获取JVM*,再获得当前线程的JNIEnv,JniHelper已经封装保存了jvm,然后实现了getEnv接口,所以可以直接使用相应接口。具体可用的接口可以自己看JniHelper.h。

jobject obj = info.env->CallStaticObjectMethod(info.classID, info.methodID, 参数…);
info.env->CallVoidMethod(obj, info.methodID, 参数…);
调用函数有static和成员函数调用,区别就是第一个参数一个是类ID一个实例object,第二个参数是函数id,后面的参数就是函数的参数了。调用的这个函数名决定了返回值的类型,如
CallVoidMethod 无返回值
CallIntMethod  返回Int
CallObjectMethod  返回Object,除了基础类型都可以使用返回object
还有些其他常用的函数,如
GetObjectClass(obj) 获得object的类型
FindClass(classname) 获得类型
GetArrayLength(array) 获得array长度
GetObjectArrayElement(array, index) 获得array的某个值
GetStringUTFChars(jstring, NULL) 得到const char*
ReleaseStringUTFChars(jstring, const char*) 释放之前取得饿const char*
还有一些c++中常用的java基本类型
boolean jboolean C/C++8位整型
byte jbyte C/C++带符号的8位整型
char jchar C/C++无符号的16位整型
short jshort C/C++带符号的16位整型
int jint C/C++带符号的32位整型
long jlong C/C++带符号的64位整型e
float jfloat C/C++32位浮点型
double jdouble C/C++64位浮点型
Object jobject 任何Java对象,或者没有对应java类型的对象
Class jclass Class对象
String jstring 字符串对象
Object[] jobjectArray 任何对象的数组
boolean[] jbooleanArray 布尔型数组
byte[] jbyteArray 比特型数组
char[] jcharArray 字符型数组
short[] jshortArray 短整型数组
int[] jintArray 整型数组
long[] jlongArray 长整型数组
float[] jfloatArray 浮点型数组
double[] jdoubleArray 双浮点型数组

如果java调用c++,首先一定要注意java的包名和文件名一定不要包含‘_’,因为java是通过c++的函数名来找到相应函数的而函数名是这样
JNIEXPORT void JNICALL Java_com_domain_pack_filename_apiname(JNIEnv* env, jobject self, jobject obj)
Java开头,然后跟包名、文件名、函数名,中间使用‘_’分割,中间多了‘_’java可能就无法识别了,这个问题困扰了我好久。
调用的函数和上面的一个一样,JNIEnv的话使用参数中传来的env,c++的调用方法是env->,c的调用方法是(*env)->。记住一条,如果不知道类型是什么的话,尽量使用”Ljava/lang/Object;”。c++中函数要在extern “C” {}之中定义。
java这边需要定义函数,用native声明
private static native void apiname(Object obj);
需要的java接口可以写在cocos2d-x自动生成的java文件中,在proj.android的src下。
需要注意的是,cocos2d-x中使用jni在java中调回c++,因为android的关系并不确定当前是在哪个线程,所以如果直接处理会产生任何可能的奇怪问题,解决的办法是,你的C++处理类从CCNode派生,然后在回调函数里把需要的数据先暂时保存下来,再调用处理类的scheduleOnce等一小段时间后在主线程中执行。

因为没有找到很好的方法调试,所以jni的代码写起来非常头疼,每次编译完上传到手机,运行,有问题就会崩溃,也不知道哪出了问题,只用一点一点的试,真的是非常麻烦。也不知道有没有好的方法。

最后编辑:
作者:wy182000
这个作者貌似有点懒,什么都没有留下。

留下一个回复