
http://docs.cocos.com/creator/manual/zh/advanced-topics/hot-update.html
http://docs.cocos.com/creator/manual/zh/advanced-topics/assets-manager.html
客户端存在一个project.manifest文件,该文件包含几个信息:
packageUrl:url,服务器更新数据包根目录; remoteManifestUrl:url, [可选项]服务器上project.manifest文件的url, remoteVersionUrl:url,服务器上version.mainifest文件的url; version:x.x.x,项目版本; assets:{},资源列表;key : 资源的相对路径(相对于资源根目录)
md5 : md5 值代表资源文件的版本信息
compressed: [可选项] 如果值为 true,文件被下载后会自动被解压,目前仅支持 zip 压缩格式
size: [可选项] 文件的字节尺寸,用于快速获取进度信息 searchPaths:" ",搜索路径
客户端通过本地的project.manifest中url,可以获取服务器上project.manifest文件,比较两者的version属性,如果客户端的version比服务器低,则启动更新。
更新的内容:assets是文件列表,里面列出了项目中的完整资源,每个资源都有md5表示,客户端根据本地project.manifest中的assets列表和服务器的assets列表对比,下载不同的资源到临时文件夹,如果最后所有资源都正常,则把临时文件夹的内容替换到本地缓存文件夹中,并且修改优先搜索路径为该文件夹。所以重启游戏之后的使用的资源优先从缓存文件夹中搜索。
下载官方范例,解压。该案例已经把客户端和服务器的资源都打包好了,更新包在remote-assets文件夹中。
服务器--我使用的是nodeJs。
1 .新建一个文件夹nodeJs,在nodeJs中新建hotUpdate文件夹,在把官方案例中的remote-assets复制到hotUpdate文件夹中。
image.png
2 .在nodeJs中新建一个Js脚本,脚本内容如下
var express = require(‘express‘); var path = require(‘path‘); var app = express(); app.use(express.static(path.join(__dirname,‘hotUpdate‘))); app.Listen(80); 3.在nodeJs文件夹下执行node app.Js命令,启动服务器,可以访问http://127.0.0.1/remote-assets/project.manifest,如果成功访问则服务器启动成功。
接下来修改manifest文件里面的url,有三个文件需要修改,服务器remote-assets中的两个manifest后缀文件,官方项目assets文件夹下的project.manifest
image.png
只修改三个url
@H_403_214@ image.png
修改完成之后,打开项目,用模拟器运行看看效果。
点击检查更新按钮
image.png
点击立即更新按钮
image.png
因为某些原因,模拟器更新完成,重启不能使用更新的资源,所以需要编译成原生,我的电脑不能编译windows,就不上图了。打包成apk自测可以成功更新。
从零开始制作新版本
该项目有两个场景,作为是新版本,资源存放在服务器上。删除一个场景作为旧版本,编译安装在手机上。目标是使用旧版本热更新成新版本,并成功切换场景。
新建一个项目,新建两个场景,helloworld场景是测试热更行是否成功的场景(旧版本不存在helloworld,通过更新可以跳转到该场景)。hotUpdate场景,该场景中添加两个进度条,对应字节和文件个数两种进度,三个label,对应两种进度以及提示信息,三个按钮,分别为,检查更新,更新,切换场景。
脚本 --copy官方示例
新建一个hotUpdate脚本,添加在Canvas上。脚本中增加五个变量,把场景中对应的节点拖拽上去。,增加三个回调方法,把他绑定在按钮上。
cc.Class({ extends: cc.Component,propertIEs: { byteLabel: cc.Label,fileLabel: cc.Label,byteProgress: cc.Progressbar,fileProgress: cc.Progressbar,label: cc.Label,manifestUrl: cc.RawAsset,},onLoad() { var self = this; this._storagePath = Jsb.fileUtils.getWritablePath(); this._am = new Jsb.AssetsManager(‘‘,this._storagePath,this.versionCompareHandle); if (!cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) { this._am.retain(); } this._am.setVerifyCallback(function (path,asset) { var compressed = asset.compressed; var expectedMD5 = asset.md5; var relativePath = asset.path; var size = asset.size; if (compressed) { self .label.string = "Verification passed : " + relativePath; return true; } else { self .label.string = "Verification passed : " + relativePath + ‘ (‘ + expectedMD5 + ‘)‘; return true; } }); this.byteProgress.progress = 0; this.fileProgress.progress = 0; },hotUpdate() { if (this._am && !this._updating) { this._updateListener = new Jsb.EventListenerAssetsManager(this._am,this.updateCb.bind(this)); cc.eventManager.addListener(this._updateListener,1); if (this._am.getState() === Jsb.AssetsManager.State.UNINITED) { this._am.loadLocalManifest(this.manifestUrl); } this._am.update(); this._updating = true; } },checkUpdata() { if (this._updating) { this.label.string = ‘Checking or updating ...‘; return; } if (this._am.getState() === Jsb.AssetsManager.State.UNINITED) { this._am.loadLocalManifest(this.manifestUrl); } if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) { this.label.string = ‘Failed to load local manifest ...‘; return; } this._checkListener = new Jsb.EventListenerAssetsManager(this._am,this.checkCb.bind(this)); cc.eventManager.addListener(this._checkListener,1); this._am.checkUpdate(); this._updating = true; },changeScene() { cc.director.loadScene(‘helloworld‘); },checkCb: function (event) { switch (event.getEventCode()) { case Jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST: this.label.string = "No local manifest file found,hot update skipped."; break; case Jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: case Jsb.EventAssetsManager.ERROR_PARSE_MANIFEST: this.label.string = "Fail to download manifest file,hot update skipped."; break; case Jsb.EventAssetsManager.ALREADY_UP_TO_DATE: this.label.string = "Already up to date with the latest remote version."; break; case Jsb.EventAssetsManager.NEW_VERSION_FOUND: this.label.string = ‘New version found,please try to update.‘; this.fileProgress.progress = 0; this.byteProgress.progress = 0; break; default: return; } cc.eventManager.removeListener(this._checkListener); 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.label.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.label.string = ‘Updated file: ‘ + msg; } break; case Jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: case Jsb.EventAssetsManager.ERROR_PARSE_MANIFEST: this.label.string = ‘Fail to download manifest file,hot update skipped.‘; Failed = true; break; case Jsb.EventAssetsManager.ALREADY_UP_TO_DATE: this.label.string = ‘Already up to date with the latest remote version.‘; Failed = true; break; case Jsb.EventAssetsManager.UPDATE_FINISHED: this.label.string = ‘Update finished. ‘ + event.getMessage(); needRestart = true; break; case Jsb.EventAssetsManager.UPDATE_Failed: this.label.string = ‘Update Failed. ‘ + event.getMessage(); this._updating = false; this._canRetry = true; break; case Jsb.EventAssetsManager.ERROR_UPDATING: this.label.string = ‘Asset update error: ‘ + event.getAssetID() + ‘,‘ + event.getMessage(); break; case Jsb.EventAssetsManager.ERROR_DECOMPRESS: this.label.string = event.getMessage(); break; default: break; } if (Failed) { cc.eventManager.removeListener(this._updateListener); this._updateListener = null; this._updating = false; } if (needRestart) { cc.eventManager.removeListener(this._updateListener); this._updateListener = null; var searchPaths = Jsb.fileUtils.getSearchPaths(); var newPaths = this._am.getLocalManifest().getSearchPaths(); Array.prototype.unshift(searchPaths,newPaths); cc.sys.localstorage.setItem(‘HotUpdateSearchPaths‘,JsON.stringify(searchPaths)); Jsb.fileUtils.setSearchPaths(searchPaths); cc.game.restart(); } },}); 打包资源首先构建原生
image.png
构建完成在项目中会生成原生项目,热更新需要的资源是res,src两个文件夹以及里面的内容。
把nodeJs--hotUpdate--remote-assets文件夹下所有东西都删除,把res,src复制到nodeJs--hotUpdate--remote-assets文件夹下。
image.png
构建完原生项目,打开官方项目文件夹,拷贝出 version_generator.js 文件到helloworld项目的根目录(如下图),并在helloworld根目录打开命令窗口,执行命令,node version_generator.Js -v 1.7.0 -u http://127.0.0.1/remote-assets/ -s build/Jsb-default/ -d assets/
image.png在assets文件夹下会多出两个文件,把他们复制到nodeJs--hotUpdate--remote-assets文件夹下。
image.png
最终远程资源如图
image.png
在nodeJs文件夹下执行node app.Js命令,启动服务器,可以访问http://127.0.0.1/remote-assets/project.manifest,如果成功访问则服务器启动成功。
制作旧版本删除helloworld场景,脚本,texture文件夹,以及之前生成的manifest文件。保存之后构建项目,构建选项不要变动
在helloworld根目录打开命令窗口,执行命令,node version_generator.Js -v 1.0.0 -u http://127.0.0.1/remote-assets/ -s build/Jsb-default/ -d assets/ 注意这里的-v 1.0.0,之前是1.7.0,旧版本版本号要小于新版本
在assets生成两个manifest文件。把project.manifest拖到属性检查器上面。
image.png
重新构建原生平台,在main.Js加下面这段代码,然后编译
if (cc.sys.isNative) { var hotUpdateSearchPaths = cc.sys.localstorage.getItem(‘HotUpdateSearchPaths‘); if (hotUpdateSearchPaths) { Jsb.fileUtils.setSearchPaths(JsON.parse(hotUpdateSearchPaths)); } } image.png 现在已经完成了旧版本的制作。这是我在安卓手机上的效果。
image.png
image.png 作者:欧特雨 链接:https://www.jianshu.com/p/cec263b6b9ac 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。 总结
以上是内存溢出为你收集整理的cocoscreator热更新全部内容,希望文章能够帮你解决cocoscreator热更新所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)