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

jni的意思是java本地调用,通过jni可以实现java层代码和其他语言写得代码进行交互。在Cocos2d-x中,如果想要在C++层调用java层的代码,就是通过jni技术。通过调用java层的代码,我们就可以在Android平台下实现一些引擎没有提供给我们的功能,或者做一些其他的功能。比如加个广告,加个分享,调用Android原生的对话框等等吧。Cocos2d-x比较人性化的是为我们封装了jni调用的一些接口,这个类就是JniHelper,我们只需要使用这个类提供给我们的接口就可以完成调用java层代码的功能。

 

JniHelper类的使用:

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

<pre class="cpp" name="code">#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
 
#include "platform/android/jni/JniHelper.h"
#include <jni.h>
 
#endif
 

需要使用的接口如下:

<pre class="cpp" name="code">static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
 

实现上我们只需要使用上面这两个接口,就可以获取java类的所有函数信息了。JNI环境的获取、各种错误处理都已经在这两个接口实现中封装好了。
先上代码,再来依次讲解每个参数的意义和使用方法:

 
<div class="line number2 index1 alt1"><pre class="cpp" name="code">//    typedef struct JniMethodInfo_
//    {
//        JNIEnv *    env;
//        jclass      classID;
//        jmethodID   methodID;
//    } JniMethodInfo;
 

//函数信息结构体
JniMethodInfo minfo;
bool isHave = JniHelper::getStaticMethodInfo(minfo,/*JniMethodInfo的引用*/
                                             "com/omega/MyApp",/*类的路径*/
                                             "getJavaActivity",/*函数名*/
                                             "()Ljava/lang/Object;");/*函数类型简写*/
jobject activityObj;
if (isHave)
{
    //CallStaticObjectMethod调用java函数,并把返回值赋值给activityObj
    activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
}
 

OK,很简单。上面的代码,就是使用JNI在C++中调用java类静态函数的典型使用方法。只有两步:

1. 获取java函数的信息,classid、methodid等等

2. 选择JNIEnv中的接口,进行函数调用

getStaticMethodInfo参数详解:

两个接口的参数一样,意义也相同,详解如下:
JniMethodInfo &methodinfo JniMethodInfo对象的引用,函数执行中会把jniEvn、classid、methodid写入到引用中。
const char *className 类的路径,把类的完整包名写全,用法如以上代码。
const char *methodName 函数名,函数名写上就行了。

const char *paramCode 函数类型简写
这个参数需要单独介绍,它的格式为:(参数)返回类型。
例如:无参数,void返回类型函数,其简写为 ()V
java中的类型对应的简写如下:

 

参数类型参数简写
booleanZ
byteB
charC
shortS
intI
longJ
floatF
doubleD
voidV
ObjectLjava/lang/String; L用/分割类的完整路径
Array[Ljava/lang/String; [签名 [I

 

多参数的函数
如果函数有多个参数,直接把简写并列即可。注意Object与Array型参数简写结尾的分号,示例:
IIII //4个int型参数的函数
ILjava/lang/String;I //整形,string类型,整形组合 (int x, String a, int y)

通过JNIEnv进行函数调用:

JNIEvn有一系列的CallStatic[返回类型]Method、Call[返回类型]Method接口,需要针对不同的函数返回类型选择调用。
[返回类型]以函数返回类型的不同,对应不同的函数名。
例如:
CallStaticVoidMethod ———void
CallVoidMethod ———void
其对应关系如下:

函数名函数返回值类型
Voidvoid
Objectjobject
Booleanjboolean
Bytejbyte
Charjchar
Shortjshort
Intjint
Longjlong
Floatjfloat
Doublejdouble

 

参数传递
调用有参数的java函数时,需要把对应的参数传递进去。需要把参数按顺序加入到classid、methodid后面,并且需要做类型转换。例如:

jint jX = 10;
jint jY = 10;
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jX, jY);

参数类型转换关系如下:

C++类型JAVA类型
booleanjboolean
bytejbyte
charjchar
shortjshort
intjint
longjlong
floatjfloat
doublejdouble
Objectjobject
Classjclass
Stringjstring
Object[]jobjectArray
boolean[]jbooleanArray
byte[]jbyteArray
char[]jcharArray
short[]jshortArray
int[]jintArray
long[]jlongArray
float[]jfloatArray
double[]jdoubleArray

 

string类型的转换
实际上我们最常用的参数类型,主要是内建的数据类型、string字符串类型。数据类型可以直接转为j类型,但是string类型需要做如下处理:

jstring jmsg = minfo.env->NewStringUTF("http://www.baidu.com");
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jmsg);


非静态函数的调用:

非静态函数的调用与静态函数的调用类型,但是需要通过一个静态函数获取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定义的类非静态函数是否存在,返回bool
    bool 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了,要传入一个对象,告诉它调用的是哪个对象的方法,所以为了有这么一个对象,我们就得先调用一个静态的方法来返回这个对象,然后用这个对象作为参数调用非静态函数。




 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值