| 本次大會(huì)更多相關(guān)報(bào)道,請(qǐng)?jiān)L問(wèn)CocoaChina2013春季開(kāi)發(fā)者大會(huì)官網(wǎng)>>   《大掌門(mén)》歐陽(yáng)劉彬分享的內(nèi)容同樣是與Cocos2D-X和跨平臺(tái)開(kāi)發(fā)有關(guān),在演講中他詳細(xì)分享了為什么會(huì)選擇Lua。
 
 歐陽(yáng)劉彬:首先感謝CocoaChina的邀請(qǐng),跟大家分享一下我們《大掌門(mén)》在游戲開(kāi)發(fā)過(guò)程當(dāng)中使用Cocos2D所開(kāi)發(fā)的一些經(jīng)驗(yàn)。剛才凌聰講的內(nèi)容 感覺(jué)已經(jīng)是一個(gè)比較完整的、系統(tǒng)的東西了,我們本身在剛開(kāi)始做的時(shí)候,我覺(jué)得他們那邊應(yīng)該是有一個(gè)比較強(qiáng)大開(kāi)發(fā)團(tuán)隊(duì)在下面做了一些支撐的事情。我們做的一 些事情,其實(shí)大部分他剛才已經(jīng)提到了,我們做的可能不像他們那么系統(tǒng),但是也有一些東西是跟他很像的一個(gè)過(guò)程,我就我們這邊的一些經(jīng)驗(yàn)來(lái)跟大家再做一些分享。
 我們?yōu)槭裁催xCocos2D-X,其實(shí)最大的原因就是跨平臺(tái)。當(dāng)時(shí)為什么選擇Lua呢?大概我們從去年春天的時(shí)候開(kāi)始做這個(gè)事情,我去年春天也來(lái)了 CocoaChina的一個(gè)會(huì),當(dāng)時(shí)我們選一個(gè)腳本,覺(jué)得比較合適的可能還是用Lua,那時(shí)候已經(jīng)出來(lái)了一段時(shí)間了。它的一些特點(diǎn)其實(shí)剛才也已經(jīng)提到過(guò) 了,我們覺(jué)得它,支持一些動(dòng)態(tài)更新,它的容錯(cuò)性比別的好,我們找一個(gè)靠譜的C++程序員說(shuō)實(shí)話還是比較難的,我們?cè)陂_(kāi)發(fā)速度上會(huì)比其他的語(yǔ)言要快一些。 我們的一些基本情況,其實(shí)我們用Cocos2D是比較老的一個(gè)版本了,我們大概在去年3、4月份就開(kāi)始做,基于上面做了一些改進(jìn),后面因?yàn)樵陂_(kāi)發(fā)的過(guò)程當(dāng) 中,我們覺(jué)得一個(gè)底層的框架已經(jīng)選好了之后就盡量不要去動(dòng)它,因?yàn)檫@個(gè)說(shuō)實(shí)話是一個(gè)傷筋動(dòng)骨的事情,但是我們會(huì)繼續(xù)用Cocos2D的框架,我們會(huì)選擇 2.0的版本,老的那一套東西一直在上面做。我們做的一些事情沒(méi)有那么系統(tǒng),但是也做了一些。首先我們?cè)谏厦孀隽宋覀兊囊恍┦录芾?,做了一些底層的UI 控件,做了我們的網(wǎng)絡(luò)通信模塊和加解密的模塊。我們的一個(gè)特點(diǎn)就是說(shuō),我們所有的游戲邏輯都是用Lua去實(shí)現(xiàn)的,我們?cè)贚ua里面也去實(shí)現(xiàn)了一些MVC的 框架等等,但是對(duì)于一些性能要求比較高的東西,比如說(shuō)加解密這種東西可能還會(huì)在C上實(shí)現(xiàn),在Lua里面去用新的接口。
 首先我要分享的就是我們版本更新的機(jī)制,其實(shí)剛才凌聰也提到了,我們?yōu)槭裁匆肔ua,就說(shuō)它能夠走游戲內(nèi)更新的方式更新版本,比如說(shuō)我們拿App Store來(lái)舉例,你去提交一個(gè)版本,我們以往的經(jīng)驗(yàn),首次提交的話可能需要一個(gè)月的時(shí)間,后續(xù)的更新審核可能5個(gè)工作日,也就一周過(guò)去了。這個(gè)提交從審 核里面如果一個(gè)月過(guò)了,當(dāng)然大家相當(dāng)高興了。中間的過(guò)程當(dāng)中其實(shí)經(jīng)常會(huì)遇到一些非技術(shù)的原因把這個(gè)打回來(lái),比如說(shuō)你的截圖,或者是一些信息寫(xiě)的不對(duì),中間 來(lái)回打會(huì)可能也會(huì)耽誤時(shí)間,這個(gè)審核周期太長(zhǎng)了,我們覺(jué)得是一件讓人不太好接受的事情,尤其是一些非技術(shù)原因。
   再有一個(gè)問(wèn)題就是,像我們的游戲版本,我們游戲的安裝包現(xiàn)在說(shuō)實(shí)話,從最開(kāi)始的50兆到現(xiàn)在變成100兆已經(jīng)比較大了。假設(shè)我們?nèi)?shí)現(xiàn)的話,如果我發(fā)現(xiàn)游戲里面一個(gè)比較重要的Bug,我去修復(fù)這個(gè) Bug,提交之后玩家再去更新,按照現(xiàn)有的機(jī)制,玩家就是下一個(gè)完整的安裝包下來(lái)。國(guó)內(nèi)其實(shí)像凌聰剛剛提到了,在Android市場(chǎng)有一定的新的機(jī)制,但 是我了解在Android的4.0上面才支持這種方式,在比較低的版本上還是不支持增量的更新。   在騰訊這邊確實(shí)是做得比較好,它的QQ游戲大廳是支持增量 的更新的。我剛才提到的,就是說(shuō)更新一個(gè)版本,我們加一個(gè)什么玩法有一個(gè)全新的包,這種帶來(lái)的問(wèn)題就是每次更新都要下一個(gè)完整的包,用戶的體驗(yàn)是非常差 的,對(duì)于用戶整個(gè)留存都會(huì)有影響。我們的解決方案就是,所有的游戲邏輯都去用Lua實(shí)現(xiàn),我們實(shí)現(xiàn)一套游戲內(nèi)更新的機(jī)制,每次游戲升級(jí)的時(shí)候,基本上只要 更新自己的Lua文件就行了,這樣就可以及時(shí)、隨時(shí)的更新,我們不需要等任何人的審核。還有就是快速,我們走增量更新的方式,只需要去下載我們改動(dòng)過(guò)的一 些資源和代碼。在這里也可以插一句,剛才也人問(wèn)到蘋(píng)果基于這個(gè)審核的條款,在我的理解,實(shí)際上蘋(píng)果只是給自己設(shè)一個(gè)底線。   如果游戲只是對(duì)于一些正常的功能 邏輯的更新,走腳本的方式的話應(yīng)該還是可以的,只不過(guò)你如果把游戲整個(gè)更新一遍,變成一個(gè)完全不同的游戲,那肯定是不行的,我認(rèn)為蘋(píng)果這種條款,可能是作 為它自己的一個(gè)底線放在那兒。 我們整個(gè)游戲更新的過(guò)程,其實(shí)也是類似的,我們的后臺(tái)服務(wù)器分為了版本管理的服務(wù)器、資源服務(wù)器、游戲邏輯服務(wù)器。首先我們的游戲啟動(dòng)之后,第一次會(huì)帶著 自己的版本向我們的服務(wù)器版本去問(wèn),就是我現(xiàn)在的版本號(hào)是一,最新的版本號(hào)是多少。如果沒(méi)有更新的話,后續(xù)它直接往游戲邏輯服務(wù)器發(fā)起后續(xù)的通信需求,但 是如果有更新的話,我們的版本服務(wù)器會(huì)告訴他最新的版本已經(jīng)到了2.0了,會(huì)返回一些需要更新的文件列表回來(lái),然后我們手機(jī)端就會(huì)從資源服務(wù)器把這些所有 需要的文件全部下載下來(lái),然后在自己這里實(shí)現(xiàn)一些資源的重載,整個(gè)腳本的一些Reload,接下來(lái)再往我們的服務(wù)器做通信的時(shí)候,就已經(jīng)變成一個(gè)最新的版 本了。
 我們?nèi)绻麑?shí)現(xiàn)了這種游戲自己更新的機(jī)制的話,我們就要考慮到一個(gè)問(wèn)題,就是我們客戶端上面的那些代碼文件和一些資源文件怎么去放。我們一個(gè)簡(jiǎn)單的想法就是 說(shuō),我們的游戲邏輯都是拿Lua實(shí)現(xiàn)的,我們的代碼可能就是直接放一個(gè)Lua文件在手機(jī)上面。它從V1更新到V2的話,我們就從資源服務(wù)器直接下載一份最 新的Lua文件把它覆蓋掉。但是這樣有一個(gè)問(wèn)題,我這個(gè)PPT里面其實(shí)有一些忽略,在我們的后臺(tái)有一些版本的管理系統(tǒng),我們對(duì)于每一個(gè)版本都有資源、后臺(tái) 代碼和數(shù)值的配置都是有保存的,我們隨時(shí)可以從后臺(tái)界面上去做切換,把我們的游戲升級(jí)到某一個(gè)版本,我們也支持游戲多版本的并存。比如說(shuō)我們開(kāi)發(fā)人員在測(cè) 一個(gè)版本,但是玩家玩的是另外一個(gè)版本,我們自己測(cè)試好之后再切換上線。所以我們一套東西之后,你就會(huì)考慮到一個(gè)問(wèn)題,就是說(shuō)假設(shè)我們測(cè)試不夠充分,一個(gè) 版本放出去之后,你可能突然發(fā)現(xiàn)一個(gè)重大的Bug,你可能要么給它進(jìn)行修復(fù),如果很快的找不到解決辦法,你只能馬上把版本回復(fù)回去。第一種方式就是說(shuō),如 果客戶端只放一個(gè)版本的話,我的回滾希望更快,就是說(shuō)代碼在之前,唯一的代碼在你手上實(shí)際上是有的,希望服務(wù)器返回某一個(gè)狀態(tài),你立刻自己就能夠切回到 V1的版本上去,而不需要重新把那些代碼再重新Download一遍。
 還有一個(gè)辦法就是每個(gè)版本都通過(guò)一個(gè)版本號(hào),比如說(shuō)這是我V1的版本,我增量后續(xù)更新的時(shí)候,可能會(huì)把V1先拷貝成V2,然后再去做增量更新。比如說(shuō)V1 到V2有哪些文件變了,比如有兩個(gè)文件,A.Lua或者是B.Lua,我可能會(huì)實(shí)現(xiàn)增量的更新,但是我的V1的B點(diǎn)Lua和V2的B點(diǎn)Lua實(shí)際上是沒(méi)有 變的,它們會(huì)占用額外的存儲(chǔ)空間,會(huì)有浪費(fèi)。所以我們最后的方案,也結(jié)合我們后臺(tái)的那套版本管理的系統(tǒng),就是實(shí)現(xiàn)的方案是把我們所有的資源和我們的腳本, 包括我們的數(shù)值配置,我們的腳本都算是一種資源,我們做md5重命名,通過(guò)在我們的手機(jī)端、游戲后臺(tái)、資源管理服務(wù)器都會(huì)有一個(gè)數(shù)據(jù)庫(kù)去管理這種每一個(gè)版 本下面所有的資源的映射關(guān)系,就是原始的文件名和最后打包之后會(huì)存下來(lái),每一個(gè)版本都會(huì)存下來(lái)。接下來(lái)真正游戲邏輯運(yùn)行起來(lái)之后,需要通過(guò)一個(gè)自定義的 Lua Loader去查找這些文件。
 這是我們打包的流程,首先會(huì)打包的時(shí)候把這些文件算一個(gè)碼然后進(jìn)行重命名,同時(shí)會(huì)生成一個(gè)資源的數(shù)據(jù)庫(kù),接下來(lái)把這些資源的數(shù)據(jù)庫(kù)和腳本文件放到這個(gè)包里 面去。然后游戲邏輯里面,比如說(shuō)我們的Lua代碼去裝載一個(gè)文件的話,語(yǔ)法就是Require一個(gè)A,就會(huì)去查找A.Lua這個(gè)文件。我們現(xiàn)在面臨的問(wèn)題 就是,這個(gè)A.Lua實(shí)際上已經(jīng)不存在了,我們已經(jīng)重命名了,我們需要有一個(gè)機(jī)制,讓Lua再去Require這個(gè)A的時(shí)候要找到一個(gè)文件,所以我們需要 自己實(shí)現(xiàn)一個(gè)Lua  Loader,實(shí)際上Lua那個(gè)引擎里面是有相應(yīng)的方法的,我們可以在那個(gè)引擎里面注冊(cè)一個(gè)自己的Loader,在它被觸發(fā)之后,首先根據(jù)我們要裝載的文 件,比如說(shuō)A,在我們的List里面去查這個(gè)文件真實(shí)的文件名是什么。比如說(shuō)我們的客戶端現(xiàn)在是V1的版本,它去V1的里面去查到的文件是這個(gè),那么他可 能就會(huì)最終度曲的文件就是這個(gè)文件,再最終通過(guò)Lua的Loadbuffer這個(gè)函數(shù)轉(zhuǎn)進(jìn)來(lái),再走后續(xù)的流程。如果是V2的版本,就找到另外一個(gè)文件,最 終回進(jìn)入到這個(gè)Loadbuffer當(dāng)中來(lái)。這樣的話,我們?cè)谡麄€(gè)游戲邏輯里面有一個(gè)變量去標(biāo)識(shí)當(dāng)前客戶端的版本是1還是2,但是實(shí)際上他們版本1和版本 2的代碼可能都會(huì)在我們的手機(jī)上有,可以很快速的去切換。像我們一個(gè)沒(méi)有變化的B點(diǎn)Lua,就以我們剛才提到的這種方式去實(shí)現(xiàn)的話,他們查的話是不同的, 但是找到的文件是同一個(gè)。
 接下來(lái)大家就會(huì)想到,游戲邏輯如果去用腳本實(shí)現(xiàn)的話,那你的代碼怎么加密?像JS一般有混淆器。但是這種方式總之還是能有人去反編譯的,如果我們有一些比 較核心的業(yè)務(wù)邏輯放在前端的代碼里面,我們不希望被別人很輕易的看到。其實(shí)我們?nèi)绻诖虬鞒坍?dāng)中已經(jīng)做了這些事情,我們已經(jīng)有了自己自定義的Lua Loader的話,加解密這個(gè)事情就很容易做了,我們?cè)诖虬倪^(guò)程當(dāng)中,在重命名之前做一次加密的操作,然后在我們的游戲邏輯運(yùn)行起來(lái)之后,我們?cè)侔岩粋€(gè) 文件的內(nèi)容讀出來(lái)之后,再去調(diào)用Loadbuffer再去做加密就OK了。
 我們用這種方式去管理腳本和資源之后,這個(gè)文件就會(huì)有一個(gè)問(wèn)題,就是說(shuō)我們整個(gè)代碼可能有70多個(gè)Lua文件,有200多個(gè)配置文件,這些文件如果以文本 的方式去加密之后,APK的安裝包和IPK的安裝包都是最基礎(chǔ)的安裝包,這些文件在加密之后你再去壓縮沒(méi)有壓抑的,因?yàn)榧用苤蠖M(jìn)制流是沒(méi)有規(guī)則的,你 用Zip去壓是是沒(méi)有任何意義的,帶來(lái)的問(wèn)題就是安裝包體積會(huì)變大。還有一個(gè)需要考慮的就是說(shuō),我們這種增加一個(gè)加解密的環(huán)節(jié),對(duì)于我們游戲運(yùn)行起來(lái)的時(shí) 候會(huì)有什么性能的影響?所以我們做了一些改進(jìn)。就是說(shuō)其實(shí)這個(gè)想法也挺簡(jiǎn)單的,就是說(shuō)你加密之前先把文件壓縮了再加密,這個(gè)事情直接就讓這個(gè)加密對(duì)于壓縮 這個(gè)影響已經(jīng)完全沒(méi)有了,你先壓縮再加密的話,本身這個(gè)文件就已經(jīng)比較小了。在我們游戲運(yùn)行的時(shí)候,把它先在我們的Lua Loader里面先解密,再解壓,然后再調(diào)用Loadbuffer這個(gè)函數(shù)。
 我們做一些對(duì)比,剛才提到了我們的安裝包如果直接使用的話,這個(gè)圖(PPT)有三列,第一列是我們的原始文件,我們的文件是一個(gè)Zip格式,在安裝包里面 的大小可能就是1.5M,如果我們把配置文件和腳本去做加密處理的話,然后再放到我們的安裝包里面去,它就變大到8M,就是整個(gè)安裝包就大了不少。但是如 果我們后面再通過(guò)第三種方式,就是先壓縮再加密這種方式的話,安裝包的體積可能比以前的原始文件直接放進(jìn)去稍微大一點(diǎn)點(diǎn),基本上大不了多少。所以這樣的 話,壓縮、加密這種對(duì)于游戲安裝包的影響就已經(jīng)可以完全沒(méi)有了。
 我們對(duì)比了一下這些腳本通過(guò)處理之后,它在游戲運(yùn)行時(shí)對(duì)于性能的一些影響。因?yàn)槲覀兊挠螒蜻壿嬤\(yùn)行起來(lái)的時(shí)候最開(kāi)始的啟動(dòng)階段可能是Require一些少 量的腳本,真正進(jìn)入游戲的時(shí)候,因?yàn)槲覀僉ua內(nèi)存一些框架的實(shí)現(xiàn)原因,我們是需要幾乎把所有的Lua代碼都要裝載進(jìn)來(lái),所以你一次性的去裝載700多個(gè) Lua文件的話,實(shí)際上是有一些性能的問(wèn)題,實(shí)際上會(huì)使你的裝載時(shí)間變長(zhǎng),就是在這種加密的方式下。但是對(duì)于我這一列后面列的第三種方式,就是說(shuō)壓縮和加 密的方式下,實(shí)際上加載的時(shí)間又會(huì)降下來(lái)。所以可能大家就會(huì)困惑,為什么我只加密裝載時(shí)間變長(zhǎng)了,但是我加了一個(gè)壓縮再加密,我運(yùn)行的時(shí)候先解密再解壓, 裝載時(shí)間反而會(huì)降下來(lái)了呢?這張圖就是說(shuō)明了這個(gè)原因,大家可以對(duì)比一下。我的Lua文件裝載實(shí)際上是分了好幾個(gè)階段,可能有先讀取文件的內(nèi)容,然后有解 密,有解壓縮的過(guò)程,就是三個(gè)顏色代表了。對(duì)于原始文件,如果我們直接放到安裝包的話,直接讀原始文件就可以了,只要是能讀出來(lái),不需要解密和解壓縮,總 共1千個(gè)文件,我們腳本和配置文件夾都放進(jìn)來(lái)的話。如果只加密的話,讀文件裝載時(shí)間可能少一點(diǎn)點(diǎn),這個(gè)可能是測(cè)試的一些偏差了,正常來(lái)說(shuō)應(yīng)該是差不多的, 可能還需要另外一半的時(shí)間去做解密的操作。但是如果文件壓縮之后再加密的話,在我們運(yùn)行的時(shí)候先把它讀出來(lái),讀出來(lái)的時(shí)間因?yàn)楸旧韷嚎s之后那個(gè)文件會(huì)很 小,就是它讀出來(lái)之后,第一次裝載內(nèi)存的Buffer是比較小的,裝載的時(shí)間其實(shí)比原始的文件還要小一點(diǎn),接下來(lái)解密時(shí)間也會(huì)變得小很多,因?yàn)槲募拇笮?也小了很多,所以解密耗的時(shí)間也會(huì)比較少。最終解壓縮的時(shí)間,我們測(cè)試的時(shí)間上是很少的。
 前面提到的都是我們?cè)趇OS上做的一些性能的對(duì)比。到Android上我們就發(fā)現(xiàn)了另外一個(gè)問(wèn)題,這個(gè)圖里面藍(lán)色的線就是iOS上所有的腳本和配置文件的 加載時(shí)間,基本上就是都很小,慢的也就是2秒,快的可能也就是不到1秒的時(shí)間。跑到Android上就變得很夸張,游戲可能進(jìn)去之后開(kāi)始有一點(diǎn)轉(zhuǎn)圈,然后 過(guò)了快10秒鐘才會(huì)把一些界面裝載進(jìn)來(lái)。不管是放原始文件還是放加密的文件還是壓縮加密的這種文件,我們放到APP里面之后再去直接裝載的話就發(fā)現(xiàn)性能有 很大的問(wèn)題。我們看了一下為什么會(huì)有這種問(wèn)題?我們就發(fā)現(xiàn)在Android上面你直接從SD卡讀一個(gè)文件和直接從APK里面讀一個(gè)文件實(shí)際上是有相當(dāng)大的 差異的。其實(shí)對(duì)于單個(gè)文件來(lái)說(shuō),如果運(yùn)行時(shí)只是裝載一個(gè)文件,從SD卡上讀耗的時(shí)間可能是一毫秒,從APK里面去讀耗的時(shí)間是十毫秒。對(duì)于一個(gè)文件來(lái)說(shuō), 其實(shí)這個(gè)時(shí)間幾乎沒(méi)有什么關(guān)系。但是如果你一次裝載1千個(gè)文件出來(lái)的話,這個(gè)10倍的差距就會(huì)放大到比較明顯的一個(gè)程度。所以針對(duì)這種情況,我們?cè)?Android上面就增加了一個(gè)環(huán)節(jié),就是我們游戲安裝完第一次啟動(dòng)的時(shí)候,需要有一個(gè)解開(kāi)我們資源和配置文件的過(guò)程。像iOS上就不需要這樣的過(guò)程,因 為iOS上本身安裝包裝進(jìn)去之后就是一個(gè)展開(kāi)的狀態(tài),不像APK,安裝完了之后就是放在手機(jī)的RAM里面。
 我們對(duì)于這種展開(kāi)之后,你再去放到SD卡上后面去運(yùn)行我們游戲的話可以看到,一個(gè)淺藍(lán)色的線就是從Android上,如果從SD卡去加載我們的配置文件和 腳本的話,時(shí)間就跟iOS上的加載時(shí)間差不多了,比直接從APP里面加載要好很多,剛才提到的是我們的版本管理的一些經(jīng)驗(yàn)。接下來(lái)就是我們用Lua在開(kāi)發(fā) 商利用它的一些靈活性,利用一些豐富的接口,我們?nèi)プ鲆恍┹o助我們定位問(wèn)題和幫助我們加快開(kāi)發(fā)速度的一些方法。在調(diào)用我們Lua的時(shí)候,在Lua引擎的文 件里面,會(huì)調(diào)一個(gè)Lua的函數(shù),或者是執(zhí)行一個(gè)Lua的文件,最終的調(diào)用方式都是通過(guò)Lua Pcall這個(gè)方法,它的文檔里面其實(shí)第四個(gè)字段是一個(gè)Message Handle,這個(gè)Lua的Pcall接下來(lái)如果在執(zhí)行Lua代碼的時(shí)候如果出錯(cuò)了,如果我有設(shè)置這個(gè)Messager handler的話,我會(huì)通過(guò)這個(gè)去處置我的異常。我不知道現(xiàn)在引擎有沒(méi)有這個(gè)問(wèn)題,實(shí)際上以前在Pcall的時(shí)候是沒(méi)有做這種錯(cuò)誤處理的,第四個(gè)參數(shù)都 是直接填的,如果我們自己定位一個(gè)Message Handle,我們可以運(yùn)行一個(gè)詳細(xì)的錯(cuò)誤的堆棧,我們開(kāi)發(fā)的時(shí)候,可以選擇把這個(gè)堆棧彈放出來(lái),開(kāi)發(fā)人員可能在模擬器上調(diào)試的時(shí)候,如果出現(xiàn)什么錯(cuò)誤就 可以直接把這個(gè)錯(cuò)誤彈出來(lái)了。在我們發(fā)布之后,我們游戲畢竟不能保證百分之百?zèng)]有Bug,如果運(yùn)行的時(shí)候出現(xiàn)一些錯(cuò)誤,我們能夠把這些邏輯信息捕獲,上傳 到我們的日志服務(wù)器里面去。Lua還有一個(gè)好處,一般來(lái)說(shuō)一個(gè)掛掉了之后,可能只是影響當(dāng)時(shí)的那一次調(diào)用,一般不會(huì)讓你的游戲直接崩潰掉。
 比如說(shuō)我們實(shí)現(xiàn)了一個(gè)自己的錯(cuò)誤的Handle,這個(gè)例子就是我們?nèi)ジ脑霤CLua文件里面一個(gè)執(zhí)行Global的一個(gè)例子,紅色的三項(xiàng)是我們自己加上去 的,如果你有1G的Handle,你首先要Psuh到State上去,在最終調(diào)用的時(shí)候,-1就是你馬上要執(zhí)行的那個(gè)Global的指針,-2就是我們自 己的Message Handle。在這個(gè)Message Handle里面的實(shí)現(xiàn),實(shí)際上主要是用到了Lua的一個(gè)方法,他們可以取得運(yùn)行時(shí)的信息,就是堆棧和一些調(diào)用的腳本名稱和行號(hào)什么的。這是我們通過(guò)自己 定義的Hanlle可以捕獲的一些錯(cuò)誤異常,第一行是我們Lua錯(cuò)誤的Message,下面是Lua錯(cuò)誤的堆棧信息。我們通過(guò)這些東西很容易看到究竟是哪 個(gè)模塊,哪個(gè)文件的哪一行出了什么問(wèn)題,有堆棧的話也很容易看出,為什么它會(huì)在這些行出現(xiàn)這樣的錯(cuò)誤。
 剛才凌聰也提到了Lua跟Java跟iOS去做交互的時(shí)候有一些比較惡心的東西,他們有的通過(guò)自己的方式實(shí)現(xiàn),我們也有自己的一些小的技巧。一些常用的方 式,如果我們有一些Java和Object的接口的話,我們會(huì)通過(guò)C++導(dǎo)出給Lua用。這樣的問(wèn)題,尤其是一些像我們的iOS和Java需要有一次 C++的封裝其實(shí)就有開(kāi)發(fā)量。再有就是這種接口比較固定的還好,比如說(shuō)加解密這種可能實(shí)現(xiàn)一次就OK了。后來(lái)你再去做SDK介入的時(shí)候你會(huì)發(fā)現(xiàn)每一個(gè)渠道 都不太一樣,你很難做出一個(gè)比較通用的接口暴露給Lua,如果按照之前的這種Tolua++的方式去做的話就很麻煩。比如說(shuō)我在Java這一層實(shí)現(xiàn)打開(kāi)一 個(gè)網(wǎng)址的功能,可能先在Java里面要實(shí)現(xiàn)一個(gè)OPenUrl的函數(shù),在C++這邊也要實(shí)現(xiàn)一個(gè)OperUrl的函數(shù),去調(diào)用Java的代碼,再用 Tolua++這個(gè)導(dǎo)出,再去調(diào)用這個(gè)函數(shù)。JNI調(diào)用的代碼說(shuō)實(shí)話,我的感覺(jué)很惡心,很容易寫(xiě)出Bug,如果這個(gè)字段改成份了,需要修改的參數(shù)就很大, 需要改很多地方。Java這一層要改,C++和Lua都要改。我們的技巧就是對(duì)于一些性能要求不高的封口上,我們就安裝一個(gè)doAction這個(gè)函數(shù),在 Lua層,就去調(diào)用不管是C還是Object C還是Java的接口的時(shí)候,可能就是調(diào)這個(gè)接口。我們?cè)贑里面去實(shí)現(xiàn)一個(gè)調(diào)度,就是在C里面,我們這個(gè)Tring里面一般會(huì)有一個(gè)Action的字段, 我們?cè)贑這里面出現(xiàn)相應(yīng)的處理,可能也都會(huì)在這個(gè)Tring里面去做,在Java這邊,首先通過(guò)JNI的調(diào)用,調(diào)到一個(gè)Java的 PlatformTool里面,我們通過(guò)這種封裝之后,在Lua這一層去大概一個(gè)網(wǎng)址,我可能在Lua的代碼里面就會(huì)這么寫(xiě),首先會(huì)把我的參數(shù),比如說(shuō) Action是UIO,需要變成一個(gè)串,然后再傳給這個(gè)doAction的方法。這樣的好處就是說(shuō),我的交互,基本上第一次寫(xiě)好這個(gè)doAction之后 就不用變了,我依然要在OC或者是Java這里去實(shí)現(xiàn)我的業(yè)務(wù)代碼,不需要考慮在C這一層怎么做中間的角度。調(diào)用方式也變得比較一致了,接口后面如果發(fā)生 一些變化的話,修改量也會(huì)比之前的方式小很多。
 上面就是我們?cè)谟螒蜷_(kāi)發(fā)過(guò)程當(dāng)中對(duì)于版本更新、代碼加密、錯(cuò)誤檢查和接口封裝方面的一些經(jīng)驗(yàn)。很高興今天能在這里跟大家分享這些內(nèi)容,歡迎大家能有一些技 術(shù)上的交流。我這邊廣告準(zhǔn)備得不充分,我們也是最近招各種各樣的人,包括技術(shù)、策劃和美術(shù),我們都?xì)g迎大家來(lái)加入我們,去年這個(gè)時(shí)候我們可能就是一個(gè)很成 長(zhǎng)中的團(tuán)隊(duì)了,我們也面臨著很多的機(jī)遇和挑戰(zhàn),大家有興趣的話歡迎來(lái)聯(lián)系我。
 
 
 主持人:技術(shù)分會(huì)場(chǎng)的議程到現(xiàn)在就全部結(jié)束了,感謝各位的光臨,下次大會(huì)再見(jiàn)!
 |