Cocos2d-x3.3RC0通过JNI实现Java与C++互调

一、JNI

JNI( Java Native Interface):Java的本地调用。本文通过JNI在Cocos2d-x3.3RC0中完成Java与C++的互调。具体实现以下两个功

能:(1)通过Android sdk的API得到应用程序的包名,并传递给C++层函数。(2)通过C++函数调用Android的Java层函数,显示一个对话框。点击按钮退出程序。

详细知识见:http://blog.csdn.net/yuxikuo_1/article/details/39577257。其中最重要的是JNIEnv,这是一个C结构体。封装了许多

常用函数:具体如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

struct _JNIEnv {

    /* do not rename this; it does not seem to be entirely opaque */

    conststruct JNINativeInterface* functions;

  

#ifdefined(__cplusplus)

  

    jint GetVersion()

    {returnfunctions->GetVersion(this); }

  

    jclass DefineClass(constchar *name, jobject loader, constjbyte* buf,

        jsize bufLen)

    {returnfunctions->DefineClass(this, name, loader, buf, bufLen); }

  

    jclass FindClass(constchar* name)

    {returnfunctions->FindClass(this, name); }

// 这里省略其他函数...

  

}

Cocos2d-x对jni的操作进行了封装,提供JniHelper类解决Java与C++的通信。
下面介绍两个常用的函数:

1、getStaticMethodInfo:

用来判断java类中静态函数是否存在,初始化结构体JniMethodInfo。该结构体封装了JNIEnv*和java.lang.Class、函数ID。这样可以使用JNIEnv*调用CallStaticXXXMethod(jclass clazz,jmethodID methodID,...)和CallXXXMethod(jobject obj,jmethodID methodID,...)等常用函数,其中XXX代表函数返回值类型,如void、int等。如下代码:参数1:JniMethodInfo,参数2:类的绝对路径,该路径为:proj.android/src/下的目录,例如引擎模板工程下的路径为:src/org/cocos2dx/cpp/XXX。XXX为cpp下的java文件。记住路径中不用加.java后缀,因为路径使用的是类名。参数3:函数名,参数4:函数签名,具体规则见3类型签名

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

JniMethodInfo info; 

bool ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/AppActivity","getObj","()Ljava/lang/Object;"); 

jobject jobj; 

if(ret) 

    log("call void getObj() succeed"); 

    jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID); 

   

bool re = JniHelper::getMethodInfo(info,"org/cocos2dx/cpp/AppActivity","func1","()V"); 

if(re) 

    log("call func1 succeed"); 

    info.env->CallVoidMethod(jobj,info.methodID); 

}

2、getMethodInfo:用于调用Java类的非静态函数

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) 

    JniMethodInfo info; 

    //判断org/cocos2dx/cpp/AppActivity.java中是否存在getObj静态函数 

    bool ret = JniHelper::getStaticMethodInfo(info,"org/cocos2dx/cpp/AppActivity","getObj","()Ljava/lang/Object;"); 

    jobject jobj;//用于存放返回的对象 

    if(ret) 

    

        log("call void getObj() succeed"); 

        jobj = info.env->CallStaticObjectMethod(info.classID,info.methodID);//调用getObj函数,返回一个对象 

    

    //判断org/cocos2dx/cpp/AppActivity.java中是否存在func1非静态函数 

    bool re = JniHelper::getMethodInfo(info,"org/cocos2dx/cpp/AppActivity","func1","()V"); 

    if(re) 

    

        log("call func1 succeed"); 

        info.env->CallVoidMethod(jobj,info.methodID);//通过返回的对象调用非静态函数 

    

       

#endif

 

3、类型签名

 

