1.准备环境工作,在项目目录下新建自己的MyApplication,MyActivity,MyAllSdk,MyBroadcastReceiver的java文件:
在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:
2. cocos2d-x 调 android:
创建cocos2d-x项目,打开helloworld工程
打开helloworld.cpp添加头文件:
在.cpp需要调用android的地方加入一下代码
到这里就实现了cocos2d-x调用android,每次代码执行到上图时就会调用CLASS_NAME类下的vibrate函数
3. android 调用 cocos2d-x:
cocos2d-x中的函数:
在下图目录下新建一个对应名字的.h文件
在MyAllSdk.h中添加代码:
在main.cpp中添加代码:
这里的main.cpp编译的地址为:
我的代码到这里调用了java中的MyAllSdk 的"public","静态","native"函数onBatteryStatus:他就会到main.cpp中执行对应函数的代码,从而调用cocos2d-x;
(前面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)