文章出處

圖片來自網絡

 

思緒何來


昨天寫了一篇關于更新方案的理論 游戲開發:通過路徑搜索優先級來進行補丁升級(從端游到手游) 今天繼續細化一下

由于新項目采用的是Quick-cocos2d-x,那我就直接給出我基于Quick-cocos2d-x-master( > 2.2.3 rc) 的更新方案吧

 

此更新方案要解決以下幾個問題


一、資源、代碼在線更新

二、framework、update模塊自更新

三、玩家安裝新版本后,減少不必要的更新

四、更新中斷的處理

五、Quick-cocos2d-x中,遇上的問題

做到上面幾點后,我覺得整個更新方案應該沒有大問題了。

 

服務器與安裝包內容


在說更新流程前,我先說說安裝包的內容

首先,我們這里會涉及一個大版本號,大版本號的意思,就是C++部分的版本號,如果有變動,這個版本號才會動。 以提示用戶去APPSTORE下載新的版本

其余的版本號,只是一個顯示版本號,可以根據游戲內容來區分。

每一個安裝包本身,包含了所有游戲資源。即一個新版本發布后,玩家是不需要更新的。點開即玩。

安裝包內部帶了一個文件列表,內容如下

local flist = {
  core = 1
  version = "1.0.1"
  update_md5 = "xxxxxx"
 framework_md5 = "xxxxxx"
files = { {path="ui/shop/shop_close_btn.png",md5="xxxxxx",size="30"}, {path="ui/army/army_tip.png",md5="xxxxxx",size="20"} } }
return flist

這是一個LUA文件,之所以使用LUA文件,是為了在LUA中使用dofile方便讀取。而files里面,列出了所有包內的文件。 core就是我們剛剛提到的大版本號。

上面的 path,是相對于res的路徑,且帶完整目錄和文件后綴

 

資源服務器上也有一份同樣的資源列表,服務器和安裝包中的結構如下

res/flist 資源列表

res/update.bin 這個是update模塊自己的打包

res/framework.bin這個是quick-framework的打包

res/game.bin這個是游戲邏輯的打包

res/.....  其它游戲資源

 

更新流程


更新流程大致如下

1、從服務器取得版本列表(flist)

2、檢查update的md5值,看是否有更新,如果有更新,則下載update.bin,重新載入,并退到main(退出之前,注意清除對某些的引用),再次重新進入

3、檢查framework的md5值,看是否有更新,如果有更新,則下載framework.bin,并提示用戶重新啟動

4、讀取本地安裝目錄的版本列表文件(flist)

5、比對服務器版本列表和本地安裝目錄列表中的大版本號,如果大版本號不一樣,則提示用戶去APPSTORE上下載。

6、讀取upd目錄的版本列表文件(flist),如果flist文件不存在,或者flist中存放的core與安裝目錄列表中的不一致(表示用戶安裝了新版本),則清除整個upd目錄,并將本地安裝目錄的flist內容,寫入upd目錄

7、對比服務器列表與本地列表中的version(由上一步可以得到),如果version相同,則認為數據是不需要更新的

8、如果version不同,則與服務器的flist對行md5差異對比,得到需要更新的文件

9、遍歷需要更新的文件列表,若upd存在,則效驗其MD5值,如果MD5值與服務器的相同,則從待更新列表中移除(這一步,是為了應對上一次更新過程中,玩家中途退出的情況)

10、逐個更新文件,每個文件更新完畢后,再次效驗其MD5碼,如果MD5碼效驗失敗,則重新下載此文件

11、待所有文件更新完畢,重寫upd文件中的flist

12、進入游戲

 

通過路徑搜索實現資源更新


資源的下載是OK了,我們如何來做更新呢,如何能夠使程序加載到正確的資源。為了正確更新資源,我們可以通過路徑搜索來實現

--add update path

CCFileUtils:sharedFileUtils():addSearchPath(device.writablePath.."upd/")

--add res path for install

