首页 > 代码库 > Cocos2d-x3.3RC0通过JNI实现Java与C++互调
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结构体。封装了许多
常用函数:具体如下:
struct _JNIEnv { /* do not rename this; it does not seem to be entirely opaque */ const struct JNINativeInterface* functions; #if defined(__cplusplus) jint GetVersion() { return functions->GetVersion(this); } jclass DefineClass(const char *name, jobject loader, const jbyte* buf, jsize bufLen) { return functions->DefineClass(this, name, loader, buf, bufLen); } jclass FindClass(const char* name) { return functions->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类型签名
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类的非静态函数
#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类型 |
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
L full-qualified-class; | 完全限定的类 |
[ type | type[ ] |
(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暂时没有代码
#ifndef __JniDemo__JniTest__ #define __JniDemo__JniTest__ #include "cocos2d.h" USING_NS_CC; void setPackageName(const char* packageName)//从Java层传过来的包名在此处打印出来 { log("packageName = %s",packageName); } void exitApp()//Java层调用C++层的该函数,关闭程序。 { Director::getInstance()->end(); }
然后在HelloWorldScene.cpp中包含如下头文件,并在menuCloseCallback中添加如下代码:
//头文件包含,判断平台 #if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "../proj.android/jni/hellocpp/test.h"//一定是相对路径 #endif //调用C++调用Java层代码 void HelloWorld::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"
//test.h #ifndef TEST_H_ #define TEST_H_ extern "C" { void showTipDialog(const char* title,const char* msg); } #endiftest.cpp代码如下:
//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> void showTipDialog(const char* title,const char* 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> void Java_org_cocos2dx_cpp_JniTestHelper_setPackageName(JNIEnv* env,jobject thiz,jstring packageName) { const char* pkgName = env->GetStringUTFChars(packageName,NULL); setPackageName(pkgName);//C++层代码 env->ReleaseStringUTFChars(packageName,pkgName); } void Java_org_cocos2dx_cpp_JniTestHelper_exitApp(JNIEnv* env,jobject thiz) { exitApp();//C++层代码 } }
5、Java层函数
在ADT工程目录src/org.cocos2dx.cpp的目录下添加java类,JniTestHelper.java
1)JniTestHelper.java代码如下:
package org.cocos2dx.cpp; import org.cocos2dx.lib.Cocos2dxHandler.DialogMessage; import android.os.Handler; import android.os.Message; public class JniTestHelper { private static Handler mHandler;//Java的Handler传递消息 public static void init(Handler handler) { JniTestHelper.mHandler = handler; } public static native void setPackageName(String packageName);//声明两个静态nativa函数,在Jni中test.cpp中定义,调用C++层的对应函数。 public static native void exitApp(); private static void showTipDialog(final String title,final String text) { Message msg = mHandler.obtainMessage();//接受消息 msg.what = AppActivity.SHOW_DIALOG; DialogMessage dm = new DialogMessage(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代码package org.cocos2dx.cpp; import org.cocos2dx.lib.Cocos2dxActivity; import org.cocos2dx.lib.Cocos2dxGLSurfaceView; import org.cocos2dx.lib.Cocos2dxHandler.DialogMessage; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.os.Handler; import android.os.Message; public class AppActivity extends Cocos2dxActivity{ public static final int SHOW_DIALOG = 0x0001; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); JniTestHelper.init(mHandler);//将下面定义的Handler对象,初始化JniTestHelper中的Handler对象。 JniTestHelper.setPackageName(this.getPackageName()); } public Cocos2dxGLSurfaceView onCreateView(){ Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this); glSurfaceView.setEGLConfigChooser(5,6,5,0,16,8); return glSurfaceView; } static { System.loadLibrary("cocos2dcpp"); } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case SHOW_DIALOG://设置提示框 DialogMessage dm = (DialogMessage)msg.obj; new AlertDialog.Builder(AppActivity.this) .setTitle(dm.titile) .setMessage(dm.message).setNegativeButton("cancle", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub arg0.dismiss(); } }) .setPositiveButton("Ok",new DialogInterface.OnClickListener(){ public void onClick(DialogInterface arg0, int arg1) { arg0.dismiss(); JniTestHelper.exitApp(); } }) .create().show(); break; } } }; }
好了,代码和注释基本就结束了,还需要该的是Android.mk文件。代码如下:
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)http://blog.csdn.net/yuxikuo_1/article/details/396544992)http://blog.csdn.net/yuxikuo_1/article/details/395526393)http://blog.csdn.net/yuxikuo_1/article/details/39671733
注:环境Mac XCode6 ADT22.2.1 Cocos2d-x3.3RC0 红米Note。
四、源码
说了这么多,没有源码那不是坑爹么。源码连接:http://pan.baidu.com/s/1jGn80QE
Cocos2d-x3.3RC0通过JNI实现Java与C++互调
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。