转载自:https://www.jianshu.com/p/a033059f376d

惯例先上官方文档:

http://docs.cocos.com/creator/manual/zh/advanced-topics/hot-update.html
http://docs.cocos.com/creator/manual/zh/advanced-topics/assets-manager.html

参考:

Cocos Creator热更新
cocoscreator热更新-小白教程

具体步骤如下:

1.打开cc创建一个helloworld工程

2.新建脚本HotUpdate.js添加到场景的Canvas上。

3.在场景中添加两个进度条,三个Label,三个按钮,分别拖到到HotUpdate.js上。同时,绑定"检查版本"和"更新"按钮的点击事件

HotUpdate.js如下:

cc.Class({extends: cc.Component,properties: {byteLabel: cc.Label,fileLabel: cc.Label,byteProgress: cc.ProgressBar,fileProgress: cc.ProgressBar,infoLabel: cc.Label,manifestUrl: {type: cc.Asset,default: null},},checkCb: function (event) {cc.log('Code: ' + event.getEventCode());switch (event.getEventCode()){case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:this.infoLabel.string = "No local manifest file found, hot update skipped.";break;case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:this.infoLabel.string = "Fail to download manifest file, hot update skipped.";break;case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:this.infoLabel.string = "Already up to date with the latest remote version.";break;case jsb.EventAssetsManager.NEW_VERSION_FOUND:this.infoLabel.string = 'New version found, please try to update.';// this.panel.checkBtn.active = false;this.fileProgress.progress = 0;this.byteProgress.progress = 0;break;default:return;}this._am.setEventCallback(null);this._checkListener = null;this._updating = false;},updateCb: function (event) {var needRestart = false;var failed = false;switch (event.getEventCode()){case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:this.infoLabel.string = 'No local manifest file found, hot update skipped.';failed = true;break;case jsb.EventAssetsManager.UPDATE_PROGRESSION:this.byteProgress.progress = event.getPercent();this.fileProgress.progress = event.getPercentByFile();this.fileLabel.string = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();this.byteLabel.string = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();var msg = event.getMessage();if (msg) {this.infoLabel.string = 'Updated file: ' + msg;// cc.log(event.getPercent()/100 + '% : ' + msg);}break;case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:this.infoLabel.string = 'Fail to download manifest file, hot update skipped.';failed = true;break;case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:this.infoLabel.string = 'Already up to date with the latest remote version.';failed = true;break;case jsb.EventAssetsManager.UPDATE_FINISHED:this.infoLabel.string = 'Update finished. ' + event.getMessage();needRestart = true;break;case jsb.EventAssetsManager.UPDATE_FAILED:this.infoLabel.string = 'Update failed. ' + event.getMessage();// this.panel.retryBtn.active = true;this._updating = false;this._canRetry = true;break;case jsb.EventAssetsManager.ERROR_UPDATING:this.infoLabel.string = 'Asset update error: ' + event.getAssetId() + ', ' + event.getMessage();break;case jsb.EventAssetsManager.ERROR_DECOMPRESS:this.infoLabel.string = event.getMessage();break;default:break;}if (failed) {this._am.setEventCallback(null);this._updateListener = null;this._updating = false;}if (needRestart) {this._am.setEventCallback(null);this._updateListener = null;// Prepend the manifest's search pathvar searchPaths = jsb.fileUtils.getSearchPaths();var newPaths = this._am.getLocalManifest().getSearchPaths();console.log(JSON.stringify(newPaths));Array.prototype.unshift.apply(searchPaths, newPaths);// This value will be retrieved and appended to the default search path during game startup,// please refer to samples/js-tests/main.js for detailed usage.// !!! Re-add the search paths in main.js is very important, otherwise, new scripts won't take effect.cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));jsb.fileUtils.setSearchPaths(searchPaths);cc.audioEngine.stopAll();cc.game.restart();}},loadCustomManifest: function () {console.log("=========================loadCustomManifest=============================")if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {var manifest = new jsb.Manifest(customManifestStr, this._storagePath);this._am.loadLocalManifest(manifest, this._storagePath);this.infoLabel.string = 'Using custom manifest';}},retry: function () {if (!this._updating && this._canRetry) {// this.panel.retryBtn.active = false;this._canRetry = false;this.infoLabel.string = 'Retry failed Assets...';this._am.downloadFailedAssets();}},checkUpdate: function () {if (this._updating) {this.infoLabel.string = 'Checking or updating ...';return;}if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {// Resolve md5 urlvar url = this.manifestUrl.nativeUrl;console.log("==========================================");console.log(url);if (cc.loader.md5Pipe) {url = cc.loader.md5Pipe.transformURL(url);}this._am.loadLocalManifest(url);}if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {this.infoLabel.string = 'Failed to load local manifest ...';return;}this._am.setEventCallback(this.checkCb.bind(this));this._am.checkUpdate();this._updating = true;},hotUpdate: function () {if (this._am && !this._updating) {this._am.setEventCallback(this.updateCb.bind(this));if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {// Resolve md5 urlvar url = this.manifestUrl.nativeUrl;if (cc.loader.md5Pipe) {url = cc.loader.md5Pipe.transformURL(url);}this._am.loadLocalManifest(url);}this._failCount = 0;this._am.update();// this.panel.updateBtn.active = false;this._updating = true;}},show: function () {// if (this.updateUI.active === false) {//     this.updateUI.active = true;// }},// use this for initializationonLoad: function () {// Hot update is only available in Native buildif (!cc.sys.isNative) {return;}this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'helloworld-remote-asset');cc.log('Storage path for remote asset : ' + this._storagePath);// Setup your own version compare handler, versionA and B is versions in string// if the return value greater than 0, versionA is greater than B,// if the return value equals 0, versionA equals to B,// if the return value smaller than 0, versionA is smaller than B.this.versionCompareHandle = function (versionA, versionB) {cc.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);var vA = versionA.split('.');var vB = versionB.split('.');for (var i = 0; i < vA.length; ++i) {var a = parseInt(vA[i]);var b = parseInt(vB[i] || 0);if (a === b) {continue;}else {return a - b;}}if (vB.length > vA.length) {return -1;}else {return 0;}};var _this = this;// Init with empty manifest url for testing custom manifestthis._am = new jsb.AssetsManager('', this._storagePath, this.versionCompareHandle);// Setup the verification callback, but we don't have md5 check function yet, so only print some message// Return true if the verification passed, otherwise return falsethis._am.setVerifyCallback(function (path, asset) {// When asset is compressed, we don't need to check its md5, because zip file have been deleted.var compressed = asset.compressed;// Retrieve the correct md5 value.var expectedMD5 = asset.md5;// asset.path is relative path and path is absolute.var relativePath = asset.path;// The size of asset file, but this value could be absent.var size = asset.size;if (compressed) {_this.infoLabel.string = "Verification passed : " + relativePath;return true;}else {_this.infoLabel.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';return true;}});this.infoLabel.string = 'Hot update is ready, please check or directly update.';if (cc.sys.os === cc.sys.OS_ANDROID) {// Some Android device may slow down the download process when concurrent tasks is too much.// The value may not be accurate, please do more test and find what's most suitable for your game.this._am.setMaxConcurrentTask(2);this.infoLabel.string = "Max concurrent tasks count have been limited to 2";}this.fileProgress.progress = 0;this.byteProgress.progress = 0;},onDestroy: function () {if (this._updateListener) {this._am.setEventCallback(null);this._updateListener = null;}}
});

此时还没有生成project.manifest文件所以Manifest Url先留空,如下图:

4.构建项目生成res和src

5.下载官方示例中 version_generator.js文件,放置于hellowrold工程根目录

并执行如下代码生成两个manifest文件

node version_generator.js -v 1.0.0 -u http://192.168.123.115:8080/hotUpdate/ -s build/jsb-default/ -d assets/

6.将第四步生成的res、src以及第5步生成的两个manifest文件,一共4个文件放入hotUpdate文件夹,并放入服务器容器中,我这边用的是tomcat,如下图:

启动tomcat,确保能够访问

7.将project.manifest文件绑定到Manifest Url上

绑定之后,项目->构建发布—>构建

构建完成之后在main.js中添加如下代码

if (cc.sys.isNative) {var hotUpdateSearchPaths = cc.sys.localStorage.getItem('HotUpdateSearchPaths');if (hotUpdateSearchPaths) {jsb.fileUtils.setSearchPaths(JSON.parse(hotUpdateSearchPaths));}
}

最终main.js如下(每次构建都需要修改此处):

// QQPlay window need to be inited first
if (false) {BK.Script.loadlib('GameRes://libs/qqplay-adapter.js');
}window.boot = function () {if (cc.sys.isNative) {var hotUpdateSearchPaths = cc.sys.localStorage.getItem('HotUpdateSearchPaths');if (hotUpdateSearchPaths) {jsb.fileUtils.setSearchPaths(JSON.parse(hotUpdateSearchPaths));}}var settings = window._CCSettings;window._CCSettings = undefined;if ( !settings.debug ) {var uuids = settings.uuids;var rawAssets = settings.rawAssets;var assetTypes = settings.assetTypes;var realRawAssets = settings.rawAssets = {};for (var mount in rawAssets) {var entries = rawAssets[mount];var realEntries = realRawAssets[mount] = {};for (var id in entries) {var entry = entries[id];var type = entry[1];// retrieve minified raw assetif (typeof type === 'number') {entry[1] = assetTypes[type];}// retrieve uuidrealEntries[uuids[id] || id] = entry;}}var scenes = settings.scenes;for (var i = 0; i < scenes.length; ++i) {var scene = scenes[i];if (typeof scene.uuid === 'number') {scene.uuid = uuids[scene.uuid];}}var packedAssets = settings.packedAssets;for (var packId in packedAssets) {var packedIds = packedAssets[packId];for (var j = 0; j < packedIds.length; ++j) {if (typeof packedIds[j] === 'number') {packedIds[j] = uuids[packedIds[j]];}}}}function setLoadingDisplay () {// Loading splash scenevar splash = document.getElementById('splash');var progressBar = splash.querySelector('.progress-bar span');cc.loader.onProgress = function (completedCount, totalCount, item) {var percent = 100 * completedCount / totalCount;if (progressBar) {progressBar.style.width = percent.toFixed(2) + '%';}};splash.style.display = 'block';progressBar.style.width = '0%';cc.director.once(cc.Director.EVENT_AFTER_SCENE_LAUNCH, function () {splash.style.display = 'none';});}var onStart = function () {cc.loader.downloader._subpackages = settings.subpackages;cc.view.enableRetina(true);cc.view.resizeWithBrowserSize(true);if (!false && !false) {if (cc.sys.isBrowser) {setLoadingDisplay();}if (cc.sys.isMobile) {if (settings.orientation === 'landscape') {cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE);}else if (settings.orientation === 'portrait') {cc.view.setOrientation(cc.macro.ORIENTATION_PORTRAIT);}cc.view.enableAutoFullScreen([cc.sys.BROWSER_TYPE_BAIDU,cc.sys.BROWSER_TYPE_WECHAT,cc.sys.BROWSER_TYPE_MOBILE_QQ,cc.sys.BROWSER_TYPE_MIUI,].indexOf(cc.sys.browserType) < 0);}// Limit downloading max concurrent task to 2,// more tasks simultaneously may cause performance draw back on some android system / browsers.// You can adjust the number based on your own test result, you have to set it before any loading process to take effect.if (cc.sys.isBrowser && cc.sys.os === cc.sys.OS_ANDROID) {cc.macro.DOWNLOAD_MAX_CONCURRENT = 2;}}// init assetscc.AssetLibrary.init({libraryPath: 'res/import',rawAssetsBase: 'res/raw-',rawAssets: settings.rawAssets,packedAssets: settings.packedAssets,md5AssetsMap: settings.md5AssetsMap});var launchScene = settings.launchScene;// load scenecc.director.loadScene(launchScene, null,function () {if (cc.sys.isBrowser) {// show canvasvar canvas = document.getElementById('GameCanvas');canvas.style.visibility = '';var div = document.getElementById('GameDiv');if (div) {div.style.backgroundImage = '';}}cc.loader.onProgress = null;console.log('Success to load scene: ' + launchScene);});};// jsListvar jsList = settings.jsList;if (false) {BK.Script.loadlib();}else {var bundledScript = settings.debug ? 'src/project.dev.js' : 'src/project.js';if (jsList) {jsList = jsList.map(function (x) {return 'src/' + x;});jsList.push(bundledScript);}else {jsList = [bundledScript];}}var option = {id: 'GameCanvas',scenes: settings.scenes,debugMode: settings.debug ? cc.debug.DebugMode.INFO : cc.debug.DebugMode.ERROR,showFPS: !false && settings.debug,frameRate: 60,jsList: jsList,groupList: settings.groupList,collisionMatrix: settings.collisionMatrix,}cc.game.run(option, onStart);
};// main.js is qqplay and jsb platform entry file, so we must leave platform init code here
if (false) {BK.Script.loadlib('GameRes://src/settings.js');BK.Script.loadlib();BK.Script.loadlib('GameRes://libs/qqplay-downloader.js');var ORIENTATIONS = {'portrait': 1,'landscape left': 2,'landscape right': 3};BK.Director.screenMode = ORIENTATIONS[window._CCSettings.orientation];initAdapter();cc.game.once(cc.game.EVENT_ENGINE_INITED, function () {initRendererAdapter();});qqPlayDownloader.REMOTE_SERVER_ROOT = "";var prevPipe = cc.loader.md5Pipe || cc.loader.assetLoader;cc.loader.insertPipeAfter(prevPipe, qqPlayDownloader);window.boot();
}
else if (window.jsb) {var isRuntime = (typeof loadRuntime === 'function');if (isRuntime) {require('src/settings.js');require('src/cocos2d-runtime.js');require('jsb-adapter/engine/index.js');}else {require('src/settings.js');require('src/cocos2d-jsb.js');require('jsb-adapter/jsb-engine.js');}window.boot();
}

修改完成后,编译,编译完成后,Android Studio打开运行到手机上,此时点击检查版本按钮,会提示无更新。

8.制作新版本,和上述过程一样制造res、src、project.manifest、version.manifest放到服务器,下次就可以更新了

Cocos Creater 热更新相关推荐

  1. cocos creater 热更重启导致崩溃

    cocos creater 热更重启导致崩溃 知识点 jsb_websocket_server.cpp 游戏中用到的 socket inspector_socket_server.cc V8引擎中 用 ...

  2. Cocos Creator 热更新文件MD5计算和需要注意的问题

    Creator的热更新使用jsb.热更新基本按照 http://docs.cocos.com/creator/manual/zh/advanced-topics/hot-update.html?h=% ...

  3. cocos creator 热更新报错 ERROR_DOWNLOAD_MANIFEST: not permitted by network security policy

    热更新报错信息:'Fail to download manifest file, hot update skipped.'  not permitted by network security pol ...

  4. cocos creator 热更新

    热更新的使用:官方教程: 官网热更新教程 第一步:先生成配置文件:project.manifest和version.manifest,这两个文件的作用,官网有说明 第二步:创建loading脚本,继承 ...

  5. Cocos Creator基于热更新的分包方案

    cocos 的热更新是基于对比本来文件列表和远程文件列表的md5实现的,如果有多个远程资源库,就可以拿来作为分包方案.大概流程是这样的: 一 确定分包策略 首先是,策划要根据一定的策略,将动态加载的资 ...

  6. Cocos Creator 解决热更新资源md5比较引发卡顿问题

    大家在使用Cococ Creator提供的热更新 assetsManagers ,做md5校验的时候,一定会遇到卡顿的问题. 备注:文末有完整实现源码 原因是 Cococ Creator 官方提供的热 ...

  7. Cocos Creator 3.x 热更新

    前言:游戏做热更新 是基本需求: 好在 cocos-creator 已经为我们做好了方案,相对于 U3D 的热更新方案来说,使用起来很简便!,不用关注很多细节 本文使用的是 cocos-creator ...

  8. cocos2dx热更新tmx的一个坑

    游戏项目中使用了tmx地图,当对tmx文件进行热更新时,进入该地图总是宕机,纠结了几小时终于发现,cocos读取tmx文件时,会默认tmx关联的图集文件和tmx在同一目录,然而那个图集文件并没有在热更 ...

  9. 热更新_热更新必懂3件事

    今天我们来一起来说说热更新,谈起热更新,大家都觉得很难,都去找官方的热更新的解决方案,然后对着一步一步搞,原理还是不懂, 今天小编就带你来完整的讲解一下热更新的原理,搞懂原理,做热更新可以自己做,也可 ...

最新文章

  1. GoldenGate字段和数据筛选
  2. jni invalid jobject
  3. 身为网络安全的,连BlackMatter勒索软件都不知道,说出去丢不丢人啊
  4. 实验7.3 字符串 7-5 查找指定字符
  5. ASP.NET Core 替换 Action 实际执行方法
  6. 让LwIP拥有PING其他设备的能力
  7. 7-26 单词长度 (15 分) python实现
  8. 使用 Sharding-Jdbc 实现分库分表、读写分离(未完待续)
  9. Python+OpenCV:Feature Matching + Homography to find Objects
  10. 计算机组成原理第七章测试题,计算机组成原理 课堂练习-第七章
  11. WannaCry只是个开始?信息时代你急需的安全书单
  12. Android Studio3.5开发工具(安卓开发工具)的安装步骤
  13. photoshop2021一键替换蓝天白云,变化万千
  14. 【翻译】CodeMix使用教程(四):调试
  15. weblogic查看版本号教程
  16. wps怎么图片透明_wps中图片怎么样调透明度_word设置图片背景透明的图文教程-爱纯净...
  17. T检验、卡方检验以及p-value
  18. python合并word表格_python docx处理word文档中表格合并问题
  19. Codeforces Round #521 (Div. 3) B. Disturbed People 思维
  20. STM32CubeMX学习笔记(38)——FSMC接口使用(TFT-LCD屏显示)

热门文章

  1. 做好10种站外推广让你快速获得免费资源
  2. FL Studio20破解补丁包 V20.9 最新免费版(FL Studio20破解补丁包 V20.9 最新免费版功能简介)
  3. 大佬们高考成绩爆光,马云曾考1分、李彦宏东哥是学霸...
  4. 16级C++课程设计 第二题
  5. redis综合案例LOL英雄出场次数
  6. Java实现 蓝桥杯 算法提高 套正方形
  7. 最新MAC Substance 3D Stager 2021已发布,Stager中文正式版下载和安装教程
  8. uni-app - 获取汉字拼音首字母(根据中文获取拼音首字母)
  9. .Net Ria Services Preview 升级至 Wcf Ria Services Beta 记录
  10. 安装 K8S, Bigip, Gateway API 测试环境 (1)