要在C++端调用Android中的函数接口,需要用到Jni。
C++端的实现,如下:
在cocos2dx\platform\android\jni 中有这么一个类JniHelp.cpp。而我们需要用到里面的这一个函数:
static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
第一个参数是jni函数信息的结构体,如下:
typedef struct JniMethodInfo_
{
JNIEnv * env;
jclass classID;
jmethodID methodID;
} JniMethodInfo;
结构体中的第一个成员是jni固有函数的一个特殊自变量,通过它可以对jni函数进行调用,第二个成员是类的名称(包名+类名),第三个成员是方法名称
第二个参数是类的名称(包名+类名),第三个参数是方法名称,第四个参数是函数参数和函数返回值类型
具体的调用代码如下:
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) //判断当前是否为Android平台
JniMethodInfo minfo;//定义Jni函数信息结构体
//getStaticMethodInfo 次函数返回一个bool值表示是否找到此函数
bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/tysci/cocos2dx/MonsterMustDieAnd","rate", "()V");
if (!isHave) {
CCLog("jni:此函数不存在");
}else{
CCLog("jni:此函数存在");
//调用此函数
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID);
}
CCLog("jni-java函数执行完毕");
#endif
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) //判断当前是否为Android平台
JniMethodInfo minfo;//定义Jni函数信息结构体
//getStaticMethodInfo 次函数返回一个bool值表示是否找到此函数
bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/tysci/cocos2dx/MonsterMustDieAnd","feedBack", "()V");
if (!isHave) {
CCLog("jni:此函数不存在");
}else{
CCLog("jni:此函数存在");
//调用此函数
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID);
}
CCLog("jni-java函数执行完毕");
#endif
JniHelp::getStaticMethodInfo(参数。。。)这个函数的作用其实就是配置我们声明的minfo这个对象的信息,之后
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID)这句就是调用的Jni函数,达到了从C++到Android的跨平台的调用。
这里再补充说明一点,"()V"的意义:()的意思是该函数无参,若有参数V的意思是该函数返回值为void。这里给出参数、返回值的样式对照表,如下:
若是所用到的类型不在这里面,可以仿照这个方法引用:(Ljava/lang/String;Ljava/lang/String;)V",L加上路径名,多个参数中间用分号隔开。
C++中代码实现完了,这边我们调用的是Android中的com/tysci/cocos2dx这个包里面的MonsterMustDieAnd这个类的rate()和feedBack()这两个函数。
Android端的实现,如下:
首先,通过getStaticMethodInfo我们知道要调用的Android端的函数必须的静态的!
于是,一开始有了如下代码:
public static void rate(){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id="
+ getPackageName()));
startActivity(intent);
}
这段代码,一看就是不能通过编译的。先不提getPackageName(),以为我们可以直接换成项目包名。startActivity(intent);这句的错误就是:静态函数中不能调用非静态方法。
这就纠结了,C++端要求我们要调用Android中的静态函数(其实JniHelp这个类中还有一个getMethodInfo()的方法,从字面上的
意思它是要调用非静态的函数,但是我不知道这是否可行,或者说我不知道如何正确的使用这个函数。据我同事实验用这个函数直接调用Android中的非静态
函数是会报错的),而我们想调用的是一个非静态函数,明显的冲突了。
想过了挺多的方法,比如在Android中建立一个单例对象,通过getInstance()这个函数来获取单例对象,然后通过这个单例对象再调用这个单例类里面的非静态函数,结果失败了,可能是我的用法有问题吧。
最后,我的解决方法是通过Android中的Handler。这类似一个间接调用,或者说一个代理。我在C++端调用一个Android中的静态方法,这
个方法中有Message,然后用Handler来sendMessage。而在我Android中的主线程,我实例化了一个handler的对象,它时
刻的在等待handleMessage,捕获消息。只要我C++端一调用,静态方法中发送消息,主线程中的handler捕获消息,这实现了间接的调用非
静态方法。在这里我们不难理解handler的作用,它充当的就是一个第三方的角色,C++不方便和Android的非静态方法沟通(或者说没有权限),
就告诉Handler要调用Android的非静态方法,而Handler有权限调用,自然而然就可以了。
下面给出具体的代码,如下:
private static Handler handler;
private final static int HANDLER_GOTO_GOOGLE = 1;
private final static int HANDLER_GOTO_UMENG = 2;
// 对接C++的静态方法,发送消息到主线程,该方法用于谷歌市场跳转
public static void rate() {
Message msg = new Message();
msg.what = HANDLER_GOTO_GOOGLE;
handler.sendMessage(msg);
}
// 对接C++的静态方法,发送消息到主线程,该方法用于用户反馈界面跳转
public static void feedBack() {
Message msg = new Message();
msg.what = HANDLER_GOTO_UMENG;
handler.sendMessage(msg);
}
// 主线程中接收消息,加到onCreate()里
handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
// 谷歌市场跳转
case HANDLER_GOTO_GOOGLE:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id="
+ getPackageName()));
startActivity(intent);
break;
// 友盟反馈---用户反馈界面跳转
case HANDLER_GOTO_UMENG:
UMFeedbackService.openUmengFeedbackSDK(MonsterMustDieAnd.this);
break;
}
}
};
总结:总的一句话来说,就是通过Handler来间接调用Android中的非静态方法。