用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都要等上一段時間,廣告才能顯示出來,已經反饋給對方的技術,會在下一個版本修復這個問題。