用cocos2d-x lua开发完一个程序以后,要想在iOS端和Android端同时嵌入广告,是一件很麻烦的事情,若是还须要嵌入多家广告平台的SDK那就更蛋疼了,因此选择使用芒果广告平台来作广告集成,至于芒果广告平台是什么东东,还不了解的就自行百度谷歌吧,这里简单说就是一个广告平台的聚合平台,里面聚合了不少其余的广告平台,好比admob,百度,广点通。android
芒果广告平台本身的SDK提供了各个版本的,包括Android原生和iOS原生,而且也提供了Cocos2d-x版本的demo和集成说明,可是我有一个感受芒果广告平台提供的Cocos2d-x的集成说明有太多问题,也许对高手来讲解决问题分分钟的事,可是对于我这种初学者来讲,真是一步一个坑,照着说明文档走一遍,各类报错,各类崩溃。下面介绍一下集成的流程而且把这几天碰到的坑列一下,碰到坑的地方就用"坑x(x == index):"表示,其中芒果的后台配置各个广告平台的key和各类设置这里就不列了。ios
先说一下这个实现的原理,这个很重要,我要是最先能清楚原理,不至于掉那么多坑,原理是咱们能够从芒果获得iOS的SDK和Android的SDK,把他们分别放到对应的程序结构下,作对应的配置以后,在当前平台是能正常运行的,可是由于咱们是使用lua来开发程序的,因此涉及到要如何经过lua来调用到对应的iOS和Android的代码呢?
答案是:经过C++代码来作中间层,Android能够经过jni来和C++作交互,使用C++来封装一些调用Android SDK里面对应的展现广告的方法,iOS同理。这一层没问题以后,经过lua来调用C++的方法,从而实如今lua里调用方法让两个平台都兼容。segmentfault
坑0:还没走就先掉到坑里面了,其实对开发过Cocos2d-x的人来讲,这个不算事,可是由于我不知道原理,我开始看到他们官网提供的SDK下载里有cocos2d-x的,我挺开心的,由于以前只开发了iOS,在iOS里嵌入SDK是比较简单的,导入SDK,而后添加一些必要的framework,再配置一下对应的接口,基本就能通了。因此我以前认为既然提供了Cocos2d-x的SDK了,那基本也就和iOS导入差很少了吧,往项目里面导入SDK配置一下基本就完事了,没想到我错了,根本不是那么一回事呀。并且我后来才发现,官网上居然提供了iOS版的Cocos2d-x SDK和Android版的Cocos2d-x SDK。xcode
后来我研究了这两个SDK包,iOS的包里就是告诉开发者使用Cocos2d-x的项目怎么在ios平台下嵌入SDK,Android同理。并无我以前想的那么简单。那就一个一个来吧,因而先按照说明文档开始嵌入Android部分app
我上面提到过Cocos2d-x的集成文档问题不少,不少东西必需要用到的文档并无提到,对于我这种新手来讲,报个错就抓瞎了,都不知道从哪入手。编辑器
Android
按照步骤走
第一步导入各个集成各个广告平台的SDK,这些SDK其实就是jar包,按照说明导入,而后Add to Build Path就完事了,不过有的广告平台须要额外的一些jar包,好比广点通的就须要android-support-v4.jar,这个就须要开发者在嵌入什么广告平台的时候去对应的开发平台看一下嵌入须要的一些配置,作对应的处理。
第二步添加用户权限,在mainifest.xml里添加文档里说必需要添加的配置以后,根据每一个广告平台的须要配置对应的内容ide
坑1:配置各个广告平台的时候最好下载一个它们官网的android完整demo,照那个里面的配,cocos2d-x版本的demo和说明文档都不全,我在这浪费了很多时间和他们的客服和技术沟通,还被由于是新手被鄙视问太基础的问题。函数
第三步在代码里添加调用的代码,这个没什么好说的,按照说明文档配置就好了,没有坑。这里的目的是在Android代码里配置了一些静态方法,等和C++交互调通了之后,让C++调用的。第四步,新建C++文件,MOGOAd.h和MOGOAd.cpp文件都是demo里提供的,把他们放在项项目目录下的/frameworks/runtime-src/Classes下就好了
.h文件的代码:测试
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include <jni.h> #include "platform/android/jni/JniHelper.h" #include <android/log.h> #include "cocos2d.h" #endif using namespace cocos2d; class MOGOAd { public: MOGOAd(); virtual ~MOGOAd(); static void showBanner(); static void hideBanner(); };
.cpp的代码:ui
#include "MOGOAd.h" MOGOAd::MOGOAd(){} MOGOAd::~MOGOAd(){} void MOGOAd::showBanner() { #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) JniMethodInfo showBanner; bool isHave = JniHelper::getStaticMethodInfo(showBanner,"org/cocos2dx/cpp/AdsMogoCoCos2dx","showBannerStatic","()V"); if (!isHave) { CCLog("jni:showBannerStatic false"); }else{ showBanner.env->CallStaticVoidMethod(showBanner.classID, showBanner.methodID); } #endif } void MOGOAd::hideBanner() { #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) JniMethodInfo hideBanner; bool isHave = JniHelper::getStaticMethodInfo(hideBanner,"org/cocos2dx/cpp/AdsMogoCoCos2dx","hideBannerStatic","()V"); if (!isHave) { CCLog("jni:hideBannerStatic false"); }else{ CCLog("jni:hideBannerStatic true"); hideBanner.env->CallStaticVoidMethod(hideBanner.classID, hideBanner.methodID); } #endif }
由于作测试的时候只用了banner样式的广告,因此我这里只提取了banner的两个方法,其余样式的根据本身的需求添加对应的方法就好了,这些C++的文件后面作兼容iOS的时候会修改里面的内容,后面再详细说,这里先用默认的。
第五步是配置jni,让C++经过jni和Android能交互,在Android的项目目录下有个jni文件夹,里面有Android.mk文件,这个是配置jni对交互的相关的,里面找到LOCAL _ SRC _ FILES参数(我这里的""之间加了空格的,由于编辑器会把两个""作转义,大加参照下面的代码):
//这里原本会有一堆系统默认添加的内容,我这里就列了最后几个 LOCAL_SRC_FILES := \ ../../Classes/AppDelegate.cpp \ ../../Classes/ConfigParser.cpp \ lua/Runtime_android.cpp \ lua/main.cpp //--------------- //咱们须要在lua/main.cpp的后面添加一个" \",而后再后面添加开始新加的MOGOAd.cpp文件的路径,改完后的样子: LOCAL_SRC_FILES := \ ../../Classes/AppDelegate.cpp \ ../../Classes/ConfigParser.cpp \ lua/Runtime_android.cpp \ lua/main.cpp \ ../../Classes/MOGOAd.cpp
添加完以后,他们完档上写了:
可是个人Cocos2d-x lua项目里,对应的目录下根本没有这个东西呀
可是这里的大概意思是明白的,就是虽然配置好了,因此这里须要编译一下,使用:
cocos compile -p android
不出意外是能编译经过的,可是编译以后只能说明Android到C++层面联通了,可是如何让Lua能和C++交互呢?参考我老大的博客Cocos2d-x下Lua调用自定义C++类和函数的最佳实践,我想我本身写还不如他写的1/10详细,我也是按照这篇文章一步一步调通的,文章比较长,若是只想调通程序,能够直接看里面的"第五层:使用cocos2d-x的方式来将C++类注册进Lua环境",其中里面列出的流程:"五、用Xcode将自定义的C++类和生成的桥接文件加入工程,否则编译不到"的解决方案是在Xcode里添加编译后的文件,可是Android下还须要单独配置一下:
在/项目根目录/frameworks/cocos2d-x/cocos/scripting/lua-bindings下有一个Android.mk,须要在里面的LOCAL _ SRC _ FILES里添加上:
auto/lua_MOGOAd_auto.cpp \
和上面添加LOCAL _SRC _ FILES相似,由于lua_MOGOAd_auto.cpp里面用到了MOGOAd.cpp,因此还须要在Android.mk里找到LOCAL _ C _ INCLUDES:在里面添加对应的Classes路径:
$(LOCAL_PATH)/../../../../runtime-src/Classes \
这一通处理完成以后,在编译一次:
cocos compile -p android
不出意外应该是能编译经过的,接下来直接经过Cocos Code IDE去跑编译以后的apk包就好了。显示效果:
iOS
第一步把下载的SDK导入到项目里,下载下来的SDK分红了三个文件夹AdsMoGoRes,AdsMoGOSDK,Utils,用Xcode打开Cocos2d-x的iOS_Mac项目,把这三个文件夹导入到项目的根目录下,其真实路径是/cocos2d-x项目根目录/frameworks/runtime-src/proj.ios_mac/
坑2:导入的时候须要注意一个问题,就是Cocos2d-x建立出来的项目默认是带了Mac版本的,而导入的SDK是给iOS用的,里面用到了的好比UIKit之类的framework在Mac下是没有的,因此在导入这些SDK文件选择Target的时候记得不要勾选Mac版本的Target,要否则后面编译Mac的时候各类报错各类找不到对应的framework,还获得Build Phases里的Compile Sources把添加进去的再挨个移除掉。
第二步添加各类必要的Framework,这个没什么好说的,添加就好了
坑3:这里再一次吐槽Cocos2d-x的说明文档写的烂,必需要的包都没有列全,EventkitUI.framework、GameController.framework都是必需要的,文档没列出来,只是把他们放在了建议添加的framework里
第三步更改静态库设置,点击程序Target文件,选择Build Settings标签页,找到Linking下面的Other Linker Flags,添加参 数-ObjC:
第四步添加各广告平台SDK,直接在官网下载芒果的iOS版的SDK,里面有很全的各个广告平台的SDK包,根据本身的须要导入到项目里就能够了,导入完以后最好去已经导入过的广告平台官网看一下,他们的SDK须要哪些framework支持,而后根据需求导入framework。
第五步配置MOGOAd.h和.cpp,若是集成Android的时候已经配置过lua调用C++的程序了,这里只须要修改MOGOAd.h和.cpp,使之能同时兼容iOS和Android就完成了,若是还没调通lua和C++的交互,请看上面介绍Android部分里的lua和C++交互部分。
MOGOAd.h:
#include "cocos2d.h" //原来这里作的#include 都放到.cpp统一处理了 using namespace cocos2d; class MOGOAd { public: MOGOAd(); virtual ~MOGOAd(); static void showBanner(); static void hideBanner(); };
MOGOAd.cpp:
#include "MOGOAd.h" //若是是Android,就导入jni的一套东西,若是是iOS,就导入SDK里须要引入的头文件 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include <jni.h> #include "platform/android/jni/JniHelper.h" #include <android/log.h> #elif (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #include "AdsmogoBanner.h" #include "AdsMogoInterstitial.h" #endif MOGOAd::MOGOAd(){} MOGOAd::~MOGOAd(){} void MOGOAd::showBanner() { //下面也是一样的操做,不一样的平台不一样的处理方式 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) JniMethodInfo showBanner; bool isHave = JniHelper::getStaticMethodInfo(showBanner,"org/cocos2dx/lua/AppActivity","showBannerStatic","()V"); if (!isHave) { CCLog("jni:showBannerStatic false"); }else{ showBanner.env->CallStaticVoidMethod(showBanner.classID, showBanner.methodID); } #elif (CC_TARGET_PLATFORM==CC_PLATFORM_IOS) char mogoid []="芒果的appid"; AdsmogoBanner::sharedBanner()->showBanner(mogoid, AdsmogoBannerTypeNormalBanner, 0, 0, false); #endif } void MOGOAd::hideBanner() { #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) JniMethodInfo hideBanner; bool isHave = JniHelper::getStaticMethodInfo(hideBanner,"org/cocos2dx/lua/AppActivity","hideBannerStatic","()V"); if (!isHave) { CCLog("jni:hideBannerStatic false"); }else{ CCLog("jni:hideBannerStatic true"); hideBanner.env->CallStaticVoidMethod(hideBanner.classID, hideBanner.methodID); } #elif (CC_TARGET_PLATFORM==CC_PLATFORM_IOS) AdsmogoBanner::sharedBanner()->hideBanner(); #endif }
配置完成,执行:
cocos compile -p ios
不出意外,编译经过,而后在lua里调用:
-- 这里的ad指的是当时配置.ini文件时的target_namespace ad.MOGOAd:showBanner() ad.MOGOAd:hideBanner()
就能实现Banner的开启和关闭了,模拟器测试效果以下:
坑4:若是程序还在Mac上运行,这个时候若是编译Mac会报错,由于当时配置lua和C++交互的时候,在AppDelegate.cpp里添加过一段代码:
register_all_MOGOAd(stack->getLuaState())
而这个MOGOAd其实不该该加在Mac版本里的,有两种方法解决这个问题
第一种,添加这段代码的时候须要加一个判断:
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID ||CC_TARGET_PLATFORM == CC_PLATFORM_IOS) register_all_MOGOAd(stack->getLuaState()); #endif
只有Android和iOS的状况下把这段代码添上就OK了,可是这样修改在lua层调用的时候不方便,须要判断一次设备才行,要否则lua会找不到对应的方法,应为Mac版本把那些方法都屏蔽了。
第二种,这里不改,修改Mac的Target,在Mac的Target里Build Phases里的Compile Sources里添加MOGOAd.cpp,添加以后:
而后点击项目下里的cocos2d _ lua _ bindings.xcodeproj,Target选择luabindings Mac,在后在Build Phases里的Compile Sources里添加lua _ MOGOAd _ auto.cpp,在Copy Headers里添加lua _ mogo _ auto.hpp,添加以后:
这种方法的目的就是把MOGOAd.cpp也放入到Mac的项目中,让其能够调用到,不至于在lua端报错,等因而把lua端的判断放到.cpp里作了,MOGOAd.cpp里面若是Mac什么都不作的话,什么都不写就好了。设置完成以后再编译运行,一切正常了,Mac下也能点对应的按钮,只是没有广告,效果图:
折腾了一个星期,总算搞定了。
添加一个新的问题,发现SDK里的ShowBanner是用来作初始化操做的,而hideBanner是直接对Banner的View作remove操做,并非方法名所说的hide和show的关系,这样的设计的感觉就是每次show都要等上一段时间,广告才能显示出来,已经反馈给对方的技术,会在下一个版本修复这个问题。