天天看点

cocos2d-x和android相互调用

1.准备环境工作,在项目目录下新建自己的MyApplication,MyActivity,MyAllSdk,MyBroadcastReceiver的java文件:

cocos2d-x和android相互调用

在MyApplication.Java中添加代码:

package com.OYHP;

import android.app.Application;

public class MyApplication extends Application {
	@Override
	public void onCreate() {
		super.onCreate();
	}
}
           

在MyActivity.Java中添加代码:

package com.OYHP;

import com.OYHP.MyAllSdk;
import com.OYHP.MyApplication;
import com.OYHP.MyBroadcastReceiver;

import android.util.Log;
import android.os.Bundle;
import android.content.Intent;
import android.content.IntentFilter;
import org.cocos2dx.lib.Cocos2dxActivity;

import com.OYHP.SdkTest.R;    //这里的路径后面介绍

public class MyActivity extends Cocos2dxActivity {
	
	private MyAllSdk myAllSdk; //我声明了,但未使用
	private MyApplication myApp; //我声明了,但未使用
	private MyBroadcastReceiver receiver;

	@Override
	public void onCreate(Bundle saveInstanceState) {
		super.onCreate(saveInstanceState);
		
		myApp = (MyApplication) getApplication();
		myAllSdk = new MyAllSdk(this);
		
		receiver = new MyBroadcastReceiver();
		registerReceiver(receiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));    //注册电量监听广播
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		//销毁广播
		unregisterReceiver(receiver);
	}
}
           

在MyAllSdk.Java中添加代码:

package com.OYHP;

import android.content.Context;
import android.app.Activity;
import android.os.Vibrator;

public class MyAllSdk {
	private static Activity sActivity = null;
	
	MyAllSdk(Activity _activity) {
		sActivity = _activity;
	}
	
	public static void vibrate(int times) {
		if(sActivity != null) {
			Vibrator v = (Vibrator) sActivity.getSystemService(Context.VIBRATOR_SERVICE);
			v.vibrate(times);
		}
	}
	
	public native static void onBatteryStatus(int _batteryStatus, int _charge);
}
           

在MyBroadcastReceiver.Java中添加代码:

package com.OYHP;

import android.content.BroadcastReceiver;
import android.os.BatteryManager;
import android.widget.TextView;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.OYHP.MyAllSdk;

public class MyBroadcastReceiver extends BroadcastReceiver { 
	 @Override
	 public void onReceive(Context context, Intent intent) {
		int isCharge = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN) == BatteryManager.BATTERY_STATUS_CHARGING ? 1 : 0;
		int currtent = intent.getExtras().getInt("level");
		int total = intent.getExtras().getInt("scale");
		int percent = currtent * 100 / total;
		 
		MyAllSdk.onBatteryStatus(percent, isCharge);
	 }
 }
           

配置AndroidManifest.xml:

cocos2d-x和android相互调用
cocos2d-x和android相互调用

2. cocos2d-x 调 android:

创建cocos2d-x项目,打开helloworld工程

    打开helloworld.cpp添加头文件:

cocos2d-x和android相互调用

在.cpp需要调用android的地方加入一下代码

cocos2d-x和android相互调用

到这里就实现了cocos2d-x调用android,每次代码执行到上图时就会调用CLASS_NAME类下的vibrate函数

3. android 调用 cocos2d-x:

cocos2d-x中的函数:

cocos2d-x和android相互调用

在下图目录下新建一个对应名字的.h文件

cocos2d-x和android相互调用

在MyAllSdk.h中添加代码:

cocos2d-x和android相互调用

在main.cpp中添加代码:

cocos2d-x和android相互调用

这里的main.cpp编译的地址为:

cocos2d-x和android相互调用
cocos2d-x和android相互调用

我的代码到这里调用了java中的MyAllSdk 的"public","静态","native"函数onBatteryStatus:他就会到main.cpp中执行对应函数的代码,从而调用cocos2d-x;

cocos2d-x和android相互调用

(前面MyActivity代码中创建了广播来监听电量,所以当系统电量发生变化时就会通知这里的onReceive函数)

以上的相关的一些解释:

主体思路通过JNI获取java虚拟机,再获取当前程序的JNI环境,通过JNI环境获取需要调用的java类信息,再获取需要调用的java类中的函数信息。再通过JNI环境调用,使用类信息、函数信息,调用对应的java函数。

JniHelper类的使用,加入如下头文件:

#include "platform/android/jni/JniHelper.h"

