IOS热更新重启就会回退部分资源

  • 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版本的
有没有同样情况的大佬帮忙看看

加上

,退出再进也不会回退了

还有一个问题:你热更新完之后,试试手动清理热更新目录,然后调用cc.game.restart(),看会不会卡住

这么做的目的,清除目录,重新热梗新
我目前游戏会卡死,不知道你遇到没有

试了一下 还是不行 这两句话 昨晚也加过差不多的 也是不行

你把你的搜索路劲打印看下,第二次进的时候

搜索路劲貌似没什么问题 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后还是能正常使用