9.Quick-cocos2dx热更新客户端实现
2017-07-15 本文已影响52人
会写诗的翩翩少年
0.前言
本文介绍的是热更新客户端实现,本文的阅读可结合上文,热更新的客户端实现大致分为以下几个步骤:
1.修改资源搜索路径,使热更之后,游戏能优先加载热更资源
2.加载本地资源清单Reslist
3.请求远程资源清单替换本地资源清单
4.对照资源清单检查本地资源,有的则在清单中标记,没有的则删除
5.请求资源清单中未标记的资源
6.加载资源清单中的代码资源
7.热更结束,回调主逻辑
1.使用方式
local CCHotFix = require("app.scenes.CCHotFix")
CCHotFix.new(handler(self, function(self)
end))
2.代码阅读
代码很简单,注释很清晰,阅读建议就是将代码拷贝至sublime(个人感觉看着舒服一些),逐行阅读,开始吧!
require("lfs")
local CCHotFix = class("CCHotFix")
--游戏版本号
VERSION_C_GAME = 1
--资源清单名
local NAME_C_RES_LIST = "ResList"
--服务器路径
local PATH_C_SERVER_URL = "ftp://localhost/"
--资源路径
local PATH_C_HOTFIX_RES = device.writablePath .. "upd/Res/"
--临时资源路径
local PATH_C_HOTFIX_RES_TMP = device.writablePath .. "upd/ResTmp/"
--资源清单路径
local PATH_C_HOTFIX_RES_LIST = device.writablePath .. "upd/" .. NAME_C_RES_LIST
function CCHotFix:ctor(onComplete)
--热更结束的回调
self.onComplete = onComplete
--资源文件夹创建
cc.FileUtils:getInstance():createDirectory(PATH_C_HOTFIX_RES)
cc.FileUtils:getInstance():createDirectory(PATH_C_HOTFIX_RES_TMP)
--修改资源搜索路径
cc.FileUtils:getInstance():addSearchPath(PATH_C_HOTFIX_RES)
cc.FileUtils:getInstance():addSearchPath("res/")
--检测是否存在资源清单
if cc.FileUtils:getInstance():isFileExist(PATH_C_HOTFIX_LIST) then
self.ResList = dofile(PATH_C_HOTFIX_RES_LIST)
VERSION_C_GAME = self.ResList.ver
end
--请求服务器上的资源清单
self:requestResList()
end
--从服务器请求文件
function CCHotFix:requestFileFromServer(url, succ, err)
local url = PATH_C_SERVER_URL .. url
local request = network.createHTTPRequest(function(event)
if event.name == "completed" then
local rscode = event.request:getResponseStatusCode()
if rscode == 226 then
succ(event.request:getResponseData())
else
err()
end
elseif event.name == "progress" then
else
err()
end
end, url, "GET")
request:setTimeout(15)
request:start()
end
--遍历路径
function CCHotFix:traversePath(rootpath, func)
for entry in lfs.dir(rootpath) do
if entry ~= '.' and entry ~= '..' then
local path = rootpath .. '\\' .. entry
local attr = lfs.attributes(path)
assert(type(attr) == 'table')
if attr.mode == 'directory' then
self:traversePath(path)
else
func(path)
end
end
end
end
--请求资源列表
function CCHotFix:requestResList()
self:requestFileFromServer(NAME_C_RES_LIST,
handler(self, function(self, data)
--请求成功后,将其写入本地路径,并加载
io.writefile(PATH_C_HOTFIX_RES_LIST, data, "wb+")
self.ResList = dofile(PATH_C_HOTFIX_RES_LIST)
--根据资源清单对本地资源进行检测
self:checkUpdRes()
end),
handler(self, function(self)
--本地和服务器都无资源清单
if not self.ResList then
self.onComplete()
else --本地有,远程请求失败的情况
self:checkUpdRes()
end
end))
end
function CCHotFix:checkUpdRes()
--遍历本地资源路径
self:traversePath(PATH_C_HOTFIX_RES, handler(self, function(self, path)
local keep = false
local md5 = string.lower(crypto.md5file(path))
--检测该文件的md5是否存在于资源清单
for i, v in ipairs(self.ResList.stage) do
if string.lower(v.code) == md5 then
local arr = string.split(path, "/")
local name = table.remove(arr, #arr)
local path = table.concat(arr, "/") .. "/"
if name ~= v.name then --与资源清单上的名字不同则重命名
cc.FileUtils:getInstance():renameFile(path, name, v.name)
end
--存在则标记资源清单
v.fileCheck = true
keep = true
break
end
end
--该文件不存在于资源清单,则删除该文件
if not keep then
cc.FileUtils:getInstance():removeFile(path)
end
end))
--请求资源清单上未标记的资源
self:requestUncheckRes()
end
function CCHotFix:requestUncheckRes()
--将未标记资源写入对象存储
self.uncheckRes = {}
for i, v in ipairs(self.ResList.stage) do
if not v.fileCheck then
table.insert(self.uncheckRes, v.code)
end
end
--一次下载一个资源文件
self.downloadNext = function(self)
local path = table.remove(self.uncheckRes)
if path then
self:requestFileFromServer(path,
handler(self, function(self, data)
--请求成功后,写入tmp路径
io.writefile(PATH_C_HOTFIX_RES_TMP .. path, data, "wb+")
self:downloadNext()
end),
handler(self, function(self)
print("请求资源失败,热更新停止")
cc.FileUtils:getInstance():removeDirectory(PATH_C_HOTFIX_RES_TMP)
self.onComplete()
end))
else
print("下载完毕")
self:movTmpRes()
end
end
self:downloadNext()
end
--将tmp路径下的资源写入正式路径下
function CCHotFix:movTmpRes()
for i, v in ipairs(self.ResList.stage) do
if not v.fileCheck then
v.fileCheck = true
os.rename(PATH_C_HOTFIX_RES_TMP .. v.code, PATH_C_HOTFIX_RES .. v.name)
end
end
self:loadZip()
end
--加载热更下来的代码资源
function CCHotFix:loadZip()
for i, v in ipairs(self.ResList.stage) do
if v.act == "load" then
cc.LuaLoadChunksFromZIP(PATH_C_HOTFIX_RES .. v.name)
end
end
VERSION_C_GAME = self.ResList.ver
self.onComplete()
end
return CCHotFix