轉載自:(http://www.cnblogs.com/flyFreeZn/p/4152881.html)
相信很多朋友在使用cocos2d-x+lua開發游戲時都遇到過接入iOS原生SDK的問題,比如常見的接應用內支付SDK,廣告SDK或是一些社交平臺SDK等等,我也沒少接過這類SDK。這篇文章主要是對我做過項目中接入iOS原生SDK實現方案的一個總結,在這里分享給大家,希望對自己和大家的開發工作都有幫助。
在展開正文之前,先做幾點說明:
1.我這里說的iOS原生SDK是指那些完全用Objective-C語言開發,為原生iOS程序設計的SDK。swift很好很強大,不過我還沒用過,慚愧,不過語言終歸只是表達方式而已,解決問題的思路都是一樣的;
2.這里假設游戲的主要邏輯使用lua實現,對于主要邏輯使用C++實現的,用本文的思路一樣可行,并且設計上更簡單,接著往下看就知道了:)
3.本文以quick-cocos2d-x 2.1版本為例進行講解,主要因為這個是我之前做項目用得最多的一個版本,-x新版本變動比較大,但是,還是那句話,解決問題的思路是相同的。
-------------------正式開始的分割線-------------------
好了,我們正式開始。開門見山!
**解決這種接入問題,實際上最主要是解決不同語言交互的問題,一旦跨過語言交互的障礙,剩下的事情就so easy!**
由于涉及到Lua,C++,Objective-C三種語言,這個問題表面上看起來錯綜復雜,但其實只要冷靜地(=。=)梳理,我們便可以得到正確的思路。
因為我們游戲的邏輯主要是用Lua實現的(前面已經做過假設),而SDK是用Objective-C實現,所以這里我們需要解決Lua與Objective-C的交互問題,即最終希望達到的目標是,在Lua層面“調用”Objective-C的代碼(注意這里的調用是加引號的,間接的調用),而當Objective-C層面收到SDK的回調,再通知Lua。我們知道,Lua并沒有簡單的方法直接和Objective-C交流,但是Lua可以通過Lua Binding和C/C++交流,而我們又知道,C++和Objective-C可以混編,即C++可以直接調用(這里調用沒引號,是真的直接調用)Objective-C的代碼。想到這里,思路就很明顯了,我們可以使用C++為Lua和Objective-C的交互充當橋梁,進而實現Lua到Objective-C的交互。
根據上面的分析,我們可以用如下圖表達我們的思路,我們這里將語言交互的過程分成了4個小部分:
**整個語言交互的過程可以總結為:Lua調用Lua Binding的C++接口,C++接口調用混編的Objective-C接口,而Objective-C通過block形式的回調,將結果通知給C++,C++通過Lua的C API將最終結果返回給Lua。**這樣一趟下來,就完成了Lua與Objective-C的整個交互過程。
簡單的說一下這4部分:
1.Lua Binding
將C/C++接口導出給Lua調用的方法,由于篇幅的原因這里就不展開了,具體可以參考Lua的文檔,以及網上其他地方的文章。
2.混編
Objective-C的一大優點就是可以和C與C++混編使用,就像同一個語言一樣共存在一個實現文件里面。具體混編規則也不說了,這里只提兩個小細節:
一,在XCode下混編的實現文件后綴是.mm,而不能是.cpp或者是.m;
二,混編的實現文件引用頭文件的地方,C++或者C的用#include,而Objective-C用#import,相互沒有影響。
3.Block回調
Block是Objective-C一個非常棒的特性,更棒的是在Block里面還可以直接寫C++代碼:)具體想了解的可以看[蘋果官方文檔]
其實在最初,我曾經嘗試過使用發送通知的方式來實現Objective-C對C++的回調,即Objective-C收到SDK回調,給C++部分發送附帶回調信息的通知,雖然cocos2d-x中有現成的NotificationCenter來幫助實現,但這種方式的一個顯而易見的弊端是大大增加了C++代碼和Objective-C代碼的耦合度,Objective-C部分也要混編C++調用C++的NotificationCenter發通知,C++部分也要混編Objective-C代碼,調用C++的NotificationCenter收通知,這種結構實在是有夠煩躁的。
相比之下,使用Block回調就干凈利落太多,Objective-C這邊一切都是純粹的,它并不需要知道自己要被C++調用還是Objective-C調用,也不需要花很多精力在返回回調上,只需要干好自己的本職工作,然后在適當的時候調用Block就一切搞定。
4.Lua C API
Lua C API用于C/C++與Lua的交互,在cocos2d-x中這些C API已經被封裝成了更加易用的C++ Class API。這里要提到的是,在用這套API調用Lua函數的時候,為了傳參,需要參數入棧的操作,這個入棧的順序影響到了Lua函數接受到參數的順序,不過好在規則很簡單:**先入棧的參數排在前**或者說是**入棧順序和實參順序相同**。舉例,如果C++這邊調用Lua函數func時,入棧的順序是A,B,C,那么就是調用函數func(A,B,C)
-------------------漸入佳境的分割線-------------------
在整個語言交互的過程中,如果認為Lua是頂層,Objective-C是底層,那么在實際游戲中交互的過程就是一個自頂向下的過程,然而我們在實現各層級代碼的時候,需要自底向上完成,因為在頂層Lua代碼中的邏輯,是由底層Objective-C SDK的接口與功能決定的。即**我們需要先根據SDK中原始的Objective-C的接口,做適合我們游戲Objective-C封裝代理類,然后根據封裝結果實現C++的bridge接口,最后再實現Lua的對應邏輯**。
根據以上分析,從層級的角度,設計如下:
除過Lua的邏輯,我們最重要需要實現的兩部分內容:C++ Bridge Class 和 Objective-C SDK Delegate Class。前者是起橋梁作用的接口類,原則上不做任何與游戲邏輯相關的數據處理,而后者負責封裝原始的SDK接口,接收以及初步處理SDK回調數據。前者的實現依賴于后者的實現,而后者的實現又依賴于SDK。SDK取得的數據最終通過層層傳遞,交給Lua邏輯處理,最終保證對數據處理的游戲邏輯盡可能多的放到Lua層中。
這樣設計的好處有很多,一方面,頂層的游戲邏輯變動,不影響下層多語言交互代碼,另一方面,底層的SDK變動,如版本更新甚至更換,不影響上層游戲邏輯,多層次結構有效地降低了復雜度,隔離了變化,對于頻繁的需求變更,這種結構也可以保證擴展的便利。
-------------------總結的分割線-------------------
綜上所述,解決接入iOS原生SDK的問題,主要需要4步:
1.根據SDK接口與功能實現Objective-C SDK Delegate Class;
2.根據Objective-C SDK Delegate Class實現對應的C++ Bridge Class;
3.根據C++ Bridge Class生成對應的Lua Binding代碼;
4.寫Lua層邏輯。