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

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功能

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:null, 
        _percent:0, 
        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); 
                            } 
                            break; 
                        case cc.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: 
                        case cc.EventAssetsManager.ERROR_PARSE_MANIFEST: 
                            cc.log("Fail to download manifest file, update skipped."); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.ALREADY_UP_TO_DATE: 
                            cc.log("ALREADY_UP_TO_DATE."); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.UPDATE_FINISHED: 
                            cc.log("Update finished."); 
                            that.loadGame(); 
                            break; 
                        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(); 
                            } 
                            break; 
                        case cc.EventAssetsManager.ERROR_UPDATING: 
                            cc.log("Asset update error: " + event.getAssetId() + ", " + event.getMessage()); 
                            that.loadGame(); 
                            break; 
                        case cc.EventAssetsManager.ERROR_DECOMPRESS: 
                            cc.log(event.getMessage()); 
                            that.loadGame(); 
                            break; 
                        default: 
                            break; 
                    } 
                });

                cc.eventManager.addListener(listener, 1); 
                this._am.update(); 
                cc.director.runScene(this); 
            }

            this.schedule(this.updateProgress, 0.5); 
        },

        loadGame:function(){ 
            //jsList是jsList.js的变量,记录全部js。 
            cc.loader.loadJs(["src/jsList.js"], 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();

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

var jsList = [ 
    "src/resource.js", 
    "src/app.js" 
]

3、修改project.json。加入extensions模块,删除jsList的内容。 { "project_type": "javascript", "debugMode" : 1, "showFPS" : true, "frameRate" : 60, "id" : "gameCanvas", "renderMode" : 0, "engineDir":"frameworks/cocos2d-html5", "modules" : ["cocos2d", "extensions"],  //貌似这个对jsb是无效的,只有html5才有效 "jsList" : [ ] } 4、项目res目录增加一个project.manifest文件,AssetsManager.js里会用到。url填写自己服务器的地址,packageUrl是准备动态更新的文件的存放目录。 { "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" : [ ] }

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

三、动态更新测试

1、服务器放置version.manifest和新的project.manifest。 AssetsManager会先检查version.manifest,判断是否有更新。如果有,再拉取project.manifest。可以说version.manifest就是缩小版的project.manifest,只有头几行,两者一致。 version.manifest: { "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" } project.manifest: { "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" : { "src/app.zip" : { "md5" : "D07D260D8072F786A586A6A430D0E98B", "compressed" : true } }, "searchPaths" : [ ] }

manifest这里使用了官方说明没有提到的compressed,src/app.zip并没有在初始打包的程序中,这个只是更新用的。指定了compressed=true,AssetsManager下载后会自动解压这个文件,并保留这个文件。这样就可以减少网络传输的文件大小。 app.zip压缩的是app.js,解压后将覆盖初始化安装的app.js,从而实现了动态更新。 这里可以多次更新,不断更新version号即可,每次AssetsManager会检查文件是否存在、文件md5是否一致,如果不存在或者md5不一致都会重新下载。

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏喔家ArchiSelf

嵌入式Linux的网络连接管理

连接管理器(ConnMan)是一个连接管理守护进程 , 用于管理运行 Linux 操作系统中设备的互联网连接。 它以快速、连贯、同步的方式对不断变化的网络条件提...

2322
来自专栏沈唁志

在Windows下搭建Python3.6的运行环境

2155
来自专栏IMWeb前端团队

react 的数据管理方案:redux 还是 mobx?

本文作者:IMWeb jerytang 原文出处:IMWeb社区 未经同意,禁止转载 mobx 简介 和 redux 类似,mobx 是一个数据管理库...

3347
来自专栏Janti

记一次内存溢出的分析经历——thrift带给我的痛orz

说在前面的话 朋友,你经历过部署好的服务突然内存溢出吗? 你经历过没有看过Java虚拟机,来解决内存溢出的痛苦吗? 你经历过一个BUG,百思不得其解,头发一根一...

4468
来自专栏熊二哥

快速入门系列--WCF--06并发限流、可靠会话和队列服务

这部分将介绍一些相对深入的知识点,包括通过并发限流来保证服务的可用性,通过可靠会话机制保证会话信息的可靠性,通过队列服务来解耦客户端和服务端,提高系统的可服务数...

2037
来自专栏Java后端技术

Spring+SpringMvc+Mybatis框架集成搭建教程一(项目创建)

  2.选择Maven->Create from artchetype并选择如下图红框中的骨架

641
来自专栏Java职业技术分享

如果你想搞懂“分布式锁”,必须要看这篇文章 ,看了很意外!

对于锁大家肯定不会陌生,在 Java 中 synchronized 关键字和 ReentrantLock 可重入锁在我们的代码中是经常见的,一般我们用其在多线程...

2.9K3
来自专栏Albert陈凯

JAVA高并发基础面试题(内附答案)

这都不知道就不要去大公司面试了,丢人 java并发面试题(一)基础 本文整理了常见的Java并发面试题,希望对大家面试有所帮助,欢迎大家互相交流。 多线程 ...

5238
来自专栏漏斗社区

CTF内存取证入坑指南!稳!

最近,斗哥在刷CTF题目。突然刷到了内存取证类,了解到了一款牛逼的工具——Volatility,在kali linux也默认安装好了这个工具,正好可以好好学习一...

5087
来自专栏Golang语言社区

PHP调用Go服务的正确方式 - Unix Domain Sockets

作者:枕边书 链接:http://www.cnblogs.com/zhenbianshu/p/7265415.html 來源:博客园 问题 可能是由于经验太少,...

3959

扫码关注云+社区