Cocos2d-x利用jni调用java层代码

来源:互联网 发布:unity3d玻璃材质包 编辑:程序博客网 时间:2024/03/28 20:07

转载自:http://www.zaojiahua.com/using-jni.html


jni的意思是Java本地调用,通过jni可以实现java层代码和其他语言写得代码进行交互。在cocos2d-x中,如果想要在c++层调用java层的代码,就是通过jni技术。通过调用java层的代码,我们就可以在Android平台下实现一些引擎没有提供给我们的功能,或者做一些其他的功能。比如加个广告,加个分享,调用Android原生的对话框等等吧。Cocos2d-x比较人性化的是为我们封装了jni调用的一些接口,这个类就是JniHelper,我们只需要使用这个类提供给我们的接口就可以完成调用java层代码的功能。先说一下这个类的位置,因为自己在找的时候有点犯二,所以特意说明一下。在3.0和3.1以上的引擎版本中,这个类的位置分别如下。

Cocos2d-x利用jni调用java层代码Cocos2d-x利用jni调用java层代码

3.1以后引擎把原来cocos目录下的包含各个功能的文件夹都放到了cocos目录下,我个人认为这样的放法还是比较好的。就是引擎老改目录,希望以后不要放来放去了。最主要的当然是看看怎么使用JniHelper这个类了。

首先使用之前要包含头文件,写法如下,记住要加上条件编译,这个东西是Android平台下才用到。

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)#include "platform/android/jni/JniHelper.h"#include <jni.h>#endif

接着通过一小段代码来说明一下这个类的用法。

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)    //  typedef struct JniMethodInfo_    //  {    //      JNIEnv *    env;    //      jclass      classID;    //      jmethodID   methodID;    //  } JniMethodInfo;    JniMethodInfo info;    //getStaticMethodInfo判断java定义的静态函数是否存在,返回bool    bool ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/TestJni","func1","()V");    if(ret)    {        log("call void func1() succeed");        //传入类ID和方法ID,小心方法名写错,第一个字母是大写        info.env->CallStaticVoidMethod(info.classID,info.methodID);    }#endif

大家书写代码的时候同样需要将代码使用条件编译写到里面,JniMethodInfo是一个结构体,这个结构体的定义就是代码中注释掉的地方,然后使用JniHelper调用了静态函数getStaticMethodInfo,从它的名字就知道这个函数的作用了,就是获得java层中静态函数的信息,这个信息保存在什么地方呢,当然是JniMethodInfo中了,我们要获取哪个类的哪个函数呢,第二个参数和第三个参数就是告诉JniHelper我们要获取的是哪个函数的信息了,第二个参数是类文件的包名路径,我在org/cocos2dx/cpp这个路径下新建了一个类,叫做TestJni。其实前面的路径就是一个包名,这里使用的时候用/代替.。org的路径当然就是我新建的这个工程的Android平台目录了。一会我要将这个项目打包然后测试一下,在eclipse下看看输出。第三个参数当然就是方法名字了,第四个参数是需要注意的一个,有人把它叫做签名,其实就是你要调用的java层函数的返回值和参数的类型说明。它把调用函数的参数写到前面的括号中,返回值跟在括号的后边,和我们平时书写函数的时候正好相反了。那那个V是什么东西呢,这个大写字母就是对应的一个类型,如果是void类型,那么就用一个V来代替,如果是一个int类型,那么就用一个I代替,是不是很简单,那其他的类型呢,如图所示。

Cocos2d-x利用jni调用java层代码Cocos2d-x利用jni调用java层代码

