| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- import { _decorator, Component, Node, Label, ProgressBar, Asset, game, sys, EventHandler } from 'cc';
- import { JSB } from 'cc/env';
- import { Log } from '../core/utils/Log';
- const { ccclass, property } = _decorator;
- @ccclass('HotUpdate')
- export class HotUpdate extends Component {
- @property({ tooltip: "project.manifest文件", type: Asset })
- manifestUrl: Asset = null!;
- @property({ tooltip: "检查版本后是否自动更新,否则请手动调用hotUpdate方法" })
- autoUpdate: boolean = true;
- @property({ tooltip: "检查版本回调", type: EventHandler })
- onCheck: EventHandler;
- @property({ tooltip: "热更新出错回调", type: EventHandler })
- onUpdateError: EventHandler;
- @property({ tooltip: "热更新进度回调,最大值为1", type: EventHandler })
- onUpdateProgress: EventHandler;
- @property({ tooltip: "热更新检查完成回调(只有无需热更新才会有此回调,否则是重启回调)", type: EventHandler })
- onVersionIsNew: EventHandler;
- @property({ tooltip: "热更新完成回调后会重启应用", type: EventHandler })
- onRestart: EventHandler;
- public versionIsNew: boolean = false;
- private am: jsb.AssetsManager = null!;
- private checkCb(event: any) {
- console.log('Code: ' + event.getEventCode());
- this.onCheck && this.onCheck.emit([event]);
- switch (event.getEventCode()) {
- case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
- Log.warn("找不到manifest文件,热更新跳过");
- break;
- case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
- case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
- Log.warn("无法下载manifest文件,热更新跳过");
- break;
- case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
- Log.log("热更新检查完成,已经是最新版本");
- this.versionIsNew = true;
- this.onVersionIsNew && this.onVersionIsNew.emit([event]);
- break;
- case jsb.EventAssetsManager.NEW_VERSION_FOUND:
- Log.log(`发现最新版本,即将开始热更新。总共 ${Math.ceil(this.am.getTotalBytes() / 1024)} KB`);
- if (this.autoUpdate) {
- this.hotUpdate();
- return;
- }
- break;
- default:
- return;
- }
- this.am.setEventCallback(null!);
- }
- private updateCb(event: any) {
- var needRestart = false;
- var failed = false;
- switch (event.getEventCode()) {
- case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
- Log.warn("找不到manifest文件,热更新跳过");
- this.onUpdateError && this.onUpdateError.emit([event]);
- failed = true;
- break;
- case jsb.EventAssetsManager.UPDATE_PROGRESSION:
- Log.log(`正在更新,进度: ${event.getPercent()}`);
- this.onUpdateProgress && this.onUpdateProgress.emit([event]);
- var msg = event.getMessage();
- if (msg) {
- Log.warn(`热更新失败 ${msg}`);
- this.onUpdateError && this.onUpdateError.emit([event]);
- }
- break;
- case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
- case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
- Log.warn("无法下载manifest文件,热更新跳过");
- this.onUpdateError && this.onUpdateError.emit([event]);
- failed = true;
- break;
- case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
- Log.log("热更新检查完成,已经是最新版本");
- failed = true;
- this.versionIsNew = true;
- this.onVersionIsNew && this.onVersionIsNew.emit([event]);
- break;
- case jsb.EventAssetsManager.UPDATE_FINISHED:
- Log.log("热更新完成");
- needRestart = true;
- this.onRestart && this.onRestart.emit([event]);
- break;
- case jsb.EventAssetsManager.UPDATE_FAILED:
- Log.warn(`热更新失败 ${event.getMessage()}`);
- this.onUpdateError && this.onUpdateError.emit([event]);
- break;
- case jsb.EventAssetsManager.ERROR_UPDATING:
- Log.warn(`资源更新失败,资源编号:${event.getAssetId()},错误信息:${event.getMessage()}`);
- this.onUpdateError && this.onUpdateError.emit([event]);
- break;
- case jsb.EventAssetsManager.ERROR_DECOMPRESS:
- Log.log(`${event.getMessage()}`);
- failed = true;
- this.onUpdateError && this.onUpdateError.emit([event]);
- break;
- default:
- break;
- }
- if (failed) {
- this.am.setEventCallback(null!);
- }
- if (needRestart) {
- this.am.setEventCallback(null!);
- // Prepend the manifest's search path
- var 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.
- localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
- jsb.fileUtils.setSearchPaths(searchPaths);
- // restart game.
- setTimeout(() => {
- game.restart();
- }, 1000)
- }
- }
- /**
- * 检查热更新
- * @returns
- */
- public checkUpdate() {
- if (this.am.getState() === jsb.AssetsManager.State.UNINITED) {
- var url = this.manifestUrl.nativeUrl;
- this.am.loadLocalManifest(url);
- }
- if (!this.am.getLocalManifest() || !this.am.getLocalManifest().isLoaded()) {
- Log.warn("加载manifest文件失败");
- return;
- }
- this.am.setEventCallback(this.checkCb.bind(this));
- this.am.checkUpdate();
- }
- /**
- * 执行热更新
- */
- public hotUpdate() {
- this.am.setEventCallback(this.updateCb.bind(this));
- if (this.am.getState() === jsb.AssetsManager.State.UNINITED) {
- var url = this.manifestUrl.nativeUrl;
- this.am.loadLocalManifest(url);
- }
- this.am.update();
- }
- // use this for initialization
- onLoad() {
- // Hot update is only available in Native build
- if (!JSB) {
- this.versionIsNew = true;
- return;
- }
- // 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.
- // Init with empty manifest url for testing custom manifest
- this.am = new jsb.AssetsManager('', ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'happyFarm-remote-asset'), (versionA: string, versionB: string) => {
- console.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;
- }
- });
- // 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 false
- this.am.setVerifyCallback(function (path: string, asset: any) {
- // 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) {
- Log.log("Verification passed : " + relativePath);
- return true;
- }
- else {
- Log.log("Verification passed : " + relativePath + ' (' + expectedMD5 + ')');
- return true;
- }
- });
- this.checkUpdate();
- Log.log('Hot update is ready, please check or directly update.');
- }
- onDestroy() {
- JSB && this.am.setEventCallback(null!);
- }
- }
|