流程
加载本地project.manifest,修改url,热更,
第一次可以成功,第二热更直接跳到状态:ALREADY_UP_TO_DATE,
代码如下:
`
const jsb = (window).jsb;
import { _decorator, Component, Node, Label, ProgressBar, Asset, game, sys, EventHandler, Event } from ‘cc’;
const { ccclass, property } = _decorator;
export const State_UPDATE_NEWFOUND = “newfound”//更新进度
export const State_UPDATE_PROGRESSION = “updateProgression”//更新进度
export const State_UPDATE_SKIP = “skip”//跳过
export const State_UPDATE_FAILED = “failed”//失败可以重试
export const State_UPDATE_ERR = “err”//更新错误
export const State_UPDATE_OVER = “over”//更新错误
export type updateData = {
state: string,//状态
message: string,//错误信息
downloadedFiles: number,
totalFiles: number,
downloadedBytes: number,
totalBytes: number,
}
class HostUpdate {
private updateEventHandle: EventHandler | null = null
private _am: jsb.AssetsManager | null = null
//存储地址
private _storagePath = “”
updateCb(event: any) {
if (!this._am) {
return
}
var needRestart = false;
var failed = false;
switch (event.getEventCode()) {
case jsb.EventAssetsManager.NEW_VERSION_FOUND:
// this.panel.info.string = 'New version found, please try to update. (' + Math.ceil(this._am.getTotalBytes() / 1024) + 'kb)';
//this.panel.checkBtn.active = false;
//this.panel.fileProgress.progress = 0;
//this.panel.byteProgress.progress = 0;
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_NEWFOUND,//状态
message: "",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
this._am.update();
break;
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
//this.panel.info.string = 'No local manifest file found, hot update skipped.';
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_ERR,//状态
message: "加载本地版本失败",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
break;
case jsb.EventAssetsManager.UPDATE_PROGRESSION:
//this.panel.byteProgress.progress = event.getPercent();
//.panel.fileProgress.progress = event.getPercentByFile();
//this.panel.fileLabel.string = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();
//this.panel.byteLabel.string = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();
//console.log(this.panel.fileLabel.string, this.panel.byteLabel.string);
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_PROGRESSION,//状态
message: "",//错误信息
downloadedFiles: event.getDownloadedFiles(),
totalFiles: event.getTotalFiles(),
downloadedBytes: event.getDownloadedBytes(),
totalBytes: event.getTotalBytes(),
}
this.updateEventHandle.emit([data])
}
var msg = event.getMessage();
if (msg) {
//this.panel.info.string = 'Updated file: ' + msg;
// cc.log(event.getPercent()/100 + '% : ' + msg);
}
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
//this.panel.info.string = 'Fail to download manifest file, hot update skipped.';
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_ERR,//状态
message: "加载远程版本失败",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
failed = true;
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
//this.panel.info.string = 'Already up to date with the latest remote version.';
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_SKIP,//状态
message: "",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
failed = true;
break;
case jsb.EventAssetsManager.UPDATE_FINISHED:
// this.panel.info.string = 'Update finished. ' + event.getMessage();
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_OVER,//状态
message: "",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
needRestart = true;
break;
case jsb.EventAssetsManager.UPDATE_FAILED:
//this.panel.info.string = 'Update failed. ' + event.getMessage();
// this.panel.retryBtn.active = true;
//this._updating = false;
//this._canRetry = true;
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_FAILED,//状态
message: "加载本地版本失败",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
break;
case jsb.EventAssetsManager.ERROR_UPDATING:
// this.panel.info.string = 'Asset update error: ' + event.getAssetId() + ', ' + event.getMessage();
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_ERR,//状态
message: event.getMessage(),//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
break;
case jsb.EventAssetsManager.ERROR_DECOMPRESS:
// this.panel.info.string = event.getMessage();
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_ERR,//状态
message: event.getMessage(),//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
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 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)
}
}
//重试
retry() {
if (!this._am) {
return
}
// if (!this._updating && this._canRetry) {
// this.panel.retryBtn.active = false;
// this._canRetry = false;
//this.panel.info.string = 'Retry failed Assets...';
this._am.downloadFailedAssets();
// }
}
// 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.
versionCompareHandle(versionA: string, versionB: string) {
if (versionA==versionB){
return 0
}else{
return -1
}
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;
}
}
verifyCallback (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) {
// panel.info.string = "Verification passed : " + relativePath;
return true;
}
else {
// panel.info.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';
return true;
}
}
checkAndUpdate (version: string, localManifest: string, updateEvent: EventHandler, url?: string) {
this.updateEventHandle = updateEvent
// Hot update is only available in Native build
if (!jsb) {
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_SKIP,//状态
message: "",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
return;
}
let loadManifest = jsb.fileUtils.getStringFromFile(localManifest);
if (!loadManifest) {
if (this.updateEventHandle) {
var data: updateData = {
state: State_UPDATE_ERR,//状态
message: "加载本地版本文件失败",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
this.updateEventHandle.emit([data])
}
return;
}
let manifestObject = JSON.parse(loadManifest);
if (url) {
manifestObject.packageUrl = url;
manifestObject.remoteManifestUrl = url + version + '/project.manifest';
manifestObject.remoteVersionUrl = url + version + '/version.manifest';
}
var localVersion = manifestObject.version
var compareVersion = this.versionCompareHandle(version, localVersion)
if (compareVersion == 0) {
if (updateEvent) {
var data: updateData = {
state: State_UPDATE_SKIP,//状态
message: "",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
updateEvent.emit([data])
}
return
}
this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'blackjack-remote-asset');
console.log('Storage path for remote asset : ' + this._storagePath);
// Init with empty manifest url for testing custom manifest
this._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 false
if (!this._am) {
return
}
var manifest = new jsb.Manifest(JSON.stringify(manifestObject), this._storagePath);
this._am.loadLocalManifest(manifest, this._storagePath);
if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
var data: updateData = {
state: State_UPDATE_ERR,//状态
message: "加载本地文件失败",//错误信息
downloadedFiles: 0,
totalFiles: 0,
downloadedBytes: 0,
totalBytes: 0,
}
updateEvent.emit([data])
return;
}
this._am.setEventCallback(this.updateCb.bind(this));
this._am.setVerifyCallback(this.verifyCallback.bind(this));
//执行更新
this._am.checkUpdate();
// _am.update();
}
destroy() {
if (this._am) {
this._am.setEventCallback(null!);
}
}
}
const hotUpdate = new HostUpdate()
//检查更新
export var checkAndUpdate = (version: string, localManifest: string, updateEvent: EventHandler, url?: string) => {
hotUpdate.checkAndUpdate(version, localManifest, updateEvent, url)
}
export function destroy() {
hotUpdate.destroy()
}
`