1.7 热更问题

1.7下 热更结束后 调用重启,再走检测更新, new jsb.AssetsManager(this.manifestUrl, storagePath); 会调用loadLocalManifest();
这个方法下 先加载本地的project,manifest, 然后自己和自己比较,判断版本相同后 然后 自己把自己刚下载的资源给删了,
导致下次进入,依然要重新下载

1赞

版本相同的话,应该是这个事件jsb.EventAssetsManager.ALREADY_UP_TO_DATE,打印Already up to date with the latest remote version,为什么会删除刚下载的资源呢?删除的逻辑是你自己新增的么?

还没到真正的版本检测, new jsb.AssetsManager(this.manifestUrl, storagePath),这个方法下就删除了,引擎里删除的

   loadLocalManifest(); 
   if (_localManifest->isLoaded())
   {
       // Compare with cached manifest to determine which one to use
       if (cachedManifest)
       {
           bool localNewer = _localManifest->versionGreater(cachedManifest, _versionCompareHandle);
           if (localNewer)
           {
               // Recreate storage, to empty the content
               _fileUtils->removeDirectory(_storagePath);
               _fileUtils->createDirectory(_storagePath);
               CC_SAFE_RELEASE(cachedManifest);
           }
           else
           {
               CC_SAFE_RELEASE(_localManifest);
               _localManifest = cachedManifest;
           }
       }
       prepareLocalManifest();
   }

你用最新的panda写的hotupdate脚本应该不会有这种问题的,可以先运行下官方的例子

用的就是git上下的例子 tutorial-hot-update

测试发现是 调用 cc.game.restart(); 后 游戏重启 自动走了 AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath) ,manifestUrl 带了地址,然后删掉了manifestUrl的目录,但是不知道为什么会自动调用这个方法

cc.game.restart(); 删除 手动重启 之后 热更新就会正常

你修改了hotupdate脚本么?可以把全部的热更脚本贴出来么?

cc.Class({
extends: cc.Component,

properties: {
    m_label_ResVersion: cc.Label,
    m_label_updateTips: cc.Label,

    manifestUrl: {
        default: null,
        url    : cc.RawAsset
    },
    _updating  : false,
    _needUpdate: false,
},

//检查更新回调函数
checkCb: function (event) {

    switch (event.getEventCode()) {
        case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
            cc.log("未发现本地配置文件");
            this.m_label_updateTips.string = "未发现本地配置文件";
            break;
        case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
        case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
            cc.log("下载配置文件失败");
            this.m_label_updateTips.string = "下载配置文件失败";
            break;
        case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
            cc.log("已是最新版本");
            this.m_label_updateTips.string = "当前为最新版本";
            GlobalEventManager.getInstance().emitEvent(window.LocalMessage, { tag: window.LocalMsgType.UPDATE_NOT_MESSAGE });
            break;
        case jsb.EventAssetsManager.NEW_VERSION_FOUND:
            cc.log("发现版本需要更新");
            this._needUpdate               = true;
            this.m_label_updateTips.string = "发现版本需要更新";
            break;
        default:
            return;
    }
    LoadingView.dismiss();
    cc.eventManager.removeListener(this._checkListener);
    this._checkListener = null;
    this._updating      = false;
    if (this._needUpdate) {
        GlobalEventManager.getInstance().emitEvent(window.LocalMessage, { tag: window.LocalMsgType.UPDATE_NEED_MESSAGE });
        cc.log("需要更新");
        this.hotUpdate();
    }

},

//更新回调函数
updateCb: function (event) {
    var needRestart = false;
    var failed      = false;
    switch (event.getEventCode()) {
        case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
            cc.log('No local manifest file found, hot update skipped.');
            failed = true;
            break;
        case jsb.EventAssetsManager.UPDATE_PROGRESSION:
            var percent       = event.getPercent();
            var percentByFile = event.getPercentByFile();

            cc.log("updateCb1-----percent" + percent + "percentByFile" + percentByFile);

            var msg = event.getMessage();
            if (msg) {
                cc.log("updateCb-----", msg);
            }
            this.m_label_updateTips.string = "更新进度:" + (percent * 100).toFixed(0) + "%";
            break;
        case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
        case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
            cc.log('Fail to download manifest file, hot update skipped.');
            failed = true;
            break;
        case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
            cc.log('Already up to date with the latest remote version.');
            failed = true;
            break;
        case jsb.EventAssetsManager.UPDATE_FINISHED:
            cc.log('更新完成 ' + event.getMessage());
            needRestart = true;
            break;
        case jsb.EventAssetsManager.UPDATE_FAILED:
            cc.log('更新失败 ' + event.getMessage());

            this._failCount++;
            if (this._failCount < 5) {
                this._am.downloadFailedAssets();
            }
            else {
                cc.log('Reach maximum fail count, exit update process');
                this._failCount = 0;
                failed          = true;
                ToastView.show("数据更新失败");
            }
            break;
        case jsb.EventAssetsManager.ERROR_UPDATING:
            cc.log('更新错误: ' + event.getAssetId() + ', ' + event.getMessage());
            break;
        case jsb.EventAssetsManager.ERROR_DECOMPRESS:
            cc.log(event.getMessage());
            break;
        default:
            break;
    }

    if (failed) {
        cc.eventManager.removeListener(this._updateListener);
        this._updateListener = null;
        this._updating       = false;
    }

    if (needRestart) {
        cc.eventManager.removeListener(this._updateListener);
        this._updateListener = null;
        var searchPaths      = jsb.fileUtils.getSearchPaths();
        var newPaths         = this._am.getLocalManifest().getSearchPaths();
        console.log(JSON.stringify(newPaths));
        Array.prototype.unshift(searchPaths, newPaths);

        cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
        cc.log("--------------HotUpdateSearchPaths----------------" + JSON.stringify(searchPaths));
        jsb.fileUtils.setSearchPaths(searchPaths);
        cc.game.restart();
        cc.log("资源更热完成---重启游戏");
    }
},

hotUpdate: function () {
    if (this._am && !this._updating) {
        this._updateListener = new jsb.EventListenerAssetsManager(this._am, this.updateCb.bind(this));
        cc.eventManager.addListener(this._updateListener, 1);

        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
            this._am.loadLocalManifest(this.manifestUrl);
        }

        this._failCount = 0;
        this._am.update();
        this._updating = true;
        LoadingView.dismiss();
    }
},

onLoad () {
    // GameSystem.getInstance().initConfig();
},

start () {
    if (!cc.sys.isNative) {
        cc.log("非原生版本不调用热更新");
        GlobalEventManager.getInstance().emitEvent(window.LocalMessage, { tag: window.LocalMsgType.UPDATE_NOT_MESSAGE });
        return;
    }

    let storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'project-remote-asset');
    let remoteUrl   = storagePath + "/project.manifest";

    let fullPath = "";
    if (jsb.fileUtils.isFileExist(remoteUrl)) {
        fullPath = remoteUrl;
        cc.log("有下载配置文件");
    }
    else {
        fullPath = cc.url.raw("resources/project.manifest");
        cc.log("没有下载配置文件,使用本地配置");
    }

    cc.log("manifestUrl =" + this.manifestUrl);
    var self = this;
    cc.loader.load(fullPath, function (error, data) {
        if (error) {
            cc.log("error :    " + error);
            return;
        }
        self.m_label_ResVersion.string = "资源版本:v" + JSON.parse(data).version;
        cc.log("资源版本:v" + JSON.parse(data).version)
    });

    cc.log("检测更新");
    this.m_label_updateTips.string = "检测更新";

    this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'project-remote-asset');
    cc.log('----------------hotUpdate---------Storage path for remote asset : ' + this._storagePath);

    this.versionCompareHandle = function (versionA, versionB) {
        cc.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;
        }
    };

    this._am = new jsb.AssetsManager("", this._storagePath, this.versionCompareHandle);
    if (!cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) {
        this._am.retain();
    }

    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) {
            // panel.info.string = "Verification passed : " + relativePath;
            return true;
        }
        else {
            // panel.info.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';
            return true;
        }
    });

    if (cc.sys.os === cc.sys.OS_ANDROID) {
        this._am.setMaxConcurrentTask(2);
    }

    this.checkUpdate();
    // this.hotUpdate();
},

