Cocos2dx-demo演示项目:Part2

  在实际的cocos2dx开发过程中,经常需要做跨语言的数据交互。我目前常见到的主要是c++和java之间的数据交互,用来做sdk接入、数据统计、广告及分享等,当然这主要是指Android这块的。实际上做IOS这块的话,就涉及到了C++和Object-C的混合编译了,因为目前手头上的开发设备还不支持我这个小屌丝做ios方面的实机开发(没苹果电脑没ios设备没开发者账号,只是在win上安装了个双系统,可以在mac是的ios模拟器上模拟运行项目),所以就没有实践C++和Object-C的混合编译。主要实践的是C++和Java之间的数据交互。


第一部分:C++调用Java函数

  网上的资料很多,大多数的资料介绍的东西都差不多,我的实践也是参考网友提供的资料来实现的。C++调用Java相关的东西主要涉及到:C++函数调用Java函数;带参数调用;处理返回值等。资料很多,根据自己使用到的,总结的来整理下吧:
Java这边:
  一开始我以为,被调用的函数需要是static的,不然C++这边调用的时候会报找不到函数的错误,因为看到很多网友提供的资料都是说java函数需要时静态函数,但后来发现是我太马虎了,因为不必须是静态的!如果C++这边是以getStaticMethodInfo来查找、判断Java这边有没有该方法,那么Java那边的函数就应该是static的;但如果是以getMethodInfo来查找判断,那么Java那边对应的是非静态函数。所以这个是有区别的,自己还是太马虎了点,好在之后发现了这个问题,不然会误导自己!
C++这边:
  使用JniHelper,cocos2dx v3.2引擎版本中包含的头文件为:
#include <jni.g>
#include "platform/android/jni/JniHelper.h"

  并且需要判断平台,不然直接加入这些头文件会报错的,vs或者xcode会找不到这些头文件。在前一篇博客中我就提到了友盟社交的源文件中没有做这个判断,导致当时接触开发不久的我跳进这个坑里半天没爬出来。

  调用Java函数的时候,示例代码:

JniMethodInfo t;
//得到函数信息
JniHelper::getStaticMethodInfo(t,""(这里是java代码路径及名称,如:org.xxx.xxx.test),""(这里是函数名),"()V"(这里是参数表及返回类型)
参数表及返回类型(现在应用到的):
()V                                     :参数表为空,无返回类型
(Ljava/lang/String)V                    :参数为String,无返回类型
// 调用
t.env->CallStaticVoidMethod(t.classID,t.methodID);
// 销毁
t.env->DeleteLocalRef(t.classID);

  上述代码中,如果C++传递给Java的参数是字符串型,不仅参数表需填写 Ljava/lang/String ,而且需要将C++的字符串转换形式,再将转换后的变量传递给Java:

jstring jStr = t.env->NewStringUTF(cString.c_str());

第二部分:Java调用C++函数

  我发现网上大多数介绍的都是C++调用Java函数,而且多数千篇一律,是不是xxxx了。而Java调用C++的东西稍微少了点。目前我实践了的仅是简单的Java无参数调用C++函数,因此我也就简单的记录这个,以后再接触到了其余的再补充这篇博客。

  Java调用C++函数,在Java这边需要将需要调用的函数声明为 static 和 native 的。好像ndk的机制就是这?摘抄一段:

Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google称为“NDK”。
众所周知,Android程序运行在Dalvik虚拟机中,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序。
NDK包括了:
从C / C++生成原生代码库所需要的工具和build files。
将一致的原生库嵌入可以在Android设备上部署的应用程序包文件(application packages files ,即.apk文件)中。
支持所有未来Android平台的一些列原生系统头文件和库
为何要用到NDK?
概括来说主要分为以下几种情况:
1. 代码的保护,由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。
2. 在NDK中调用第三方C/C++库,因为大部分的开源库都是用C/C++代码编写的。
3. 便于移植,用C/C++写的库可以方便在其他的嵌入式平台上再次使用。

  引擎实现跨平台到Android也是借助了这个东西。而C++这边就需要将函数声明为一个好奇怪的形式,并且需要使用C编译。具体来看:

Java这边:

  假如Java需要调用C++一个叫做callCpp的函数,那么就需要将该函数在Java中声明为:

public static native void callCpp();

  然后在Java中直接调用这个函数:

callCpp();

C++这边:

  需要以C编译函数,使用关键词extern:

 1 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
 2 #include <jni.h>
 3 #include "platform/android/jni/JniHelper.h"
 4 extern "C"{
 5     //quit app
 6     JNIEXPORT void JNICALL Java_com_relylib_util_JavaHelperUtil_callCpp(JNIEnv* env,jobject thiz)
 7     {
 8         //
 9     }
10 };
11 #endif

  加入平台判断,引入相关的头文件,然后将函数声明为上述的奇怪形式:

  • JNIEXPORT,不是很清楚这个是干什么用的;
  • void,函数无返回值;
  • JNICALL,标示是JNI调用?
  • 函数名—— Java + 包名 + 类名 + Java中声明的函数名;
  • 参数表—— 无参数表好像也是填写这两个,还没有关注有参数时是使用哪种形式。

  这样,Java中就能调用C++的函数了。


写在最后:

  简单的记录了自己实践C++、Java直接的数据交互,另外在接触到的安卓开发中有一个这样的小tip:有的时候一个操作行为可能需要一个很长的时间响应,很有可能会被系统判定为“假死”,用户就会看到该程序无响应的提示,这是很不友好的!在看网友资料的时候有提到,用handler机制进行消息传递,避免程序“假死”。这个我在做加入有米广告的时候碰到过,有米有一种弹窗广告,出现这种广告的形式相当于弹一个窗口,创建这个窗口需要跟有米的服务器交互数据,网络不稳定的时候就花费的时间长,就可能会造成程序无响应。当时就困扰了我很久,因为这个不是必现的不好查,后来改用handler机制后就没有出现过这个问题了!

  后来发现,游戏开发中要使用到调用原生对话框等可能需要一定时间开销的操作,都最好使用这个机制,以避免程序假死。因为我总是时不时的碰到程序无响应了。

  当然,上述只是建立在我没有系统接触过android开发的基础上的,以后有机会接触了android开发,可能会有更好的解决方案,可能会发现我的理解是错误的!

原文地址:https://www.cnblogs.com/zhong-dev/p/4264310.html