需要使用的这两个接口,就可以获取java类的所有函数信息了。JNI环境的获取、各种错误处理都已经在这两个接口实现中封装好了。

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);

参数详解:

两个接口的参数一样,意义也相同,详解如下:

JniMethodInfo &methodinfo JniMethodInfo对象的引用,函数执行中会把jniEvn、classid、methodid写入到引用中。

const char *className 类的路径

const char *methodName 函数名

const char *paramCode 函数类型简写:它的格式为:(参数)返回类型。例如:无参数,void返回类型函数,其简写为 ()V

java中的类型对应的简写如下:

参数类型 参数简写

boolean Z

byte         B

char         C

short S

int I

long         J

float         F

double D

void         V

Object Ljava/lang/String; //必须带分号

Array [Ljava/lang/String; //必须带分号

如果函数有多个参数,直接把简写并列即可。注意Object与Array型参数简写结尾的分号,示例:

void(int x1, int x2, int x3,int 4) (IIII)V 

void((int x, String a, int y) (ILjava/lang/String;I)V

JNIEvn有一系列的CallStatic[返回类型]Method、Call[返回类型]Method接口,需要针对不同的函数返回类型选择调用。

[返回类型]以函数返回类型的不同,对应不同的函数名。

例如:

CallStaticVoidMethod ———void

CallVoidMethod ———void

其对应关系如下:

函数名 函数返回值类型

Void         void

Object jobject

Boolean jboolean

Byte         jbyte

Char         jchar

Short jshort

Int         jint

Long jlong

Float         jfloat

Double jdouble

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

jint jX = 10;

jint jY = 10;

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

参数类型转换关系如下:

C++类型     JAVA类型

boolean     jboolean

byte     jbyte

char     jchar

short     jshort

int     jint

long     jlong

float     jfloat

double     jdouble

Object     jobject

Class     jclass

String     jstring

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);

详尽的示例代码

最后,放一块比较详细的JNI使用代码,基本上覆盖了的全部使用情况。

    JniMethodInfo minfo;//JniHelper   

    bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","loginGree", "()V"); 

     if (isHave) {

         //CCLog("有showText ");

         minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID);

     } else  {

         //CCLog("没有方法showText");

     }

    //将c++中的string转换成java中的string

    char str[] = "test";

    bool isHava = JniHelper::getStaticMethodInfo(minfo, "com/cocoa/HiWorld", "shareSina", "(Ljava/lang/String;)V")

     if ( isHave ) {

         jstring jstr = minfo.env->NewStringUTF("test1 share");

         minfo.env -> CallStaticVoidMethod(minfo.classID, minfo.methodID, jstr);

     } else {

         CCLog("没有方法share");

     }

    jint ind = 0;

    jlong lsre = 2202l;

    bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","setHighScore", "(IJ)V"); 

     if (isHave) {

         minfo.env -> CallStaticVoidMethod(minfo.classID, minfo.methodID, ind, lsre);            

     }

    isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "()V"); 

     if ( isHave ) {

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

     }

    isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([II)V"); 

     if ( isHave ) {

         jint buf[]={7,5,8,9,3};

         jintArray jintArr;     //定义jint数组

         jintArr = minfo.env->NewIntArray(5);

         minfo.env->SetIntArrayRegion(jintArr,0,5,buf);

         jint index = 0;

         minfo.env -> CallVoidMethod(jobj,minfo.methodID,jintArr,index);

     }

    isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([BI)V"); 

    if (isHave) {

        jbyte buf[]={7,5,8,9,3};

        jbyteArray jbyteArr; //定义jbyte数组

        jbyteArr = minfo.env->NewByteArray(5);

        minfo.env->SetByteArrayRegion(jbyteArr,0,5,buf);

        jint index = 0;

        minfo.env -> CallVoidMethod(jobj,minfo.methodID,jbyteArr,index);

    }

    private static HiWorld hiWorld = null;

    // c++中調用的方法

    public static Object rtnActivity()

    // c++中調用的方法,传String类型

    public void showText(final String msg) 

    //c++中調用的方法,传String类型和int类型

    public String showText(final String msg,final int index) { 

        return "okey String showText(final String msg,final int index)";

    }

    //c++中調用的方法,传String[]类型和int类型

    public String[] showText(final String[] msg,final int index) { 

        String[] strArr;

        return strArr;

    }

    //c++中調用的方法,传int[]类型和int类型

    public void testArr(final int msg[],final int index)

    //c++中調用的方法,传int[]类型和int类型

    public void testArr(final byte msg[],final int index)