使用cocos2dx开发游戏过程中难免需要调用其他代码,因为其是跨平台的。必然会要去调用不同平台的代码,这篇博客就介绍如何使用Jni来实现c++与java代码的互调。
先实现c++调用Android的java层代码。我们先添加一个类,比如类名叫CallJava,下面贴上代码,再做解释:
1 #ifndef __CALL_JAVA_H__ 2 #define __CALL_JAVA_H__ 3 4 #include "cocos2d.h" 5 USING_NS_CC; 6 7 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) 8 class CallJava 9 { 10 public: 11 void static initCall(); 12 void static loginCall(); 13 void static closeCall(); 14 }; 15 16 17 #endif 18 19 #endif // __CALL_JAVA_H__
CallJava.h
1 #include "CallJava.h" 2 3 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) 4 #include "platform/android/jni/JniHelper.h" 5 #include <jni.h> 6 #include <android/log.h> 7 void CallJava::initCall() 8 { 9 JniMethodInfo minfo; 10 11 bool isHave = JniHelper::getStaticMethodInfo(minfo,"org/cocos2dx/call/CallJava","initCall","(Ljava/lang/String;I)V"); 12 if (isHave) 13 { 14 15 jstring jstr = minfo.env->NewStringUTF("init_call"); 16 17 minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,jstr,2000); 18 minfo.env->DeleteLocalRef(minfo.classID); 19 } 20 else 21 { 22 CCLOG("func is not exited..."); 23 } 24 25 } 26 27 28 void CallJava::loginCall() 29 { 30 JniMethodInfo minfo; 31 32 bool isHave = JniHelper::getStaticMethodInfo(minfo,"org/cocos2dx/call/CallJava","loginCall","(Ljava/lang/String;)V"); 33 if (isHave) 34 { 35 36 jstring jstr = minfo.env->NewStringUTF("login_call"); 37 38 minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,jstr); 39 minfo.env->DeleteLocalRef(minfo.classID); 40 } 41 else 42 { 43 CCLOG("func is not exited..."); 44 } 45 46 } 47 48 void CallJava::closeCall() 49 { 50 JniMethodInfo minfo; 51 52 bool isHave = JniHelper::getStaticMethodInfo(minfo,"org/cocos2dx/call/CallJava","CloseCall","()V"); 53 if (isHave) 54 { 55 minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID); 56 minfo.env->DeleteLocalRef(minfo.classID); 57 } 58 else 59 { 60 CCLOG("func is not exited..."); 61 } 62 63 } 64 #endif
CallJava.cpp
头文件没啥好说的,我们重点说说cpp文件。。。
JniHelper::getStaticMethodInfo(minfo,"org/cocos2dx/call/CallJava","initCall","(Ljava/lang/String;I)V");
"org/cocos2dx/call/CallJava"就是要调用函数的路径,“initCall”当然就是函数名了,
"(Ljava/lang/String;I)V" 就是(参数)返回值的意思。 这里函数的参数是string和int类型,返回值void
参数、返回值对照表如下:
jstring jstr = minfo.env->NewStringUTF("init_call"); 这是java的string类型的本地表示,int->jint,诸如此类...
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,jstr,2000); 函数的意思是调用静态方法,后面2个参数就是传进去的字符串和int值。第一个参数在调用CallVoidMethod方法是不用传的。。。这个不用多说,你传多了会报错的
好,下面看看java层代码的实现:因为我们的路径是"org/cocos2dx/call/CallJava",所以我们在project.android下的src文件夹添加一个包org/cocos2dx/call,然后添加一个CallJava文件
1 package org.cocos2dx.call; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.os.Message; 6 import android.util.Log; 7 import android.widget.Toast; 8 import org.cocos2dx.cpp.AppActivity; 9 import org.cocos2dx.lib.Cocos2dxActivity; 10 11 12 public class CallJava { 13 14 public static void initCall(String str,int i) 15 { 16 17 Message msg = new Message(); 18 19 Bundle bundle = new Bundle(); 20 bundle.putString("key", str); 21 bundle.putInt("id", i); 22 msg.what = AppActivity.call_login; 23 msg.setData(bundle); 24 25 AppActivity.getInstance()._handler.sendMessage(msg); 26 27 } 28 29 30 public static void loginCall(String str) 31 { 32 33 Message msg = new Message(); 34 35 Bundle bundle = new Bundle(); 36 bundle.putString("key", str); 37 38 msg.what = AppActivity.call_login; 39 msg.setData(bundle); 40 41 AppActivity.getInstance()._handler.sendMessage(msg); 42 43 } 44 45 public static void CloseCall() 46 { 47 CallCpp.exit(); 48 } 49 }
CallJava.java
这里的3个方法,对应这上面cpp文件的三个方法,就是JniHelper::getStaticMethodInfo方法的第三个参数。关于这里面的实现不多说,是android的消息机制,这里写在了另个AppActivity.java文件中,一会贴上代码。
我们先看第三个函数CloseCall()的实现
1 public static void CloseCall() 2 { 3 CallCpp.exit(); 4 }
CallCpp是src文件夹下的另个文件CallCpp.java的类名,exit是它的一个函数,代码如下
1 package org.cocos2dx.call; 2 3 public class CallCpp { 4 public static native void init(String str,int i); 5 public static native void login(String str); 6 public static native void exit(); 7 }
JNI是Java Native Interface的 缩写。如果你想将一个方法做为一个本地方法的话,那么你就必须声明改方法为native的,并且不能实现。
看看c++层这几个函数的对应调用
1 #ifndef __CALL_CPP_H__ 2 #define __CALL_CPP_H__ 3 4 #include "cocos2d.h" 5 USING_NS_CC; 6 7 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) 8 #include <jni.h> 9 extern "C" 10 { 11 void Java_org_cocos2dx_call_CallCpp_init(JNIEnv *,jobject,jstring,jint); 12 void Java_org_cocos2dx_call_CallCpp_login(JNIEnv *,jobject,jstring); 13 void Java_org_cocos2dx_call_CallCpp_exit(JNIEnv *,jobject); 14 }; 15 16 17 18 #endif 19 20 #endif // __CALL_CPP_H__
CallCpp.h
解释下函数名的意思,首先Java_ 后面是 包名,类名,函数名。
1 #include "CallCpp.h" 2 #include "HelloWorldScene.h" 3 4 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) 5 #include "platform/android/jni/JniHelper.h" 6 #include <jni.h> 7 8 void Java_org_cocos2dx_call_CallCpp_init(JNIEnv *env,jobject thiz,jstring str,jint id) 9 { 10 std::string msg = JniHelper::jstring2string(str); 11 int i = id; 12 MessageBox(msg.c_str(),"C++"); 13 14 } 15 16 void Java_org_cocos2dx_call_CallCpp_login(JNIEnv *env,jobject thiz,jstring str) 17 { 18 std::string msg = JniHelper::jstring2string(str); 19 MessageBox(msg.c_str(),"C++"); 20 21 } 22 23 void Java_org_cocos2dx_call_CallCpp_exit(JNIEnv *env,jobject thiz) 24 { 25 26 HelloWorld* main = HelloWorld::getInstance(); 27 if (main) 28 { 29 Director::getInstance()->end(); 30 } 31 } 32 #endif
CallCpp.cpp
我们看下实现效果: