2014年8月15日补充
cocos2d-js 3.0 rc0 的AssetsManager有缺陷,有一些注意点:(可以阅读源代码发现)
1、旧manifest中有,但新manifest中没有的文件(Assets),会被删除;旧的没有,新的有,会正常下载。
2、groupversion暂时没什么意义,并无法达到这位博主所谓的增量更新:https://github.com/faint2death/cocos2d-js/blob/master/assetsmanager.md。暂时只在版本比较中用到,并没有在计算增量值中用到。
3、下载过程中N个文件其中某个遇到错误,已下载的文件还是会妥妥的覆盖了旧文件,这样会造成更新了一半的尴尬情况。
2014年8月19日补充
cocos2d-js 3.0 rc2 的AssetsManager依然有没有确保全部同步更新的bug。本来想彻底解决这个问题,但无奈时间有限,没有彻底理解AssetsManager多个类的作用。彻底解决的事,还是留给触控去解决吧。
经过小修改,已经可以确保同步更新资源。其实做的工作就是:等最终全部下载完成后再解压文件,这样的改动是最小的。
 
使用这个更新包: https://github.com/kenkozheng/cocos2d-js/tree/master/modified-AssetsManager
覆盖本地2个目录相应的文件:
【项目路径】\frameworks\js-bindings\cocos2d-x\extensions\assets-manager(新建工程时复制出来的)
【库路径】E:\cocos2d-js-v3.0-rc2\frameworks\js-bindings\cocos2d-x\extensions\assets-manager
 

使用方法:

1、所有js必须使用zip打包,但不强求只打包为1个文件。但不同zip不要有重复的js。

2、非js可以用zip,也可以直接列出。

由于确保所有资源都下载完成后才解压js,所以玩家即使N次更新失败,还是会妥妥的停留在上一版。

建议:
1、自第一次发布后,历次更新的代码都打包在一个js.zip中,每次只更新这个js.zip。这样好处是,保证所有代码是同步的,即使没更新到,玩家也就停留在上一版。例如第一次更新,有1.js,那么js.zip只有1.js;第二次更新2.js,那么js.zip就得包含1.js和2.js,这样避免一些跳版本更新的玩家出问题。
2、非代码资源,避免修改,可以直接用新文件,但不要替换旧文件,这样目的是避免多次版本更新造成新旧混乱。设想2次更新都是zip包,两个zip包都有1.png,这时候有个跳版本更新的玩家,就会下载2个zip包,但先后顺序是不可控的。
3、每次更新manifest文件必须保留以前的assets配置,不能删除。否则,如果删了以前的assets配置,客户端会跟随着删除相应的文件。
 

一、cocos2d-js 动态更新的基本思路

动态更新的好处不言而喻,不需要重新上架审核,能节省很多时间,也能让用户尽快使用上最新的版本,减少下载的成本。

  • 官方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。

二、程序发布步骤

本文参考:https://github.com/faint2death/cocos2d-js/blob/master/assetsmanager.md,但配置的方式不一样,本文更偏于使用官方的配置。按参考文章的写法,更新多次之后,project.manifest文件会很大,这影响用户更新的速度。