CCFileUtils:sharedFileUtils():addSearchPath("res/")

 

假設device.writablePath的目錄是 /data/data/com.ooxx.game1/  那,第一個目錄就是/data/data/com.ooxx.game1/upd/ 第二個目錄是 res/

在ANDROID和IOS上,如果它檢查是以 / 開頭的,則認為是絕對路徑,直接與文件名合并,生成對應的完整路徑

如果不是以 / 開頭的,那在IOS上的工作原理和WINDOWS一個樣,在ANDROID上,他會先檢查是否以assets開頭,如果不是,則強加上 "assets/" 并去APK里面搜索

總之,上面的兩個路徑,是在任何地方都適合的。

以上就是我綜合了陽光七月,yezehui200,GcvqrNq等人的更新方案而得出的自己的更新流程,上面的流程,幾乎解決了本文開頭就提出的問題。

 

實現過程中遇到的問題


下面我來說說我在實現這一方案中,遇上的問題

問題一

執行安裝目錄中的flist. 因為dofile會認一個絕對路徑,我在WINDOWS上是很OK的,但是在ANDROID上死活都不行,即使我硬編碼 dofile("assets/res/flist") 其原因是因為,在ANDROID上,讀取資源是從APK壓縮包中讀取的。

后來我只有通過一個比較矬的方法來優美地解決 就是使用CCFileUtils:sharedFileUtils:getFileData(“res/flist”) ,將得到的數據寫入存儲卡上,再dofile

由于upd目錄下是沒有res文件夾的,因此,我們可以保證,這貨取得的肯定是安裝包下的文件路徑。 這樣就解決了dofile在ANDROID上的問題。

而要想取安裝上下的資源,就只能像這樣 dofile(device.writablePath.."upd/flist")

總之,在添加了多路徑搜索后,對路徑的使用就要格外小心。

問題二

我在測試crypto.md5file的時候,發現,在ANDROID上,如果我們要取一個APK中的文件時,是會失敗的,原因就是在C++實現里,它使用了fopen來打開文件,這在ANDROID上是做不到讀取APK中文件的。 好在這個需求不需要了。

問題三

由于沒有使用AssetManager,因此,目前還沒有實現單個文件的進度條,到時候可能會參考一下AssetManager的實現

問題四

目錄創建問題, 比如 ui/shop/ 我們直接使用 lfs.mkdir(device.writablePath.."upd/ui/shop/) 是不會成功的,需要一級級向下創建,目前沒有找到一次性搞定的方案,說不定使用os.execute的mkdir帶參數,可以搞定

咦,遞歸創建目錄的方法找到了
windows下直接 os.execute("mkdir ooxx\\ooxx\\ooxx\\ooxx")
ios,android,mac,linux下,直接 os.execute("mkdir -p ooxx/ooxx/ooxx/ooxx")

 

測試資源服務器搭建


測試資源服務器最簡單的方法,就是網上下載一個nginx,解壓,解壓后,找到html目錄,把資源扔進去,點nginx.exe啟動,瀏覽器輸入127.0.0.1,你會發現welcome nginx 輸入127.0.0.1/1.png (假設你html目錄下有這個圖片),你會在瀏覽器里看到圖片。

剩下的,就愛怎么整怎么整了。

PS:如果是手機測試,最好是把內網的防火墻關了,否則連接不上。

 

結語


熱更新對于手機網絡游戲研發來說,已經是一項不可或缺的特性。Quick-Cocos2d-x為我們提供了一個可以在純LUA環境中開發項目的能力。但是,熱更新的解決方案需要針對不同的項目需求進行調整,不可一概而論。 我想這也是為什么Quick-Cocos2dx只提供了一個update的DEMO,而并未將其作為框架特性的原因吧。

本文中實現的方案,也僅僅是初試。并未經過大量的項目驗證,因此肯定會有許多不妥之處。大家使用過程中,如果有發現問題,請及時反饋。

 


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()