-
Creator 版本: 2.4.8
-
目标平台: IOS
热更新后可以正常使用,但是只要重启APP后,场景资源保留,脚本资源会丢失
加密脚本勾选和密钥是一致的
安卓正常
无语的点就是 热更后只要不重启是正常的 但是重启就回退了
怀疑是又一次进行了热更比对 然后有什么影响
Creator 版本: 2.4.8
目标平台: IOS
热更新后可以正常使用,但是只要重启APP后,场景资源保留,脚本资源会丢失
加密脚本勾选和密钥是一致的
安卓正常
无语的点就是 热更后只要不重启是正常的 但是重启就回退了
怀疑是又一次进行了热更比对 然后有什么影响
main.js 设置搜索路径那里没处理吧
有想过这个问题
但是我看了每次构建后的 main.js 开头都已经有一段相同处理路径的了
好像没必要自己加
这个你查查搜索路径,控制台打印重启前后的值,大概率是更新完后 搜索路径被改出问题了
main.zip (2.0 KB)
HotUpdate.zip (2.1 KB)
main.js 是 2.4.8 构建后的 没有手动更改过 感觉该有的都有
HotUpdate 使用的是ts版本的
有没有同样情况的大佬帮忙看看
试了一下 还是不行 这两句话 昨晚也加过差不多的 也是不行
你把你的搜索路劲打印看下,第二次进的时候
搜索路劲貌似没什么问题 mac模拟器看的
那就不知道了,我的是不会回退的
能否贴一个 你的 main.js 和 HotUpdate 文件
我比对看看
window.boot = function () {
var settings = window._CCSettings;
window._CCSettings = undefined;
var onProgress = null;
let { RESOURCES, INTERNAL, MAIN, START_SCENE } = cc.AssetManager.BuiltinBundleName;
function setLoadingDisplay () {
// Loading splash scene
var splash = document.getElementById('splash');
var progressBar = splash.querySelector('.progress-bar span');
onProgress = function (finish, total) {
var percent = 100 * finish / total;
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.view.enableRetina(true);
cc.view.resizeWithBrowserSize(true);
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_BAIDU_APP,
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.assetManager.downloader.maxConcurrency = 2;
cc.assetManager.downloader.maxRequestsPerFrame = 2;
}
var launchScene = settings.launchScene;
var bundle = cc.assetManager.bundles.find(function (b) {
return b.getSceneInfo(launchScene);
});
bundle.loadScene(launchScene, null, onProgress,
function (err, scene) {
if (!err) {
cc.director.runSceneImmediate(scene);
if (cc.sys.isBrowser) {
// show canvas
var canvas = document.getElementById('GameCanvas');
canvas.style.visibility = '';
var div = document.getElementById('GameDiv');
if (div) {
div.style.backgroundImage = '';
}
console.log('Success to load scene: ' + launchScene);
}
}
}
);
};
var option = {
id: 'GameCanvas',
debugMode: settings.debug ? cc.debug.DebugMode.INFO : cc.debug.DebugMode.ERROR,
showFPS: settings.debug,
frameRate: 60,
groupList: settings.groupList,
collisionMatrix: settings.collisionMatrix,
};
cc.assetManager.init({
bundleVers: settings.bundleVers,
remoteBundles: settings.remoteBundles,
server: settings.server
});
let bundleRoot = [INTERNAL, MAIN];
settings.hasStartSceneBundle && bundleRoot.push(START_SCENE);
settings.hasResourcesBundle && bundleRoot.push(RESOURCES);
var count = 0;
function cb (err) {
if (err) return console.error(err.message, err.stack);
count++;
if (count === bundleRoot.length + 1) {
cc.game.run(option, onStart);
}
}
cc.assetManager.loadScript(settings.jsList.map(function (x) { return 'src/' + x;}), cb);
for (let i = 0; i < bundleRoot.length; i++) {
cc.assetManager.loadBundle(bundleRoot[i], cb);
}
};
if (window.jsb) {
var isRuntime = (typeof loadRuntime === 'function');
if (isRuntime) {
require('src/cocos2d-runtime.js');
if (CC_PHYSICS_BUILTIN || CC_PHYSICS_CANNON) {
require('src/physics.js');
}
require('jsb-adapter/engine/index.js');
}
else {
require('src/cocos2d-jsb.js');
if (CC_PHYSICS_BUILTIN || CC_PHYSICS_CANNON) {
require('src/physics.js');
}
require('jsb-adapter/jsb-engine.js');
}
var hotUpdateSearchPaths = cc.sys.localStorage.getItem('HotUpdateSearchPaths');
if (hotUpdateSearchPaths) jsb.fileUtils.setSearchPaths(JSON.parse(hotUpdateSearchPaths));
require('src/settings.js');
cc.macro.CLEANUP_IMAGE_CACHE = true;
window.boot();
}
// @ts-ignore
// let md5 = require(“md5”);
import { LggData } from “./app/data/LggData”;
import transitions from “./shaders/transitions/transitions”;
const { ccclass, property } = cc._decorator;
@ccclass
export default class UpdateScene extends cc.Component {
@property(cc.Label)
upTit: cc.Label = null;
@property(cc.ProgressBar)
upPro: cc.ProgressBar = null;
@property(cc.Label)
progress: cc.Label = null;
@property(cc.Label)
rate: cc.Label = null;
@property(sp.Skeleton)
logo: sp.Skeleton = null;
@property(cc.Node)
zgnode: cc.Node = null;
@property(cc.Node)
zgbgnode: cc.Node = null;
@property(transitions)
tta: transitions = null;
private _updating: boolean = false;
private _am: jsb.AssetsManager = null;
private _currPer: number = null;
private _failCount: number = 0;
private _newVerCall: Function = null;
private _dowloading: Function = null;
/**
* 加载游戏主场景
*/
loadAppScene() {
this.node = cc.director.getScene().getChildByName('transitions');
let com = this.node.getComponent(transitions);
cc.assetManager.loadBundle("resources_bundle", () => {
com.loadScene("AppScene", 'Canvas/Main Camera', 'WindowManager/Main Camera', () => {
})
})
// cc.director.loadScene("AppScene");
// cc.director.preloadScene("AppScene",(completedCount: number, totalCount: number, item: any)=>{
// },(error: Error)=>{
// })
}
/**
* 设置回调
*/
setUpdateCall() {
this._newVerCall = (bytes: number) => {
let mb = Math.floor(bytes / (1024 * 1024)) + "MB";
this.upTit.string = "New version found, size:" + mb;
}
this._dowloading = (down, total, per) => {
if (total < 1024 * 1024 && this.rate.node.active) {
this.rate.node.active = false;
} else {
this.rate.node.active = true;
}
this.rate.string = `${Math.floor(down / (1024 * 1024))}MB/${Math.floor(total / (1024 * 1024))}MB`;
this.progress.string = Math.floor(per * 100) + "%";
}
}
/**
* 播放logo
*/
playLogo(callback, skip?: boolean) {
this.zgbgnode.active = false;
if (skip) {
this.logo.node.active = false;
if (callback) callback();
} else {
this.logo.node.active = true;
this.logo.clearTracks();
this.logo.setAnimation(0, 'animation', false);
this.logo.setCompleteListener(() => {
this.logo.node.active = false;
if (callback) callback();
})
}
}
start() {
// this.playLogo(this.startUpdate.bind(this), !cc.sys.isNative);
if (LggData.instance.curLang == "default") {
cc.tween(this.zgnode)
.delay(2)
.to(1.0, { opacity: 0 })
// .hide()
// .removeSelf()
.call(() => {
this.playLogo(this.startUpdate.bind(this), true);
})
.start();
} else {
this.playLogo(this.startUpdate.bind(this), true);
}
}
/**
* 热更新
*/
startUpdate() {
this.upTit.string = "loading...";
this.upPro.node.active = false;
if (!cc.sys.isNative) {
this.loadAppScene();
return;
}
this.setUpdateCall();
let rootpath = jsb && jsb.fileUtils ? jsb.fileUtils.getWritablePath() : "/";
let storageTempPath = rootpath + "remote-assets";
let versionCompareHandle = (versionA, versionB) => {
//cc.log("本地版本:" + versionA + ",远程版本:" + versionB);
if (versionA == versionB) return 0;
let vA = versionA.split(".");
let vB = versionB.split(".");
for (let i = 0, len = vA.length; i < len; ++i) {
let a = parseInt(vA[i]);
let b = parseInt(vB[i] || 0);
if (a != b) return a - b;
}
return (vB.length > vA.length) ? -1 : 0;
}
let os = "";
// 固定返回 false ,即 oldManifest = "project.manifest";
// 也可加载缓存中的manifest,与包内原始版本做区分,am会自动比较较新的版本
// let oldManifest = jsb.fileUtils.isFileExist(storageTempPath + "/project.manifest") ? (storageTempPath + "/project.manifest") : ("project.manifest");
let oldManifest = jsb.fileUtils.isFileExist(rootpath + "project.manifest") ? (rootpath + "project.manifest") : ("project.manifest");
this._am = new jsb.AssetsManager(oldManifest, storageTempPath, versionCompareHandle);
// if (cc.sys.os === cc.sys.OS_ANDROID) {
// // @ts-ignore
// this._am.setMaxConcurrentTask(100);
// }
this.checkUpdate();
}
loadLocalManifest() {
// 固定不相等,应该是因为new的时候传入了manifest路径,而不是""
if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
let rootpath = jsb && jsb.fileUtils ? jsb.fileUtils.getWritablePath() : "/";
let os = "";
let oldManifest = jsb.fileUtils.isFileExist(rootpath + "project.manifest") ? (rootpath + "project.manifest") : ("project.manifest");
this._am.loadLocalManifest(oldManifest);
}
let manifest = this._am.getLocalManifest();
//cc.log("本地版本加载成功:" + manifest.getVersion());
}
checkUpdate() {
//cc.log("---------- 检查更新 ----------");
if (this._updating) {
return;
}
this.loadLocalManifest();
if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
this.upTit.string = "Failed to load local version information!";
this.loadAppScene();
return;
}
this._am.setVerifyCallback((path, asset) => {
return true;
// 当path所在的文件太大时md5运算可能会导致堆栈内存不足
// 正常情况默认返回true,需要验证推荐crc等算法验证,而非md5,需要同时改造version_generator.js
// @ts-ignore
// let data = jsb.fileUtils.getDataFromFile(path);
// let currMD5 = md5(data);
// let expectedMD5 = asset.md5; // 文件MD5值
// if (currMD5 == expectedMD5) {
// //cc.log("MD5校验成功:" + asset.path);
// return true;
// }
// // MD5不相同,删除下载文件
// // if (jsb.fileUtils.isFileExist(path)) {
// // jsb.fileUtils.removeFile(path);
// // }
// //cc.log("MD5校验失败:" + asset.path, "当前MD5:" + currMD5 + " 目标MD5:" + expectedMD5);
// return false;
})
this._am.setEventCallback(this.checkCb.bind(this));
this._am.checkUpdate();
this._updating = true;
}
checkCb(event: jsb.EventAssetsManager) {
let over = false;
let hoting = false;
switch (event.getEventCode()) {
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
//cc.log("没有找到本地manifest文件,跳过热更新!");
over = true;
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
//cc.log("下载manifest文件失败,跳过热更新!");
over = true;
break;
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
//cc.log("解析manifest文件失败,跳过热更新!");
over = true;
break;
case jsb.EventAssetsManager.NEW_VERSION_FOUND:
let bytes = this._am.getTotalBytes();
//cc.log("发现新版本,需要热更新!大小:" + bytes + "bytes");
hoting = true;
this.hotUpdate();
if (this._newVerCall) this._newVerCall(bytes);
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
//cc.log("已经是最新版本了!");
over = true;
break;
default:
return;
}
if (!hoting) {
this._am.setEventCallback(null);
this._updating = false;
}
if (over) {
this.loadAppScene();
return;
}
}
hotUpdate() {
//cc.log("---------- 开始更新 ----------");
if (this._am) {
this.upPro.progress = 0;
this.rate.string = "";
this.progress.string = "";
this.upPro.node.active = true;
this._am.setEventCallback(this.updateCb.bind(this));
this.loadLocalManifest();
this._failCount = 0;
this._am.update();
this._updating = true;
} else {
//cc.log("更新时缺少am,跳过热更新!");
this.loadAppScene();
}
}
updateCb(event: jsb.EventAssetsManager) {
let needRestart = false;
let failed = false;
let over = false;
switch (event.getEventCode()) {
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
//cc.log("没有找到本地manifest文件,跳过热更新!");
failed = true;
over = true;
break;
case jsb.EventAssetsManager.UPDATE_PROGRESSION:
let percent = event.getPercent();
if (!this._currPer) this._currPer = percent || 0;
if (percent >= this._currPer) {
this._currPer = percent;
}
this.upPro.progress = this._currPer;
let downBytes = event.getDownloadedBytes(),
totalBytes = event.getTotalBytes(),
downFiles = event.getDownloadedFiles(),
totalFiles = event.getTotalFiles()
if (this._dowloading) this._dowloading(downBytes, totalBytes, this._currPer);
let msg = event.getMessage();
//cc.log("已更新进度:" + (msg ? msg : this._currPer));
break;
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
//cc.log("下载或解析manifest文件失败,跳过热更新!");
failed = true;
over = true;
break;
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
//cc.log("已经更新到最新版本了!");
failed = true;
over = true;
break;
case jsb.EventAssetsManager.ASSET_UPDATED:
//cc.log("更新资源:" + event.getAssetId());
break;
case jsb.EventAssetsManager.UPDATE_FINISHED:
//cc.log("更新完成: " + event.getMessage());
needRestart = true;
break;
case jsb.EventAssetsManager.UPDATE_FAILED:
//cc.log("更新失败:" + event.getMessage());
this._updating = false;
this.retry();
break;
case jsb.EventAssetsManager.ERROR_UPDATING:
//cc.log("更新错误:" + event.getMessage());
break;
case jsb.EventAssetsManager.ERROR_DECOMPRESS:
//cc.log("解压错误:" + event.getMessage());
break;
default:
break;
}
if (failed) {
this._am.setEventCallback(null);
this._updating = false;
}
if (over) {
this.upTit.string = "loading...";
this.loadAppScene();
return;
}
if (needRestart) {
this._am.setEventCallback(null);
let searchPaths = jsb.fileUtils.getSearchPaths();
let newPaths = this._am.getLocalManifest().getSearchPaths();
let paths = [];
for (let i = 0, len = newPaths.length; i < len; i++) {
paths.push(newPaths[i]);
}
for (let i = 0, len = searchPaths.length; i < len; i++) {
if (paths.indexOf(searchPaths[i]) >= 0) continue;
paths.push(searchPaths[i]);
}
cc.sys.localStorage.setItem("HotUpdateSearchPaths", JSON.stringify(paths));
jsb.fileUtils.setSearchPaths(paths);
cc.audioEngine.stopAll();
cc.game.restart();
}
}
/**
* 失败重试
*/
retry() {
if (this._updating) return;
this._am.downloadFailedAssets();
//cc.log("---------- 失败重试 ----------");
}
}
我直接把构建好的 main.js 换成你这个 解决了
看来 自动构建后的 main.js 虽然上面有那些 搜索路劲 但是后面应该没写好
你试试手动删除热更新缓存,然后调用restar,看会不会卡死?
随便弄个按钮
if (cc.sys.isNative && jsb && jsb.fileUtils) {
let storagePath = jsb.fileUtils.getWritablePath() + "remote-assets/";
if (jsb.fileUtils.isDirectoryExist(storagePath)) {
let flag = jsb.fileUtils.removeDirectory(storagePath);
console.log("删除热更缓存目录" + (flag ? "成功" : "失败"));
}
let storageTempPath = jsb.fileUtils.getWritablePath() + "remote-assets_temp/";
if (jsb.fileUtils.isDirectoryExist(storageTempPath)) {
let flag = jsb.fileUtils.removeDirectory(storageTempPath);
console.log("删除热更Temp缓存目录" + (flag ? "成功" : "失败"));
}
}
cc.game.restart();
你是安卓还是ios会卡死 还是都会
我跟你用的 应该不是同一份 HotUpdate 感觉不准
ios卡死,你试试我给你发的let storagePath = jsb.fileUtils.getWritablePath() + “remote-assets/”;
if (jsb.fileUtils.isDirectoryExist(storagePath)) {
let flag = jsb.fileUtils.removeDirectory(storagePath);
console.log("删除热更缓存目录" + (flag ? "成功" : "失败"));
}
let storageTempPath = jsb.fileUtils.getWritablePath() + "remote-assets_temp/";
if (jsb.fileUtils.isDirectoryExist(storageTempPath)) {
let flag = jsb.fileUtils.removeDirectory(storageTempPath);
console.log("删除热更Temp缓存目录" + (flag ? "成功" : "失败"));
}
}
cc.game.restart();
我试过了 好好的 restar后还是能正常使用