quick-cocos2d之动态更新
1.创建一个UpdateScene.lua 作为你的更新模块。
require("config")
require("framework.init")
require("datastore")
require("framework.cc.init")
local UpdateScene =class("UpdateScene",
function()
returndisplay.newScene(UpdateScene)
end)
local server ="http://192.168.3.2/" --192.168.3.2
local versionFile = "version/version"
local allFileList = "version/V"
local nowVersion = nil -- 当前版本号
local bigVersion = nil -- 服务器最大的版本号
function UpdateScene:ctor()
DataStore:init()
self.mIsHandover = false -- 控制noUpdateStart只回调一次
self.needRestart = false -- 是否需要重启
self.needDownload = false -- 是否需要下载
self.path =device.writablePath
self:createDownPath(self.path)
self:createDownPath(self.path.."res/")
self:createDownPath(self.path.."src/")
--把当前的版本号从本地取出来
nowVersion =self:getVersion("nowVersion")
ifnowVersion == nil or nowVersion == "" then
nowVersion = Config.gameVersion
end
self.progressLabel = display.newTTFLabel({
text = "您好,世界",
font = "Arial",
size = 35,
color = cc.c3b(255,0),-- 使用纯红色
align = cc.TEXT_ALIGNMENT_LEFT,
valign = cc.VERTICAL_TEXT_ALIGNMENT_CENTER,
dimensions = cc.size(400,200)
}):pos(display.cx,display.cy):addTo(self)
self.progressLabel:setString("更新.....")
end
--根据服务器取出来的版本文件加载要更新的资源
functionUpdateScene:downIndexedVersion()
if self.needDownload then --需要重新下载apk
--apk 下载链接
return
end
if not self.nowDownIndex then
self.nowDownIndex = 1
end
local versionUrl =server..versionFile..self.needDownVersions[self.nowDownIndex].version..
"."..self.needDownVersions[self.nowDownIndex].id
local packageUrl =self.needDownVersions[self.nowDownIndex].fileUrl
if self.nowDownIndex == 1 then
self.assetsManager =cc.AssetsManager:new(packageUrl,versionUrl,self.path) --资源包路径,版本号路径,下载好的资源存储路径
self.assetsManager:setDelegate(handler(self,self.onSuccess),cc.ASSETSMANAGER_PROTOCOL_SUCCESS )—设置加载完成的回调函数
self.assetsManager:setDelegate(handler(self,self.onProgress),cc.ASSETSMANAGER_PROTOCOL_PROGRESS ) —设置加载进度的回调函数
self.assetsManager:setDelegate(handler(self,self.onError),cc.ASSETSMANAGER_PROTOCOL_ERROR ) —设置加载出现错误的回调函数
self.assetsManager:retain()
else
self.assetsManager:setVersionFileUrl(versionUrl)
self.assetsManager:setPackageUrl(packageUrl)
end
if self.assetsManager:checkUpdate() then
self.assetsManager:update()
end
end
--从服务器获取最新版本号
functionUpdateScene:getNewestVersion()
function callback(event)
local ok = (event.name == "completed")
local request = event.request
if event.name then
self.progressLabel1:setString("requestevent.name = " .. event.name)
print("request event.name = " ..event.name)
end
if not ok then
self.progressLabel1:setString("请求失败"..request:getErrorMessage())
print("请求失败"..request:getErrorMessage())
--self:pro
self:performWithDelay(
function ()
self:noUpdateStart()
end,2)
return
end
local code = request:getResponseStatusCode()
if code ~= 200 then
print("请求错误,代码"..request:getResponseStatusCode())
self:performWithDelay(
function ()
self:noUpdateStart()
end,2)
return
end
if json.decode(request:getResponseString()) then
print(request:getResponseString())
local needDownVersions =json.decode(request:getResponseString())
if needDownVersions.code == 200 then
if needDownVersions.needRestart > 0 then
self.needRestart = true
end
ifneedDownVersions.needDownload > 0 then
self.needDownload = true
end
self.needDownVersions =needDownVersions.list
--版本号判断 是否已经是最新的
if needDownVersions.bigVersion == nowVersionthen
self.progressLabel:setString("已经是-----最新的版本")
self:performWithDelay(
function ()
self:noUpdateStart()
end,1)
return
end
--版本号更换,并存储到本地
nowVersion = needDownVersions.bigVersion
self:setVersion("nowVersion",nowVersion,true)
if #self.needDownVersions > 0 then
self:downIndexedVersion()
end
else
self.progressLabel:setString("当前版本已经是最新版本")
self:performWithDelay(
function ()
self:noUpdateStart()
end,2)
end
end
end
--请求得到最新的版本号数据 回调函数callback
local request = network.createHTTPRequest(callback,server..allFileList,"GET")
request:setTimeout(10)
request:start()
end
--进入场景后开始更新判断
function UpdateScene:onEnter()
self:getNewestVersion()
end
--更新成功之后,启动游戏
function UpdateScene:afterUpdateStart()
if self.needRestart then
print("提示需要重新启动游戏")
local game = require("game")
game.exit();
return
end
Config.gameVersion = nowVersion
self.progressLabel:setString("更新成功,启动游戏 ")
local game = require("game")
game.startup();
end
--不有更新(或者没有成功)直接开始
functionUpdateScene:noUpdateStart()
if self.mIsHandover == true then
return
end
self.mIsHandover = true
Config.gameVersion = nowVersion
self.progressLabel:setString("没有更新或者更新失败启动游戏")
local game = require("game")
game.startup();
end
--更新错误回调
functionUpdateScene:onError(errorCode)
if errorCode == cc.ASSETSMANAGER_NETWORK then
text = "网络出错!"
end
if errorCode == cc.ASSETSMANAGER_NO_NEW_VERSION then
text = "没有新版本"
end
if errorCode == cc.ASSETSMANAGER_UNCOMPRESS then
text = "解压出错"
end
if errorCode == cc.ASSETSMANAGER_CREATE_FILE then
text = "未知错误"
end
print("text:",text)
self:performWithDelay(function ()
self:noUpdateStart()
end
--更新进度回调
function UpdateScene:onProgress( percent)
-- 显示下载进度
localprogress = string.format("downloading %d%%",percent)
print("progress:",progress)
end
-- 更新完成回调
function UpdateScene:onSuccess()
--每次更新可能有多个zip包,做下处理
if self.nowDownIndex < #self.needDownVersions then
self.nowDownIndex = self.nowDownIndex +1
self:downIndexedVersion()
else
-- "更新成功"
self:performWithDelay(function ()
self:afterUpdateStart()
end,2)
end
end
functionUpdateScene:createDownPath( path )
if not self:checkDirOK(path) then
print("更新目录创建失败,直接开始游戏")
self:noUpdateStart()
return
else
-- print("更新目录存在或创建成功")
end
end
--改变目录
function UpdateScene:checkDirOK(path )
require "lfs"
local oldpath = lfs.currentdir()
if lfs.chdir(path) then
lfs.chdir(oldpath)
return true
end
if lfs.mkdir(path) then
return true
end
end
--
functionUpdateScene:delAllFilesInDirectory( path )
for file in lfs.dir(path) do
if file ~= "." and file ~= ".."then
local f = path..'/'..file
local attr = lfs.attributes (f)
assert (type(attr) == "table")
if attr.mode == "directory" then
self:delAllFilesInDirectory(f)
else
os.remove(f)
end
end
end
end
string.startWith =function(str,strStart)
local a,_ = string.find(str,strStart)
return a==1
end
string.split = function(s,p)
local rt= {}
string.gsub(s,'[^'..p..']+',function(w)table.insert(rt,w) end )
return rt
end
--版本号的本地存储
functionUpdateScene:setVersion(__key,__value,__isSave)
DataStore:setData(__key,__isSave)
end
functionUpdateScene:getVersion(__key)
return DataStore:getData( __key )
end
return UpdateScene
main.lua
local writablePath =cc.FileUtils:getInstance():getWritablePath().."assets/"
cc.FileUtils:getInstance():addSearchPath(writablePath.."res/")
cc.FileUtils:getInstance():addSearchPath("res/")
cc.FileUtils:getInstance():addSearchPath(writablePath.."res/sound")
cc.FileUtils:getInstance():addSearchPath("res/sound")
cc.FileUtils:getInstance():addSearchPath(writablePath.."src/")
cc.FileUtils:getInstance():addSearchPath("src/")
local function main()
package.path =package.path .. ";src/"
cc.FileUtils:getInstance():setPopupNotify(false)
cc.Director:getInstance():runWithScene(require("update.updatescene").new())
end
xpcall(main,__G__TRACKBACK__)
配置文件:
1.如network.createHTTPRequest()中的第二个参数文件内容大致为(可根据需要自己配)
{"code":200,"bigVersion":"1.0.01","needRestart":0,"needDownload":0,
"list":[
{"fileUrl":"http://192.168.3.2/version/res.zip","version":"1.0","id":1},
{"fileUrl":"http://192.168.3.2/version/src.zip","id":2}
]}
2.如AssetsManager:new(constchar*packageUrl,constchar*versionFileUrl,constchar*storagePath)
中的参数2,versionFileUrl版本号文件,也就是在文件里面写一个版本号,例如:1.0.01
更新的大致流程:
1. 获取当前本地存储的版本号
2. 请求更新版本的数据,并以最新版本号与当前本地存储的版本号做比较
3. 版本不一致时,就利用AssetsManager进行资源更新。否则退出让玩家开始游戏
AssetsManager的基本流程:
@H_923_2502@1. @H_923_2502@配置需要更新的zip的URL,更新版本号的URL,更新存放的相对路径
@H_923_2502@2. @H_923_2502@从Server获取该zip文件的版本号
@H_923_2502@3. @H_923_2502@对比Client中的UserDefault.xml中current-version-code键的值(当前版本号)是否过期
@H_923_2502@4. @H_923_2502@若Server的版本比Client的新,则通过http请求下载该zip
@H_923_2502@5. @H_923_2502@解压缩该zip文件
@H_923_2502@6. @H_923_2502@下载后通过CCFileUtils的fullPathForFilename方法来获取文件的引用
AssetsManager内部函数:
1. 构造函数
AssetsManager::AssetsManager(constchar*packageUrl,constchar*storagePath)
_packageUrl(packageUrl)//下载.zip文件地址
_versionFileUrl(versionFileUrl)//版本核查地址 v1.0
_storagePath(storagePath)//.zip下载后存储位置
2. checkStoragePath
由1调用
检查_storagePath 存储地址不能为""并且不是以"/"结尾的,在结尾处加上"/"
3.getVersionCodelibcurl绑定的下载字符串回调函数通过checkUpdate里调用
把下载的字符串放到传过来的字符串指针里
4.checkUpdate
通过网络检查当前的版本是不是最新版本。如果是设置优先搜索资源路径setSearchPath
5.update
(1)下载地址、版本核查的网址都不能为null,存储的文件名以"。zip"后缀
(2)checkUpdate调用,是最新版本了返回,不是执行下面
(3)通过xml文件判断是不是下载完成了没有解压,是,解压,不是,调用,downLoad下载
(4)下载完成uncompress解压
(5)设置资源搜索优先级setSearchPath
6.createDirectory
创建目录
7.downLoad
执行下载资源,建立了指向本地资源的指针
关于详细讲解AssetsManager和动态更新的网站链接:
1. http://blog.sina.com.cn/s/blog_923fdd9b0101edmv.html
2. http://www.jb51.cc/article/p-rwaqitzb-tb.html
3. http://my.oschina.net/u/1785418/blog/283043
4. http://zengrong.net/post/2131.htm
出现的问题:
1. 有可能出现AssetsManager这个文件为nil的情况。那是因为他与CURL 库提供 HTTP 网络功能有关联。CURL关闭后,assetsmanager等相关功能也会被去掉。
解决:在打包时应该在android工程下的jni\Application.mk中
把 CC_USE_CURL := 1修改为1 ,设置为开启状态 ,0为关闭状态
ifeq ($(CC_USE_CURL),1)
APP_CPPFLAGS += -DCC_USE_CURL=1
以上是参考西门大官人的:基于Quick-cocos2dx 2.2.3 的动态更新实现完整篇。(打包,服务器接口,模块自更新)所写的