1、修改main.js,加载AssetsManager功能

  1. cc.game.onStart = function(){
  2. cc.view.setDesignResolutionSize(800, 450, cc.ResolutionPolicy.SHOW_ALL);
  3. cc.view.resizeWithBrowserSize(true);
  4.  
  5. var failCount = 0;
  6. var maxFailCount = 1; //最大错误重试次数
  7.  
  8. /**
  9. * 自动更新js和资源
  10. */
  11. var AssetsManagerLoaderScene = cc.Scene.extend({
  12. _am:null,
  13. _progress:null,
  14. _percent:0,
  15. run:function(){
  16. if (!cc.sys.isNative) {
  17. this.loadGame();
  18. return;
  19. }
  20.  
  21. var layer = new cc.Layer();
  22. this.addChild(layer);
  23. this._progress = new cc.LabelTTF.create("update 0%", "Arial", 12);
  24. this._progress.x = cc.winSize.width / 2;
  25. this._progress.y = cc.winSize.height / 2 + 50;
  26. layer.addChild(this._progress);
  27.  
  28. var storagePath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : "./");
  29.  
  30. this._am = new jsb.AssetsManager("res/project.manifest", storagePath);
  31. this._am.retain();
  32.  
  33. if (!this._am.getLocalManifest().isLoaded())
  34. {
  35. cc.log("Fail to update assets, step skipped.");
  36. this.loadGame();
  37. }
  38. else
  39. {
  40. var that = this;
  41. var listener = new cc.EventListenerAssetsManager(this._am, function(event) {
  42. switch (event.getEventCode()){
  43. case cc.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
  44. cc.log("No local manifest file found, skip assets update.");
  45. that.loadGame();
  46. break;
  47. case cc.EventAssetsManager.UPDATE_PROGRESSION:
  48. that._percent = event.getPercent();
  49. cc.log(that._percent + "%");
  50. var msg = event.getMessage();
  51. if (msg) {
  52. cc.log(msg);
  53. }
  54. break;
  55. case cc.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
  56. case cc.EventAssetsManager.ERROR_PARSE_MANIFEST:
  57. cc.log("Fail to download manifest file, update skipped.");
  58. that.loadGame();
  59. break;
  60. case cc.EventAssetsManager.ALREADY_UP_TO_DATE:
  61. cc.log("ALREADY_UP_TO_DATE.");
  62. that.loadGame();
  63. break;
  64. case cc.EventAssetsManager.UPDATE_FINISHED:
  65. cc.log("Update finished.");
  66. that.loadGame();
  67. break;
  68. case cc.EventAssetsManager.UPDATE_FAILED:
  69. cc.log("Update failed. " + event.getMessage());
  70. failCount++;
  71. if (failCount < maxFailCount)
  72. {
  73. that._am.downloadFailedAssets();
  74. }
  75. else
  76. {
  77. cc.log("Reach maximum fail count, exit update process");
  78. failCount = 0;
  79. that.loadGame();
  80. }
  81. break;
  82. case cc.EventAssetsManager.ERROR_UPDATING:
  83. cc.log("Asset update error: " + event.getAssetId() + ", " + event.getMessage());
  84. that.loadGame();
  85. break;
  86. case cc.EventAssetsManager.ERROR_DECOMPRESS:
  87. cc.log(event.getMessage());
  88. that.loadGame();
  89. break;
  90. default:
  91. break;
  92. }
  93. });
  94.  
  95. cc.eventManager.addListener(listener, 1);
  96. this._am.update();
  97. cc.director.runScene(this);
  98. }
  99.  
  100. this.schedule(this.updateProgress, 0.5);
  101. },
  102.  
  103. loadGame:function(){
  104. //jsList是jsList.js的变量,记录全部js。
  105. cc.loader.loadJs(["src/jsList.js"], function(){
  106. cc.loader.loadJs(jsList, function(){
  107. cc.director.runScene(new MainScene());
  108. });
  109. });
  110. },
  111.  
  112. updateProgress:function(dt){
  113. this._progress.string = "update" + this._percent + "%";
  114. },
  115.  
  116. onExit:function(){
  117. cc.log("AssetsManager::onExit");
  118.  
  119. this._am.release();
  120. this._super();
  121. }
  122. });
  123.  
  124. var scene = new AssetsManagerLoaderScene();
  125. scene.run();
  126. };
  127. cc.game.run();

2、建立jsList.js。使用固定名字jsList,这个跟第1步的代码相对应。

  1. var jsList = [
  2. "src/resource.js",
  3. "src/app.js"
  4. ]

3、修改project.json。加入extensions模块,删除jsList的内容。

  1. {
  2. "project_type": "javascript",
  3.  
  4. "debugMode" : 1,
  5. "showFPS" : true,
  6. "frameRate" : 60,
  7. "id" : "gameCanvas",
  8. "renderMode" : 0,
  9. "engineDir":"frameworks/cocos2d-html5",
  10.  
  11. "modules" : ["cocos2d", "extensions"],  //貌似这个对jsb是无效的,只有html5才有效
  12.  
  13. "jsList" : [
  14.  
  15. ]
  16. }