放了俩张表,用得时候查就好了,关于这个参数其他的细节问题待会讨论。整个函数的返回值是一个bool类型,什么意思不用说了吧。当这个函数的信息存在的时候我们就进入到了if中了,然后我使用了info结构体的第一个变量来调用了函数CallStaticVoidMethod,这个函数可真是需要说一说。首先它的调用者就是保存函数信息的结构体JniMethodInfo的第一个成员变量env,这货是什么东西不用管,用就好了。然后这个函数的第一个字母是大写,这一点要小心,Call后边如果跟Static代表的就是我要调用的是一个静态的函数,如果没有那就不是静态的,不是静态的函数,我们使用JniHelper获取信息的时候用得就是getMethodInfo这个函数。然后Void代表的是函数的返回值,来看我们的例子,我调用的函数func1是一个无参无返回值的函数,这个看什么地方,当然java代码我接着会向你展示,但是你可以直接看getStaticMethodInfo这个函数的第四个参数啊。这里的这个void代表的是函数的返回值类型,所以如果调用的是返回值为int的java函数,那就是CallStaticIntMethod了。里边的参数就是结构体info的第二个和第三个成员变量了,代表的是类ID和函数ID。这样的话基本的用法就说清楚了,接着就是TestJni中得代码了,我把要调用到得函数都写了出来。

package org.cocos2dx.cpp;import android.util.Log;public class TestJni{    public static void func1()    {        Log.e("xiaota","java:func1,called succeed!");    }    public static int func2()    {        return 3838438;    }    public static String func3(int i)    {        String str = "get int value:"+i;        Log.e("xiaota",str);        return str;    }    public static String func4(String str)    {        Log.e("xiaota",str);        return str;    }    public static int func5(int a,int b)    {        int c = a+b;        Log.e("xiaota","func5");        return c;    }}

然后打包到Android平台,我们使用USB连接上电脑,打开eclipse,进行调试,看看信息输出了没有。

Cocos2d-x利用jni调用java层代码

好了,这样的话就把这个流程都说明白了,下面我们看一些细节的地方。

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)    log("android platform!");    //  typedef struct JniMethodInfo_    //  {    //      JNIEnv *    env;    //      jclass      classID;    //      jmethodID   methodID;    //  } JniMethodInfo;    JniMethodInfo info;    //getStaticMethodInfo判断java定义的静态函数是否存在,返回bool    bool ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/TestJni","func1","()V");    if(ret)    {        log("call void func1() succeed");        //传入类ID和方法ID,小心方法名写错,第一个字母是大写        info.env->CallStaticVoidMethod(info.classID,info.methodID);    }    //调用的函数有返回值    ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/TestJni","func2","()I");    if(ret)    {        log("call int func2() succeed");        //返回的int值,用jint类型来接收        jint iret = info.env->CallStaticIntMethod(info.classID,info.methodID);        log("func2的返回值是%d",iret);    }    //调用的函数有参数有返回值,这里有坑,注意Ljava/lang/String;后边的;    ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/TestJni","func3","(I)Ljava/lang/String;");    if(ret)    {        log("call int func3(int) succeed");        //java层的类类型对应的是jobject,把需要传递的参数写到调用函数的后边        jobject jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID,1438);    }    //参数和返回值都是类类型    ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/TestJni","func4","(Ljava/lang/String;)Ljava/lang/String;");    if(ret)    {        log("call string func4(string) succeed");        jobject para = info.env->NewStringUTF("haha");        jstring jstr = (jstring)info.env->CallStaticObjectMethod(info.classID,info.methodID,para);        //使用jstring2string函数将返回的jstring类型的值转化为c++中的string类型        std::string text = JniHelper::jstring2string(jstr);        log("%s",text.c_str());    }    //如果函数需要的参数是俩个或者是多个,可以采用如下的写法    ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/TestJni","func5","(II)I");    if(ret)    {        log("call int func5(int a,int b) succeed");        jint iret = info.env->CallStaticIntMethod(info.classID,info.methodID,1,2);        log("return value is %d",iret);    }#endif

