概述:

当我们游戏开发好要移植到Android后,在我们的游戏中,可能有打开跳转谷歌市场和添加用户反馈的功能。这些功能的一个特点就是:我在C++端(也就是我的游戏中)的特定地方调用,在Android端实现。也就是说,我要在C++端调用Android中跳转谷歌市场和添加用户反馈的函数接口。那么,如何在C++端调用Android中的函数接口呢?请看正文。

正文:

要在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中的非静态方法。

更多相关文章

  1. Android输入事件从读取到分发一:是谁在读取输入事件
  2. android集成 任务调度 cron4j
  3. EventBus :概述及基本概念 《一》
  4. Android开发指南 ──应用程序基础
  5. Cocos2d-x从C++端调用Android端的非静态函数接口
  6. android NDK的第一个实验
  7. Android屏幕适配全攻略(最权威的官方适配指导)Android屏幕适配出现
  8. kotlin 协程在 Android(安卓)中的使用——Jetpack 中的协程、Ret
  9. 箭头函数的基础使用

随机推荐

  1. 安全与权限
  2. android的 网络下载和数据持久化
  3. 中国市场 Android(安卓)App 兼容性报告
  4. 在QQ通讯录之前拦截短信
  5. UI设计师给的px尺寸单位,安卓如何换算成dp
  6. Android支付宝支付的示例代码
  7. iOS和Android规范解析——提示框(Toast)对
  8. 你真的相信Android手机有加速秘技?这三个
  9. 关于Android开发工程师的从业预期与自我
  10. android使用 webp格式 android使用新格式