类型签名Java类型
Zboolean
Bbyte
Cchar
Sshort
Iint
Jlong
Ffloat
Ddouble
L full-qualified-class;完全限定的类
[ typetype[ ]
(arg-types) ret-type方法类型


如java方法:long f(int n,String s,int[] arr); 类型签名为:(ILjava/lang/String;[I)J。注意L后的分号,[是半开的,要与类型签名完全一致。

二、具体步骤

1、创建Cocos2d-x3.3RC0工程

这个不做过多介绍,既然研究到Jni了,相比都不是太菜鸟了。

2、ADT与XCode分别导入工程

3、Xcode的Class目录下添加JniTest类

\
JniTest.h代码如下:JniTest.cpp暂时没有代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#ifndef __JniDemo__JniTest__

#define __JniDemo__JniTest__

 

#include"cocos2d.h"

USING_NS_CC;

 

voidsetPackageName(constchar* packageName)//从Java层传过来的包名在此处打印出来

{

    log("packageName = %s",packageName);

}

 

voidexitApp()//Java层调用C++层的该函数,关闭程序。

{

    Director::getInstance()->end();

}

 

然后在HelloWorldScene.cpp中包含如下头文件,并在menuCloseCallback中添加如下代码:

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//头文件包含,判断平台

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

#include"../proj.android/jni/hellocpp/test.h"//一定是相对路径

#endif

 

 

//调用C++调用Java层代码

voidHelloWorld::menuCloseCallback(Ref* pSender)

{

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

    showTipDialog("exit","Exit,Really Go?");

#endif

     

#if(CC_TARGET_PLATFORM == CC_PLATFORM_IOS)

    exit(0);

#endif

}

4、Jni层代码

打开ADT工程目录下的jni/hellocpp/列表,在hellocpp下添加c++类,test.cpp和test.h。代码如下:一定包含extern "C"

?

1

2

3

4

5

6

7

8

//test.h

#ifndef TEST_H_

#define TEST_H_

extern"C"

{

    voidshowTipDialog(constchar* title,constchar* msg);

}

#endif

test.cpp代码如下:

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

//test.cpp

#include"test.h"

#include"cocos2d.h"

#include"platform/android/jni/JniHelper.h"//引擎提供的JniHelper类

#include"../../../Classes/JniTest.h"//相对路径,上一步在Xcode中创建的类

#include <jni.h>

 

#define CLASS_NAME "org/cocos2dx/cpp/JniTestHelper"//这步的路径即是上面红线的路径,很重要

using namespace cocos2d;

extern"C"

{<span style="white-space:pre"> </span><span style="color:#cc0000;">//下面的函数通过Jni调用Java层的函数。

</span>voidshowTipDialog(constchar* title,constchar* msg)//在HelloWorldScene中调用该处的此函数,此函数在通过Jni传到Java层

    {<span style="white-space:pre">                     </span>//调用Java层JniTestHelper.java中的showTipDialog函数

        JniMethodInfo t;

        if(JniHelper::getStaticMethodInfo(t,CLASS_NAME,"showTipDialog","(Ljava/lang/String;Ljava/lang/String;)V"))//该函数的意思就是,寻找org/cocos2dx/cpp/JniTestHelper类中有无静态函数showTipDialog,<span style="color:#cc0000;">暂时还没有放出JniTestHelper的代码,稍后。</span>

        {

            jstring jTitle = t.env->NewStringUTF(title);

            jstring jMsg   = t.env->NewStringUTF(msg);

            t.env->CallStaticVoidMethod(t.classID,t.methodID,jTitle,jMsg);

            t.env->DeleteLocalRef(jTitle);

            t.env->DeleteLocalRef(jMsg);

        }

    }<span style="color:#cc0000;">//以下两个函数,是通过Jni调用C++层的setPackageName和exitApp,Java层的两个函数在JniTestHelper中定义,参数通过JNIEnv传入</span>

    voidJava_org_cocos2dx_cpp_JniTestHelper_setPackageName(JNIEnv* env,jobject thiz,jstring packageName)

    {

        constchar* pkgName = env->GetStringUTFChars(packageName,NULL);

        setPackageName(pkgName);//C++层代码

        env->ReleaseStringUTFChars(packageName,pkgName);

    }

    voidJava_org_cocos2dx_cpp_JniTestHelper_exitApp(JNIEnv* env,jobject thiz)

    {

        exitApp();//C++层代码

    }

}</jni.h>

5、Java层函数

在ADT工程目录src/org.cocos2dx.cpp的目录下添加java类,JniTestHelper.java

1)JniTestHelper.java代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

packageorg.cocos2dx.cpp;

importorg.cocos2dx.lib.Cocos2dxHandler.DialogMessage;

importandroid.os.Handler;

importandroid.os.Message;

 

publicclass JniTestHelper {

    privatestatic Handler mHandler;//Java的Handler传递消息

    publicstatic void init(Handler handler) {

        JniTestHelper.mHandler = handler;

    }

     

    publicstatic native void setPackageName(String packageName);//声明两个静态nativa函数,在Jni中test.cpp中定义,调用C++层的对应函数。

     

    publicstatic native void exitApp();

     

    privatestatic void showTipDialog(finalString title,finalString text)

    {

        Message msg = mHandler.obtainMessage();//接受消息

        msg.what = AppActivity.SHOW_DIALOG;

        DialogMessage dm = newDialogMessage(title, text);//重点是这一步,之前的教程自己定的数据结构,而新版本的Cocos的

        dm.titile = title;<span style="white-space:pre">                </span>//Jni库为我们提供了DialogMessage这个数据结构类。所以不用自定义

        dm.message = text;

        msg.obj = dm;

        msg.sendToTarget();

    }

}

2)AppActivity.java代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

packageorg.cocos2dx.cpp;

 

importorg.cocos2dx.lib.Cocos2dxActivity;

importorg.cocos2dx.lib.Cocos2dxGLSurfaceView;

importorg.cocos2dx.lib.Cocos2dxHandler.DialogMessage;

 

importandroid.app.AlertDialog;

importandroid.content.DialogInterface;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.os.Message;

 

publicclass AppActivity extendsCocos2dxActivity{

    publicstatic final int SHOW_DIALOG = 0x0001;

    protectedvoid onCreate(Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        JniTestHelper.init(mHandler);//将下面定义的Handler对象,初始化JniTestHelper中的Handler对象。

        JniTestHelper.setPackageName(this.getPackageName());

    }

     

    publicCocos2dxGLSurfaceView onCreateView(){

        Cocos2dxGLSurfaceView glSurfaceView = newCocos2dxGLSurfaceView(this);

        glSurfaceView.setEGLConfigChooser(5,6,5,0,16,8);

        returnglSurfaceView;

    }

    static{

        System.loadLibrary("cocos2dcpp");

    }

     

    privateHandler mHandler = newHandler()

    {

        publicvoid handleMessage(Message msg) {

             

            switch(msg.what)

            {

            caseSHOW_DIALOG://设置提示框

                DialogMessage dm = (DialogMessage)msg.obj;

                newAlertDialog.Builder(AppActivity.this)

                .setTitle(dm.titile)

                .setMessage(dm.message).setNegativeButton("cancle",newDialogInterface.OnClickListener() {

                     

                    @Override

                    publicvoid onClick(DialogInterface arg0, intarg1) {

                        // TODO Auto-generated method stub

                        arg0.dismiss();

                    }

                })

                .setPositiveButton("Ok",newDialogInterface.OnClickListener(){

                    publicvoid onClick(DialogInterface arg0, intarg1) {

                        arg0.dismiss();

                        JniTestHelper.exitApp();

                    }

                })

                .create().show();

                break;

            }

        }

    };

}

好了,代码和注释基本就结束了,还需要该的是Android.mk文件。代码如下:

?

1

2

3

4

LOCAL_SRC_FILES := hellocpp/main.cpp \

                   hellocpp/test.cpp \   //将新建的test.cpp类加入mk文件

                   ../../Classes/AppDelegate.cpp \

                   ../../Classes/HelloWorldScene.cpp

之前介绍过万能mk文件生成方法,详见http://blog.csdn.net/yuxikuo_1/article/details/39552431。为了减少出问题的几率,建议改高AndroidManifest中的SDK版本,不改无所谓也。

6、工程总目录

?

1

 

\

 

三、编译运行

 

如出现问题可参考 1)http://blog.csdn.net/yuxikuo_1/article/details/39654499 2)http://blog.csdn.net/yuxikuo_1/article/details/39552639 3)http://blog.csdn.net/yuxikuo_1/article/details/39671733

 

http://www.2cto.com/kf/201410/347637.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值