quick-cocos2d 之动态更新

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, 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,__value,__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","version":"1.0","id":2}

]}

2.如AssetsManager:new(constchar*packageUrl,constchar*versionFileUrl,constchar*storagePath)

中的参数2versionFileUrl版本号文件,也就是在文件里面写一个版本号,例如:1.0.01

 

更新的大致流程:

1.  获取当前本地存储的版本号

2.  请求更新版本的数据,并以最新版本号与当前本地存储的版本号做比较

3.  版本不一致时,就利用AssetsManager进行资源更新。否则退出让玩家开始游戏

 

AssetsManager的基本流程:

1.  配置需要更新的zip的URL,更新版本号的URL,更新存放的相对路径

2.  从Server获取该zip文件的版本号

3.  对比Client中的UserDefault.xml中current-version-code键的值(当前版本号)是否过期

4.  若Server的版本比Client的新,则通过http请求下载该zip

5.  解压缩该zip文件

6.  下载后通过CCFileUtils的fullPathForFilename方法来获取文件的引用

 

AssetsManager内部函数:

1.  构造函数

AssetsManager::AssetsManager(constchar*packageUrl,constchar*versionFileUrl,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)删除.zip源文件

6.createDirectory

创建目录

7.downLoad

执行下载资源,建立了指向本地资源的指针

 

关于详细讲解AssetsManager和动态更新的网站链接:

1.  http://blog.sina.com.cn/s/blog_923fdd9b0101edmv.html

2.  http://blog.csdn.net/renzhe20092584/article/details/9184163

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 的动态更新实现完整篇。(打包,服务器接口,模块自更新)所写的 

链接:http://my.oschina.net/u/1785418/blog/283043

 

 

 

你可能感兴趣的:(quick-cocos2d)