上边的代码主要还是那俩个函数调用的说明,getStaticMethodInfo的第四个参数如果是类类型,注意要使用的签名,后边的分号也要加,如果参数有多个,直接连起来书写就可以了。使用CallStaticMethod调用的时候注意一下参数和返回值的类型,传递参数的时候直接写到函数的后边,但是参数类型要正确,返回值使用对应的类型来接受,这个类型就是前面加一个j,比如java层返回的类型是int,那接受的类型就是jint,java层返回object,接受类型就是jobject。

Cocos2d-x利用jni调用java层代码

以上是调用java的静态函数,接下来是非静态函数的调用。我将c++的代码和java的代码都贴出来。

  • C++
JniMethodInfo info;bool ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/TestJniHelper","getObj","()Ljava/lang/Object;");//先获得类的对象,然后用这个对象去调用它的非静态函数jobject jobj;if(ret){    log("call static method");    jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID);}//getMethodInfo判断java定义的类非静态函数是否存在,返回boolbool re = JniHelper::getMethodInfo(info,"org/cocos2dx/cpp/TestJniHelper","func","()V");if(re){    log("call no-static method");    //非静态函数调用的时候,需要的是对象,所以与静态函数调用的第一个参数不同    info.env->CallVoidMethod(jobj,info.methodID);}

  • java
package org.cocos2dx.cpp;import android.util.Log;public class TestJniHelper{    private static TestJniHelper instance = new TestJniHelper();    public static Object getObj()    {        return instance;    }    public void func()    {        Log.e("xiaota","func is called");    }}

因为调用的是非静态的函数,所以我们使用CallVoidMethod的时候就不能传入类ID了,要传入一个对象,告诉它调用的是哪个对象的方法,所以为了有这么一个对象,我们就得先调用一个静态的方法来返回这个对象,然后用这个对象作为参数调用非静态函数。好了,关于Jni的基本用法就是这样了,只是本人的一点拙见,没有了解过的可以看看,如果是大神就绕路吧。

Cocos2d-x利用jni调用java层代码

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 美的电饭煲e一传感器也没坏怎么办 美的电饭煲不工作显示C3怎么办 美的电饭煲啪一声响不工作了怎么办 误给宝宝吃了坏的饭怎么办 鼠标没反应键盘指示灯不亮怎么办 新买变频冰箱风机声音大怎么办 三星手机玩王者荣耀一直闪退怎么办 刚申请的阿里大宝卡不想要了怎么办 国美刚买不到一个月电视坏了怎么办 交保险后保险公司不给开收据怎么办 收据白联作废红联丢失怎么办 收据作废客户联给客户了怎么办 宜家买的床和床垫搬家了怎么办 科龙空调开机后自己关机怎么办 以旧换新旧的没给商家 报案怎么办 想换新手机但是旧的没坏怎么办 从苏宁易购买的电视坏了怎么办 苏宁易购服务站买的电视坏了怎么办 用微信登陆京东账号退不出来怎么办 微信账号密码手机号都忘记了怎么办 我的手机号京东被别人绑定了怎么办 京东之前绑定的手机号不用了怎么办 京东退货钱未到银行卡账号里怎么办 京东身份证绑的手机号不用了怎么办 海尔冰箱要退货箱子扔了怎么办 海尔冰箱门变形关不严没吸力怎么办 长时间不用的手机忘记密码怎么办啊 微信忘记密码手机号又不用了怎么办 华为账号换了手机密码忘记了怎么办 用u盘制作音响喊话内容怎么办 新三板公司退市了小股东怎么办? 新三板公司退市股东股票怎么办 利群收购乐天玛特超市卡怎么办 买房过户夫妻一方是外省户口怎么办 欠了国美金融贷款没钱还会怎么办? 国企员工涨工资不在编的员工怎么办 装车牌照的螺丝孔小了怎么办 北京摇号之后中签和未中签怎么办 拉轿车的大车出车祸车怎么办 美图m6手机忘记锁屏密码怎么办 微信验证码登录收不到验证码怎么办