@H_404_17@
1、所有js必须使用zip打包,但不强求只打包为1个文件。但不同zip不要有重复的js。@H_404_17@
2、非js可以用zip,也可以直接列出。@H_404_17@
由于确保所有资源都下载完成后才解压js,所以玩家即使N次更新失败,还是会妥妥的停留在上一版。@H_404_17@
@H_404_17@
1、所有js必须使用zip打包,但不强求只打包为1个文件。但不同zip不要有重复的js。@H_404_17@
2、非js可以用zip,也可以直接列出。@H_404_17@
由于确保所有资源都下载完成后才解压js,所以玩家即使N次更新失败,还是会妥妥的停留在上一版。@H_404_17@
@H_404_17@
一、cocos2d-js 动态更新的基本思路@H_404_17@
动态更新的好处不言而喻,不需要重新上架审核,能节省很多时间,也能让用户尽快使用上最新的版本,减少下载的成本。@H_404_17@
- 官方BETA版本后提供了AssetsManager类,可以完成动态更新的步骤,说明:https://github.com/chukong/cocos-docs/blob/master/manual/framework/html5/v3/assets-manager/zh.md
- cocos2d程序安装后,以Android为例,程序存在于2个地方:apk安装目录(/data/dalvik-cache),apk数据目录(/data/data/[包名])
- AssetsManager根据projec.manifest文件的配置,把新文件下载到apk数据目录,并默认把这个下载目录设置为最优先搜索的地方。
- project.json文件中指定的js文件,将在程序main.js启动前就加载完。main.js不需要写到这个list中。所以需要动态更新的js,不能列在这个json中。
- 除了main.js外,把其他js列到一个文件中:src/jsList.js。AssetsManager检查完之后,先加载这个jsList.js,然后根据里边的配置再加载全部js。
二、程序发布步骤@H_404_17@
本文参考:https://github.com/faint2death/cocos2d-js/blob/master/assetsmanager.md,但配置的方式不一样,本文更偏于使用官方的配置。按参考文章的写法,更新多次之后,project.manifest文件会很大,这影响用户更新的速度。@H_404_17@
cc.game.onStart = function(){ cc.view.setDesignResolutionSize(800,450,cc.ResolutionPolicy.SHOW_ALL); cc.view.resizeWithBrowserSize(true); var failCount = 0; var maxFailCount = 1; //最大错误重试次数 /** * 自动更新js和资源 */ var AssetsManagerLoaderScene = cc.Scene.extend({ _am:null,_progress:,run:function(){ if (!cc.sys.isNative) { this.loadGame(); return; } var layer = new cc.Layer(); this.addChild(layer); this._progress = new cc.LabelTTF.create("update 0%","Arial",12); this._progress.x = cc.winSize.width / 2; this._progress.y = cc.winSize.height / 2 + 50; layer.addChild(this._progress); var storagePath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : "./"); this._am = new jsb.AssetsManager("res/project.manifest",storagePath); this._am.retain(); if (!this._am.getLocalManifest().isLoaded()) { cc.log("Fail to update assets,step skipped."); this.loadGame(); } else { var that = this; var listener = new cc.EventListenerAssetsManager(this._am,function(event) { switch (event.getEventCode()){ case cc.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST: cc.log("No local manifest file found,skip assets update."); that.loadGame(); break; case cc.EventAssetsManager.UPDATE_PROGRESSION: that._percent = event.getPercent(); cc.log(that._percent + "%"); var msg = event.getMessage(); if (msg) { cc.log(msg); } case cc.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: case cc.EventAssetsManager.ERROR_PARSE_MANIFEST: cc.log("Fail to download manifest file,update skipped."); that.loadGame(); case cc.EventAssetsManager.ALREADY_UP_TO_DATE: cc.log("ALREADY_UP_TO_DATE."); that.loadGame(); case cc.EventAssetsManager.UPDATE_FINISHED: cc.log("Update finished."); that.loadGame(); case cc.EventAssetsManager.UPDATE_Failed: cc.log("Update Failed. " + event.getMessage()); failCount++; if (failCount < maxFailCount) { that._am.downloadFailedAssets(); } else { cc.log("Reach maximum fail count,exit update process"); failCount = 0; that.loadGame(); } case cc.EventAssetsManager.ERROR_UPDATING: cc.log("Asset update error: " + event.getAssetId() + "," + event.getMessage()); that.loadGame(); case cc.EventAssetsManager.ERROR_DECOMPRESS: cc.log(event.getMessage()); that.loadGame(); default: break; } }); cc.eventManager.addListener(listener,1); this._am.update(); cc.director.runScene(this); } this.schedule(this.updateProgress,0.5); },loadGame:jsList是jsList.js的变量,记录全部js。 cc.loader.loadJs(["src/jsList.js"],255); line-height:1.5!important">function(){ cc.loader.loadJs(jsList,function(){ cc.director.runScene(new MainScene()); }); }); },updateProgress:function(dt){ this._progress.string = "update" + this._percent + "%"; },onExit:function(){ cc.log("AssetsManager::onExit"); this._am.release(); this._super(); } }); var scene = new AssetsManagerLoaderScene(); scene.run(); }; cc.game.run();
@H_404_17@
var jsList = [ "src/resource.js","src/app.js" ]
3、修改project.json。加入extensions模块,删除jsList的内容。@H_404_17@
{ "project_type": "javascript","debugMode" : 1,"showFPS" : true,"frameRate" : 60,"id" : "gameCanvas","renderMode" : 0,"engineDir":"frameworks/cocos2d-html5","modules" : ["cocos2d","extensions"], //貌似这个对jsb是无效的,只有html5才有效 "jsList" : [ ] }
@H_404_17@
@H_404_17@
4、项目res目录增加一个project.manifest文件,AssetsManager.js里会用到。url填写自己服务器的地址,packageUrl是准备动态更新的文件的存放目录。@H_404_17@
{ "packageUrl" : "http://192.168.1.11:8000/res","remoteManifestUrl" : "http://192.168.1.11:8000/res/project.manifest","remoteVersionUrl" : "http://192.168.1.11:8000/res/version.manifest","version" : "1.0.1","engineVersion" : "3.0 rc0","assets" : { },"searchPaths" : [ ] }
@H_404_17@
5、打包程序。此时即使没有网络,也已经可以运行基础版本。@H_404_17@
@H_404_17@
三、动态更新测试@H_404_17@
1、服务器放置version.manifest和新的project.manifest。@H_404_17@
AssetsManager会先检查version.manifest,判断是否有更新。如果有,再拉取project.manifest。可以说version.manifest就是缩小版的project.manifest,只有头几行,两者一致。@H_404_17@
version.manifest:@H_404_17@
}@H_404_17@
project.manifest:@H_404_17@
: { "src/app.zip" : { "md5" : "D07D260D8072F786A586A6A430D0E98B","compressed" : true } },sans-serif; font-size:14px">manifest这里使用了官方说明没有提到的compressed,src/app.zip并没有在初始打包的程序中,这个只是更新用的。指定了compressed=true,AssetsManager下载后会自动解压这个文件,并保留这个文件。这样就可以减少网络传输的文件大小。@H_404_17@
app.zip压缩的是app.js,解压后将覆盖初始化安装的app.js,从而实现了动态更新。@H_404_17@
这里可以多次更新,不断更新version号即可,每次AssetsManager会检查文件是否存在、文件md5是否一致,如果不存在或者md5不一致都会重新下载。@H_404_17@
@H_404_17@
2、无需重新打包发布,直接打开cocos2d程序,可以看到update的字样,如果打开了logcat,也可以看到对应的日志。@H_404_17@