jni note

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值