checkUpdate: function () {
    if (this._updating) {
        return;
    }
    cc.log("this._am.getState() === jsb.AssetsManager.State.UNINITED=" + this._am.getState() === jsb.AssetsManager.State.UNINITED);
    if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
        this._am.loadLocalManifest(this.manifestUrl);
    }
    if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
        this.m_label_updateTips.string = 'Failed to load local manifest ...';
        return;
    }
    this._checkListener = new jsb.EventListenerAssetsManager(this._am, this.checkCb.bind(this));
    cc.eventManager.addListener(this._checkListener, 1);
    cc.log("开始检测版本");
    this._am.checkUpdate();
    this._updating = true;
},


onDestroy: function () {
    if (this._updateListener) {
        cc.eventManager.removeListener(this._updateListener);
        this._updateListener = null;
    }
    if (this._am && !cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) {
        this._am.release();
        this._am = null;
    }
}

});

代码基本是复制粘贴的,只是把手动点击 改 自己动检测下载

cc.log(“资源更热完成—重启游戏”);
cc.game.restart();

这个重启后有执行么?
这个本地预置的描述文件可以直接写成json字符串,配置在这个脚本里,就不用load了。

fullPath = cc.url.raw(“resources/project.manifest”);
cc.log(“没有下载配置文件,使用本地配置”);
重启没执行, 这个方法只是读下当前最新的资源 版本

    this._am = new jsb.AssetsManager("", this._storagePath, this.versionCompareHandle);

自己调用的应该是
AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath, const VersionCompareHandle& handle)
三个参数,第一个manifestUrl 为空的

if (manifestUrl.size() > 0)
{
    loadLocalManifest(manifestUrl);
}

这段代码不走

但是重启后 自动调用了
AssetsManagerEx* AssetsManagerEx::create(const std::string& manifestUrl, const std::string& storagePath)
manifestUrl是下载后的配置文件,然后 走了 loadLocalManifest(manifestUrl); 把资源删除了

这个是异步的

是重启后 整个 start 都没执行,重启的时候 onDestroy 也没调用,手动调用了,也还是不行

和这个没关系的,我屏蔽测试过了

你说的这个方法在哪个方法里?start没执行的话,重启后执行的最先是哪个方法?

new jsb.AssetsManager(this.manifestUrl, storagePath) 我没有使用这个方法,
只有 new jsb.AssetsManager("", this._storagePath, this.versionCompareHandle);
这个热更新代码 都在这里,其他没地方
图片就是重启后自动调用的断点,
工程是重新build的,用的link

是default

可是这个方法在start里啊,那就是重启后执行start了吧?

你看这个方法是三个参数的 而且 第一个是空的 ,但是自动调用的 是两个参数的,第一个不为空
看屏幕下的log,start的方法也没执行,log没打印,
重启后,整个hotupdate,方法里 就执行一句话
收到消息 jsb.EventAssetsManager.ALREADY_UP_TO_DATE
打印是最新版本 ,然后没了

杀进程,重进游戏,又开始下载资源