热更新完成后重启游戏,清空临时文件夹temp下的资源,会导致资源找不到
哪个temp文件夹,可否把路径发一下,如果清除的是APP的缓存目录,资源是会加载APP包里的资源。
var beiMiCommon = require(“BeiMiCommon”);
var MD5 = require(“MD5”);
cc.Class({
extends: beiMiCommon,
properties: {
manifestUrl: {
type: cc.Asset,
default: null
},
progressBar: {
type: cc.ProgressBar,
default: null
},
progressBarNode: {
type: cc.Node,
default: null
},
progress: {
type: cc.Label,
default: null
},
bytes: {
type: cc.Label,
default: null
},
files: {
type: cc.Label,
default: null
},
curVersion: {
type: cc.Label,
default: null
},
lastVersion: {
type: cc.Label,
default: null
},
updateContentDesc: {
type: cc.Label,
default: null
},
tips: {
type: cc.Label,
default: null
},
updateTips: {
type: cc.Node,
default: null
},
logo: {
type: cc.Node,
default: null
},
desc: {
type: cc.Node,
default: null
},
main: {
type: cc.Node,
default: null
},
version: {
type: cc.Node,
default: null
},
_canRetry: false,
_needUpdate: false,
_storagePath: '',
_hotUpdateName: 'zpsuoha-remote-asset'
},
checkCb: function (event) {
console.log('Code: ' + event.getEventCode());
switch (event.getEventCode()) {
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
this.tips.string = "未检测到更新插件,跳过更新";
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
this.tips.string = "更新插件下载失败,跳过更新";
break;
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
this.tips.string = "解压热更新插件失败,跳过更新";
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
this.tips.string = "已是最新版本";
break;
case jsb.EventAssetsManager.NEW_VERSION_FOUND:
this.tips.string = '发现新版本,即将更新';
this.prepareForUpdate();
this._needUpdate = true;
break;
default:
return;
}
console.log(this.tips.string);
this._am.setEventCallback(null);
this.checkNativeVersion(this._needUpdate);
if (this._needUpdate) {
console.log("异步自动执行更新操作");
this.scheduleOnce(this.hotUpdate, 0.5);
} else {
this.showLoginView();
}
},
showLoginView() {
this.progressBar.progress = 1;
console.log("更新结束,展示登录按钮");
this.scheduleOnce(function () {
this.main.active = true;
this.logo.active = true;
this.progressBarNode.active = false;
this.desc.active = false;
this.updateTips.active = false;
this._failCount = 0;
}, 0.3);
},
prepareForUpdate() {
console.log("切换到更新界面");
this.files.string = "0/0";
this.bytes.string = "0k/0k";
this.logo.active = false;
this.updateTips.active = true;
let isIOS = true;
if (cc.sys.os === cc.sys.OS_ANDROID) {
isIOS = false;
}
cc.beimi.http.httpGet("/api/player/getLastVersionUpdateLog?isIOS=" + isIOS, this.showChangeLog, this.showChangeLog, this);
},
showChangeLog(changelog, that) {
console.log("查询到更新日志:", changelog);
that.updateContentDesc.string = changelog ? changelog : "版本更新日志加载失败";
//加载更新日志,再进行展示
that.desc.active = true;
},
updateCb: function (event) {
let needRestart = false;
let failed = false;
let that = this;
switch (event.getEventCode()) {
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
this.tips.string = '未检测到更新插件,跳过更新';
failed = true;
break;
case jsb.EventAssetsManager.UPDATE_PROGRESSION:
if (event.getPercent()) {
this.progressBar.progress = Number(event.getPercent());
this.progress.string = Math.ceil(Number(event.getPercent() * 100)) + "%";
this.bytes.string = Math.ceil(event.getDownloadedBytes() / 1000) + "K / " + Math.ceil(event.getTotalBytes() / 1000) + "K";
this.files.string = event.getDownloadedFiles() + " / " + event.getTotalFiles();
}
let msg = event.getMessage();
if (msg) {
this.tips.string = '下载文件: ' + msg;
} else {
let tips = this.tips.string;
if (tips.length === 8) {
tips = "下载文件中.";
} else if (tips.length === 6) {
tips = "下载文件中..";
} else if (tips.length === 7) {
tips = "下载文件中...";
}
this.tips.string = tips;
}
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
this.tips.string = '下载manifest文件失败,跳过更新';
failed = true;
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
this.tips.string = '已更新到最新版本';
failed = true;
break;
case jsb.EventAssetsManager.UPDATE_FINISHED:
this.tips.string = '更新完成 ' + event.getMessage();
this.progressBar.progress = 1;
this.progress.string = "100%";
needRestart = true;
break;
case jsb.EventAssetsManager.UPDATE_FAILED:
this.tips.string = '更新失败 ' + event.getMessage();
this._failCount++;
let message = this._failCount + "个文件更新失败,请尝试重新下载更新";
this.confirm(message, function () {
that.tips.string = '尝试重新加载失败的资源...';
that.downloadFailedAssets();
}, function () {
that.showLoginView();
});
break;
case jsb.EventAssetsManager.ERROR_UPDATING:
this._failCount++;
this.tips.string = '更新资源时发生错误: ' + event.getAssetId() + ', ' + event.getMessage();
break;
case jsb.EventAssetsManager.ERROR_DECOMPRESS:
this._failCount++;
this.tips.string = event.getMessage();
break;
default:
break;
}
console.log(this.tips.string);
if (failed) {
this.onFailed();
}
if (needRestart) {
this.restart();
}
},
onFailed() {
this._am.setEventCallback(null);
//直接跳转登录界面
this.showLoginView();
},
restart() {
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.
cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
jsb.fileUtils.setSearchPaths(searchPaths);
cc.audioEngine.stopAll();
cc.game.restart();
},
//检查原生app的版本号,如果有重新更新安装,则删除旧的热更新资源
checkNativeVersion(noNeedRestart) {
let io = require("IOUtils");
let curVersion = cc.beimi.wechat.getNativeAppVersion();
let preVersion = io.get("appVersion");
console.log(curVersion, preVersion);
if (curVersion && preVersion) {
//如果新版本大于旧版本
if (Number(curVersion) > Number(preVersion)) {
//删除热更新资源
this.clearResourcesAndRestart(noNeedRestart);
}
}
io.put("appVersion", curVersion);
},
clearResourcesAndRestart (noNeedRestart) {
this.clearHotupdateCache();
this.clearHotupdateCacheTemp();
if (!noNeedRestart) {
cc.audioEngine.stopAll();
cc.game.restart();
}
},
/**
* 一键修复并重启
*/
oneButtonRepaired() {
if (!cc.sys.isNative) {
this.msg("仅支持原生平台");
return;
}
let that = this;
this.confirm("一键修复可以解决无法更新成功或异常出现的未知问题,但可能需要消耗几分钟时间,确定进行此操作?", function () {
that.clearResourcesAndRestart(false);
});
},
/**
* 错误处理和失败重试
*/
downloadFailedAssets() {
console.log('downloadFailedAssets');
this._failCount = 0;
this._am.setEventCallback(this.updateCb.bind(this));
this._am.downloadFailedAssets();
},
checkUpdate: function () {
this.tips.string = "检查更新...";
if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
// Resolve md5 url
var url = this.manifestUrl.nativeUrl;
if (cc.loader.md5Pipe) {
url = cc.loader.md5Pipe.transformURL(url);
}
this._am.loadLocalManifest(url);
}
if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
this.tips.string = '加载 manifest 失败 ...';
return;
}
this._am.setEventCallback(this.checkCb.bind(this));
this._am.checkUpdate();
},
hotUpdate: function () {
console.log("开始热更新");
if (this._am) {
console.log("设置热更新回调");
this._am.setEventCallback(this.updateCb.bind(this));
if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
// Resolve md5 url
let url = this.manifestUrl.nativeUrl;
if (cc.loader.md5Pipe) {
url = cc.loader.md5Pipe.transformURL(url);
}
this._am.loadLocalManifest(url);
}
this._failCount = 0;
console.log("执行热更新update操作");
this._am.update();
}
},
initView() {
this.tips.string = "";
this.progressBar.progress = 0;
this.progress.string = "0%";
this.desc.active = false;
this.updateTips.active = false;
this.main.active = false;
this.version.active = true;
this.logo.active = true;
this.progressBarNode.active = true;
},
// use this for initialization
onLoad: function () {
// Hot update is only available in Native build
if (!cc.sys.isNative) {
return;
}
//初始化进入登录页展示的界面
this.initView();
this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + this._hotUpdateName);
console.log('Storage path for remote asset : ' + this._storagePath);
//如果是重新进入游戏,清除cache
this.clearHotupdateCacheTemp();
let that = this;
// 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) {
console.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);
that.curVersion.string = versionA;
that.lastVersion.string = versionB;
let vA = versionA.split('.');
let vB = versionB.split('.');
for (let i = 0; i < vA.length; ++i) {
let a = parseInt(vA[i]);
let b = parseInt(vB[i] || 0);
if (a === b) {
continue;
} else {
return a - b;
}
}
if (vB.length > vA.length) {
return -1;
} else {
return 0;
}
};
// Init with empty manifest url for testing custom manifest
this._am = new jsb.AssetsManager(this.manifestUrl, 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
this._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) {
// that.tips.string = "校验文件: " + relativePath;
console.log("压缩文件,无需校验:" + relativePath);
return true;
} else {
const md5 = that.calMD5OfFile(path);
// const md5 = crypto.createHash('md5').update(fs.readFileSync(path)).digest('hex');
that.tips.string = "校验文件: " + relativePath + ' (' + expectedMD5 + ')';
console.log("热更新文件md校验:左边是服务器上得md5,右边是下载下来后生成得md5码", md5, asset.md5, asset.md5 === md5);
if (expectedMD5 === md5) {
return true;
}
//md5不相同,删除下载文件
if (jsb.fileUtils.isFileExist(path)) {
console.log("文件存在,删除该文件");
jsb.fileUtils.removeFile(path);
}
//返回false,重新下载
return false;
}
});
this.tips.string = '更新已备就绪,马上开始';
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(3);
this.tips.string = "最大下载线程已设置为3";
}
//自动检查是否需要更新
this.checkUpdate();
},
calMD5OfFile(filePath) {
return MD5(jsb.fileUtils.getDataFromFile(filePath));
},
//清除热更新文件
clearHotupdateCache() {
if (cc.sys.isBrowser) {
return;
}
let storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + this._hotUpdateName);
jsb.fileUtils.removeDirectory(storagePath);
},
//清除临时热更新文件
clearHotupdateCacheTemp() {
if (cc.sys.isBrowser) {
return;
}
console.log('temp file clear');
let storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + this._hotUpdateName + '_temp');
jsb.fileUtils.removeDirectory(storagePath);
},
onDestroy: function () {
if (this._updateListener) {
this._am.setEventCallback(null);
this._updateListener = null;
}
}
});
//如果是重新进入游戏,清除cache
this.clearHotupdateCacheTemp();
我会在每次重启的时候去清空临时缓存文件夹
//清除临时热更新文件
clearHotupdateCacheTemp() {
if (cc.sys.isBrowser) {
return;
}
console.log(‘temp file clear’);
let storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : ‘/’) + this._hotUpdateName + ‘_temp’);
jsb.fileUtils.removeDirectory(storagePath);
},
难道是我的路径写的有问题:
_hotUpdateName: ‘zpsuoha-remote-asset’
我自己定义了个文件夹名
现在的问题是,更新完成后调用cc.game.restart()进入游戏是没有问题的,资源都引用正常;
但是只要我重新后台关闭应用,再打开就会出现资源找不到的问题
安卓调试报错
找不到res/import/uuid.json
都是热更新的资源
找到问题原因了,是hotUpdate插件引入问题,忘记加文件夹,导致构建时没有自动给main.js加上路径
抱歉挖个坟 我也碰到这个问题了 请问是怎么解决的 加文件夹是什么意思?