4、项目res目录增加一个project.manifest文件,AssetsManager.js里会用到。url填写自己服务器的地址,packageUrl是准备动态更新的文件的存放目录。

  1. {
  2. "packageUrl" : "http://192.168.1.11:8000/res",
  3. "remoteManifestUrl" : "http://192.168.1.11:8000/res/project.manifest",
  4. "remoteVersionUrl" : "http://192.168.1.11:8000/res/version.manifest",
  5. "version" : "1.0.1",
  6. "engineVersion" : "3.0 rc0",
  7. "assets" : {
  8.  
  9. },
  10.  
  11. "searchPaths" : [
  12. ]
  13. }

5、打包程序。此时即使没有网络,也已经可以运行基础版本。

三、动态更新测试

1、服务器放置version.manifest和新的project.manifest。

AssetsManager会先检查version.manifest,判断是否有更新。如果有,再拉取project.manifest。可以说version.manifest就是缩小版的project.manifest,只有头几行,两者一致。

version.manifest:

  1. {
  2. "packageUrl" : "http://192.168.1.11:8000/res",
  3. "remoteManifestUrl" : "http://192.168.1.11:8000/res/project.manifest",
  4. "remoteVersionUrl" : "http://192.168.1.11:8000/res/version.manifest",
  5. "version" : "1.0.1",
  6. "engineVersion" : "3.0 rc0"
  7. }

project.manifest:

  1. {
  2. "packageUrl" : "http://192.168.1.11:8000/res",
  3. "remoteManifestUrl" : "http://192.168.1.11:8000/res/project.manifest",
  4. "remoteVersionUrl" : "http://192.168.1.11:8000/res/version.manifest",
  5. "version" : "1.0.1",
  6. "engineVersion" : "3.0 rc0",
  7. "assets" : {
  8. "src/app.zip" : {
  9. "md5" : "D07D260D8072F786A586A6A430D0E98B",
  10. "compressed" : true
  11. }
  12. },
  13.  
  14. "searchPaths" : [
  15. ]
  16. }

manifest这里使用了官方说明没有提到的compressed,src/app.zip并没有在初始打包的程序中,这个只是更新用的。指定了compressed=true,AssetsManager下载后会自动解压这个文件,并保留这个文件。这样就可以减少网络传输的文件大小。

app.zip压缩的是app.js,解压后将覆盖初始化安装的app.js,从而实现了动态更新。

这里可以多次更新,不断更新version号即可,每次AssetsManager会检查文件是否存在、文件md5是否一致,如果不存在或者md5不一致都会重新下载。

2、无需重新打包发布,直接打开cocos2d程序,可以看到update的字样,如果打开了logcat,也可以看到对应的日志。

 

