Cocos2d-x3.3通过JNI实现Java与C++互调【备忘转载】

前端之家收集整理的这篇文章主要介绍了Cocos2d-x3.3通过JNI实现Java与C++互调【备忘转载】前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
Cocos2d-x3.3通过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,"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,"()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,"()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);
}
#endif
test.cpp代码如下:
//test.cpp
#include "test.h"
#include "cocos2d.h"
#include "platform/android/jni/JniHelper.h"//引擎提供的JniHelper类
#include "../../../Classes/JniTest.h"//相对路径,上一步在Xcode中创建的类
#include 

#define CLASS_NAME "org/cocos2dx/cpp/JniTestHelper"//这步的路径即是上面红线的路径,很重要
using namespace cocos2d;
extern "C"
{	//下面的函数通过Jni调用Java层的函数	void showTipDialog(const char* title,const char* msg)//在HelloWorldScene中调用该处的此函数,此函数在通过Jni传到Java层
	{						//调用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,暂时还没有放出JniTestHelper的代码,稍后。
		{
			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);
		}
	}//以下两个函数,是通过Jni调用C++层的setPackageName和exitApp,Java层的两个函数在JniTestHelper中定义,参数通过JNIEnv传入
	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;				//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,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/39654499 2)http://blog.csdn.net/yuxikuo_1/article/details/39552639 3)http://blog.csdn.net/yuxikuo_1/article/details/39671733
注:环境Mac XCode6 ADT22.2.1 Cocos2d-x3.3RC0 红米Note。
<img src="http://www.2cto.com/uploadfile/Collfiles/20141030/201410300906046.png" width="360" height="640" alt="" http:="" www.2cto.com="" ym"="" target="_blank" class="keylink" style="border-width: 0px; padding: 0px; margin: 0px; list-style: none; height: 560px; width: 315px;">源码
说了这么多,没有源码那不是坑爹么。源码连接:http://pan.baidu.com/s/1jGn80Q E

猜你在找的Cocos2d-x相关文章