note
从java层传对象到jni层
1.首先要在java层建立一个类,然后在jni层要有对应的结构体,名称最好一致,这样使用起来比较方便;
2.这次我只使用类java传对象进去jni层,没有试从jni层返回对象给java层
3.java层就很好做了,直接在形参那里传一个对象进去;
4.在jni层,对应的形参形式为jobject;
直接上代码吧:
java对象类
public class CooInfo {
public byte[] mac=new byte[8];
public byte channel;
public byte[] app_version=new byte[32];
public byte[] coo_version=new byte[32];
public byte[] stack_version=new byte[32];
public byte txpower;
public String str;
}
c层的结构体:
typedef struct{
unsigned char mac[8];
unsigned char channel;
char app_version[32];
char coo_version[32];
char stack_version[32];
unsigned char txpower;
char str[255];
}coo_info_t;
java层的函数:
public native String getCooInfo(CooInfo info);
c层的具体实现函数
JNIEXPORT jstring JNICALL Java_com_example_bin_testndk_ZigbeeUtil_getCooInfo
(JNIEnv * env, jobject obj, jobject cooinfo) {
coo_info_t revdata;
jclass jcInfo = (*env)->FindClass(env,"com/example/bin/testndk/CooInfo");
jfieldID jfi = (*env)->GetFieldID(env,jcInfo, "channel", "B");
revdata.channel = (*env)->GetByteField(env,cooinfo, jfi);
/*数组*/
jfieldID jfa =(*env)->GetFieldID(env,jcInfo, "app_version", "[B");
jbyteArray ja = (jbyteArray)(*env)->GetObjectField(env,cooinfo, jfa);//获取数组
int nArrLen = (*env)->GetArrayLength(env,ja);//获取数组长度
char *chArr = (char*)(*env)->GetByteArrayElements(env,ja, 0);//获取数组单个数据的指针
memcpy(revdata.app_version, chArr, nArrLen);//把单个数据逐个拷贝到目标数组
return (*env)->NewStringUTF(env,"test");
/*string*/
//String str
jfieldID jfs = env->GetFieldID(jcInfo, "str", "Ljava/lang/String;");
//获取实例的变量str的值
jstring jstr = (jstring)env->GetObjectField(jobj, jfs);
const char* pszStr = (char*)env->GetStringUTFChars(jstr, 0);
strcpy(revdata.str, pszStr);
}
解析:
http://blog.csdn.net/lintax/article/details/51759270
*
以获取类中一个整型值为例:
//获取Java中的实例类ParamInfo
jclass jcInfo = env->FindClass(“com/example/helloworld/ParamInfo”);
-
获取类中一个整型变量intValue的定义
jfieldID jfi = env->GetFieldID(jcInfo, “intValue”, “I”);
-
获取实例的变量intValue的值,其中jobj即参数中携带数据的对象:
paramInfo.intValue = env->GetIntField(jobj, jfi);
-
注意 GetFieldID()的第3个参数的取值,是数据类型的签名标识,具体取值见下面表格:
Java类型 符号
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
object对象 LClassName; L类名;
Arrays [array-type [数组类型
methods方法 (argument-types)return-type (参数类型)返回类型
string Ljava/lang/String;
从jni层到java层
// C结构体类型向Java 类转换
JNIEXPORT jobject JNICALL Java_com_example_helloworld_JniClient_getInfo
(JNIEnv *env, jobject jo)
{
char chTmp[] = "Test array";
int nTmpLen = strlen(chTmp);
//将C结构体转换成Java类
ParamInfo paramInfo;
memset(paramInfo.array, 0, sizeof(paramInfo.array));
memcpy(paramInfo.array, chTmp, strlen(chTmp));
paramInfo.boolValue = true;
paramInfo.charValue = 'B';
paramInfo.doubleValue = 2.7182;
paramInfo.intValue = 8;
strcpy(paramInfo.str, "Hello from JNI");
LOGI("paramInfo.array=%s, paramInfo.boolValue=%d, paramInfo.charValue=%c\n",
paramInfo.array, paramInfo.boolValue, paramInfo.charValue);
//获取Java中的实例类
jclass jcInfo = env->FindClass("com/example/helloworld/ParamInfo");
//获取类中每一个变量的定义
//boolean boolValue
jfieldID jfb = env->GetFieldID(jcInfo, "boolValue", "Z");
//char charValue
jfieldID jfc = env->GetFieldID(jcInfo, "charValue", "C");
//double doubleValue
jfieldID jfd = env->GetFieldID(jcInfo, "doubleValue", "D");
//int intValue
jfieldID jfi = env->GetFieldID(jcInfo, "intValue", "I");
//byte[] array
jfieldID jfa = env->GetFieldID(jcInfo, "array", "[B");
//String str
jfieldID jfs = env->GetFieldID(jcInfo, "str", "Ljava/lang/String;");
//创建新的对象
jobject joInfo = env->AllocObject(jcInfo);
//给类成员赋值
env->SetBooleanField(joInfo, jfb, paramInfo.boolValue);
env->SetCharField(joInfo, jfc, (jchar)paramInfo.charValue);
env->SetDoubleField(joInfo, jfd, paramInfo.doubleValue);
env->SetIntField(joInfo, jfi, paramInfo.intValue);
//数组赋值
jbyteArray jarr = env->NewByteArray(nTmpLen);
jbyte *jby = env->GetByteArrayElements(jarr, 0);
memcpy(jby, paramInfo.array, nTmpLen);
env->SetByteArrayRegion(jarr, 0, nTmpLen, jby);
env->SetObjectField(joInfo, jfa, jarr);
//字符串赋值
jstring jstrTmp = env->NewStringUTF(paramInfo.str);
env->SetObjectField(joInfo, jfs, jstrTmp);
return joInfo;
}
Java 方法映射到C中的签名
如:jmethodID md = (*env)->GetMethodID(env,class_CommonMethod,“print”,"(ILjava/lang/String;)V");
观察下面四个方法对应的签名
public void test(){} ()V
public void test1(int i){} (I)V
public int test2(){ return 1;} ()I
public int test3(int i) { return i;} (I)I
由此可以看出:签名是由两部分组成,"()" 里面代表的是方法的参数,后面外面的部分代表的是该方法的返回值
关于这两部分的定义其实又有分 基本数据类型 和 引用数据类型
基本数据类型对应关系如表:
引用数据类型:比较麻烦点,以“L”开头,以“;”结束,中间对应的是该类型的路径
如:String : Ljava/lang/String;
Object: Ljava/lang/Object;
自定义类 Cat 对应 package com.duicky;
Cat : Lcom/duicky/Cat;
数组表示: 数组表示的时候以“[” 为标志,一个“[”表示一维数组
如:int [] :[I
Long[][] : [[J
Object[][][] : [[[Ljava/lang/Object;
假如要返回一个java层的对象类的话就该这么写:
jclass jcInfo = (*env)->FindClass(env,"com/example/bin/testndk/NewDevice");
jfieldID jfmac = (*env)->GetFieldID(env,jcInfo, "mac", "[B");
jobject joInfo = (*env)->AllocObject(env,jcInfo);//新建返回的对象
//获取Java层被回调的函数 onNativeCallback
jmethodID newdeviceCallback = (*env)->GetMethodID(env,javaClass,"onNewDeviceCallback","(Lcom/example/bin/testndk/NewDevice;)V");//签名是由两部分组成,"()" 里面代表的是方法的参数,后面外面的部分代表的是该方法的返回值
(*env)->CallVoidMethod(env,newdeviceObj,newdeviceCallback,joInfo);
CJSON的使用
因为返回结构体对应的对象太麻烦了,所以呀讨论决定在c代码层处理,把结构体转成json数据返回字符串给java层处理,这样更加高效;
所以这里就用到了c语言的json库,也就是CJSON,下面我们讨论一下CJSON的使用方法;
这个工程我主要用到了结构体打包json的功能,解析json