cocos2d-js 在线更新代码脚本 动态更新脚本程序 热更新 绕过平台审核 不需重新上架的更多相关文章

  1. Unity3D热更新全书-何谓热更新,为何热更新,如何热更新

    首先来赞叹一下中文,何谓为何如何,写完才发现这三个词是如此的有规律. 为何赞叹中文?因为这是一篇针对新手程序员的文字,是一节语文课. 然后来做一下说文解字,也就是 何谓热更新 热更新,每个程序员一听就 ...

  2. 开源:AspNetCore 应用程序热更新升级工具(全网第一份公开的解决方案)

    1:下载.开源.使用教程 下载地址:Github 下载 .其它下载 开源地址:https://github.com/cyq1162/AspNetCoreUpdater 使用教程: 解压AspNetCo ...

  3. 微信小程序热更新,小程序提示版本更新,版本迭代,强制更新,微信小程序版本迭代

    相信很多人在做小程序的时候都会有迭代每当版本迭代的时候之前老版本的一些方法或者显示就不够用了这就需要用到小程序的热更新.或者说是提示升级小程序版本 editionUpdate:function(){ ...

  4. cocos2d JS 使用代码判断对象类型

    changeAtlasScoreString : function (score,tfScore) { if(tfScore.getDescription() == "LabelAtlas& ...

  5. 【Quick 3.3】资源脚本加密及热更新(三)热更新模块

    [Quick 3.3]资源脚本加密及热更新(三)热更新模块 注:本文基于Quick-cocos2dx-3.3版本编写 一.介绍 lua相对于c++开发的优点之一是代码可以在运行的时候才加载,基于此我们 ...

  6. Unity3D热更新之LuaFramework篇[09]--资源热更新与代码热更新的具体实现

    前言 在上一篇文章 Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建 中,我介绍了热更新的基本原理,并且着手搭建一台服务器. 本篇就做一个实战练习,真正的来实现热 ...

  7. 另类Unity热更新大法:代码注入式补丁热更新

    对老项目进行热更新 项目用纯C#开发的? 眼看Unity引擎热火朝天,无数程序猿加入到了Unity开发的大本营. 一些老项目,在当时ulua/slua还不如今天那样的成熟,因此他们选择了全c#开发:也 ...

  8. iOS热更新-8种实现方式

    一.JSPatch 热更新时,从服务器拉去js脚本.理论上可以修改和新建所有的模块,但是不建议这样做. 建议 用来做紧急的小需求和 修复严重的线上bug. 二.lua脚本 比如: wax.热更新时,从 ...

  9. ios app 实现热更新(无需发新版本实现app添加新功能)

    目前能够实现热更新的方法,总结起来有以下三种 1. 使用FaceBook 的开源框架 reactive native,使用js写原生的iOS应用 ios app可以在运行时从服务器拉取最新的js文件到 ...

随机推荐

  1. Smali基本语法

    .field private isFlag:z 定义变量 .method 方法 .parameter 方法参数 .prologue 方法开始 .line 12 此方法位于第12行 invoke-sup ...

  2. 得到view坐标的各种方法

    这篇文章讲的方法全是再控件可以获取焦点的情况下执行的,如果在oncreat()里面执行,那么得到的都是0 1.getLocationInWindow 这个方法得到的是view相对于当前Activity ...

  3. Emulator: glTexImage2D: got err pre :( 0x502 internal 0x1908 format 0x1908 type 0x1401

    Go to Tools > AVD Manager > Virtual device configuration > Show advanced settings > Boot ...

  4. 【已解决】unity4.2.0f4 导出Android工程报错:Error building Player: ArgumentException: Illegal characters in path. [unity导出android工程 报错,路径含有非法字符]

    使用unity3D开发的一个客户端,需要导出为Android工程,然后接入一些第三方android SDK. unity版本 操作系统为: OS 名称: Microsoft Windows 7 旗舰版 ...

  5. maven项目里,junit的test程序不能访问src/test/resource下面的配置

    问题描述 最近在写单元测试,但是不想改动源代码,所以想自己在本test目录下建一个resouces文件夹并添加对应的配置文件,可是发现test程序无法读取这个resouces文件夹下的配置. 问题解决 ...

  6. 6.2 dubbo在spring中自定义xml标签源码解析

    在6.1 如何在spring中自定义xml标签中我们看到了在spring中自定义xml标签的方式.dubbo也是这样来实现的. 一 META_INF/dubbo.xsd 比较长,只列出<dubb ...

  7. OSAL工作机制分析

    协议栈代码main()函数分析 ZMain文件->ZMain.c->main()  在这里我们重点了解osal_start_system()函数 int main( void ) { // ...

  8. listview加载数据

    首先我们需要理清思路:使用ListView显示数据是很方便的,ListVIew的数据之间通过适配器adapter去作为桥梁连接起来.当我们需要使用listview显示大量数据的时候,我们需要使用到分页 ...

  9. SSAS知识回放之订单数据分析

    1:目标 基于已经做好的DW,利用SSAS实现一个多维数据模型的创建,通过浏览可以简单的实现订单数据的分析 2:步骤 2.1:添加数据源 如下图所示,创建一个数据仓库层的数据源连接 2.2:添加数据源 ...

  10. Android短信收到,语音播报

    发送短信功能界面 /** * 发送短信Demo * * @description: * @author ldm * @date 2016-4-22 上午9:07:53 */ public class ...