1.9.3版本,jsb.fileUtils.getWritablePath() 第二次获取路径发生改变

ccc版本1.9.3、模拟器,ios,android 都有问题。

自定义manifest,热更新的时候会把更新下来的文件存放到模拟器的可写路径内,第二次点击热更新会提示已经是最新版本,再点击一次更新的时候会在系统的文档目录重新创建一份目录,并重新进入热更新逻辑了,native上也有这个问题,如果用把macifest拖动绑定到节点上的就没有这个问题,麻烦引擎组帮忙看看,附件在下面


pro_hall.zip (222.6 KB)
居然没人理。。。。。
手动贴上代码

const { ccclass, property } = cc._decorator;

export const GameType = {
HALL: “hall”,
GAME1: “game1”,
GAME2: “game2”
}

@ccclass
export class HotUpdate {

private _assetsManager: any = null;
private _updateListener = null;
private _checkListener = null;

private _remoteURL: string = "http://192.168.2.2/myGame";
private _storagePath: string = null;
private _manifestPath: string = null;

// protected onLoad(): void {

// }

private initPath(gameType: string): void {
    let self = this;
    if (cc.sys.isNative) {
        let writablePath: string = jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/';
        self._storagePath = `${writablePath}hotupdate/${gameType}`;
        self._manifestPath = `${self._storagePath}/project.manifest`;
        console.log("initPath() >>> self._manifestPath = ", self._manifestPath);
    } else {
        console.log("initPath() >>> 不是原生平台");
    }
}

//** 对比版本号 */
private onVersionCompareHandle(versionA: any, versionB: any): number {
    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;
    }
}

//** 创建manifest文件并且写入本地 */
private onCreateManifest(gameType: string): any {
    console.log("onCreateManifest() >>> gameType = ", gameType);
    let self = this;
    var url: string = `${self._remoteURL}/${gameType}`;
    let remoteManifestUrl: string = `${url}/project.manifest`;
    let remoteVersionUrl: string = `${url}/version.manifest`;
    var customManifestStr: any = JSON.stringify({
        "packageUrl": url,
        "remoteManifestUrl": remoteManifestUrl,
        "remoteVersionUrl": remoteVersionUrl,
        "version": "1.0.0",
        "assets": {},
        "searchPaths": []
    });
    let manifest: any = new jsb.Manifest(customManifestStr, self._storagePath);
    let fullPath: any = `${self._storagePath}/project.manifest`;
    var isOK = jsb.fileUtils.writeStringToFile(customManifestStr, fullPath);
    console.log("onCreateManifest() >>> fullPath = ", fullPath);
    console.log('onCreateManifest() >>> 写入文件:', (isOK ? 'success' : 'error'));
    console.log("onCreateManifest() >>> customManifestStr = ", customManifestStr);
    return manifest;
}

/**初始化加载控制器*/
private onCreateJSBAssetsManager(gameType: string): void {
    let self = this;
    self.removeListener();

    if (jsb.fileUtils.isFileExist(self._manifestPath)) {
        console.log("onCreateJSBAssetsManager() >>> 加载本地manifest文件");
        // self._assetsManager.loadLocalManifest(self._manifestPath);
    } else {
        console.log("onCreateJSBAssetsManager() >>> 加载自定义manifest");
        let manifest: any = self.onCreateManifest(gameType);
        // self._assetsManager.loadLocalManifest(manifest, self._storagePath);
    }

    if (!self._assetsManager) {
        self._assetsManager = new jsb.AssetsManager(self._manifestPath, self._storagePath, self.onVersionCompareHandle);
    }
    if (!cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) {
        self._assetsManager.retain();
    }

    if (!self._assetsManager.getLocalManifest() || !self._assetsManager.getLocalManifest().isLoaded()) {
        console.log("onCreateJSBAssetsManager() >>> 加载本地manifest失败");
        return;
    }

    let version: any = self._assetsManager.getLocalManifest().getVersion();
    let versionStr: string = `当前版本:v${version}`;
    console.log(versionStr);

    self._assetsManager.setVerifyCallback(function (path: any, asset: any) {
        let compressed = asset.compressed;
        let expectedMD5 = asset.md5;
        let relativePath = asset.path;
        let size = asset.size;
        if (compressed) {
            return true;
        } else {
            return true;
        }
    });
    if (cc.sys.os === cc.sys.OS_ANDROID) {
        self._assetsManager.setMaxConcurrentTask(2);
    }
}

//检查版本
public onCheckUpdate(gameType: string) {
    if (!cc.sys.isNative)
        return;
    let self = this;
    self.initPath(gameType);
    self.onCreateJSBAssetsManager(gameType);
    console.log("添加监听:checkListener(gameType) = ", gameType);
    self._checkListener = new jsb.EventListenerAssetsManager(self._assetsManager, self.onCheckUpdateCallback.bind(self));
    cc.eventManager.addListener(self._checkListener, 1);
    self._assetsManager.checkUpdate();
}

public onStartUpdate(gameType?: string): void {
    let self = this;
    if (!self._assetsManager) {
        // self.onCreateJSBAssetsManager(gameType);
    } else {
        console.log("正在更新...");
        self._updateListener = new jsb.EventListenerAssetsManager(self._assetsManager, self.onUpdateCallback.bind(self));
        cc.eventManager.addListener(self._updateListener, 1);

        // if (self._assetsManager.getState() === jsb.AssetsManager.State.UNINITED) {
        //     console.log("onHotUpdate() >>> jsb.AssetsManager.State.UNINITED");
        //     //    let manifest = new jsb.Manifest(customManifestStr, this._storagePath)//屏蔽原因,不自定义manifest
        //     //    this.assetsManager.loadLocalManifest(manifest, this._storagePath);
        //     //    let data =  jsb.fileUtils.getStringFromFile(manifest);
        //     //    let manifestJson: any = jsb.fileUtils.getStringFromFile(this.manifestUrl);
        //     self._assetsManager.loadLocalManifest(self._manifestPath);
        // }
        self._assetsManager.update();
    }
}

/**检查更新监听*/
private onCheckUpdateCallback(event: any) {
    if (!event) {
        return;
    }
    let self = this;
    let msg: string = "";
    let isNeedUpdate: boolean = false;
    let eventCode = event.getEventCode();
    console.log('检查更新eventCode: ', eventCode);
    switch (eventCode) {
        case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
            msg = "0 >>> 检查更新失败:ERROR_NO_LOCAL_MANIFEST";
            console.log(msg);
            break;

        case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            msg = "1 >>> 检查更新失败:ERROR_DOWNLOAD_MANIFES";
            console.log(msg);
            break;

        case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
            msg = "2 >>> 检查更新失败:ERROR_PARSE_MANIFEST >>> 解析manifest文件失败";
            console.log(msg);
            break;

        case jsb.EventAssetsManager.NEW_VERSION_FOUND:
            msg = "3 >>> 发现新版本";
            isNeedUpdate = true;
            console.log(msg);
            break;

        case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
            msg = "4 >>> 已经是最新版本";
            console.log(msg);
            self.removeListener();
            break;

        // case jsb.EventAssetsManager.UPDATE_PROGRESSION:   //5
        //     msg = "5 >>> 检查更新:UPDATE_PROGRESSION";
        //     console.log(msg);
        //     break;

        case jsb.EventAssetsManager.UPDATE_FAILED://9
            console.log('9 >>> 检查更新:UPDATE_FAILED');

            break;

        case jsb.EventAssetsManager.ERROR_DECOMPRESS://10
            console.log('10 >>> 检查更新:文件解压失败!');

            break;

        default:
            msg = "检查更新失败:未知错误,eventCode = " + eventCode;
            console.log(msg);
            return;
    }
    if (isNeedUpdate) {
        console.log("isNeedUpdate >>>>");
        cc.eventManager.removeListener(self._checkListener);
        self._checkListener = null;
        self.onStartUpdate();
    } else {

    }
}

/**加载更新监听*/
private onUpdateCallback(event: any) {
    let self = this;
    let needRestart: boolean = false;
    let failed: boolean = false;
    let eventCode: any = event.getEventCode();
    console.log("onUpdateCallback() eventCode =", eventCode);
    switch (eventCode) {
        case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
            console.log('加载更新失败:ERROR_NO_LOCAL_MANIFEST');
            failed = true;
            break;

        case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
            console.log('加载更新失败:ERROR_DOWNLOAD_MANIFEST');
            failed = true;
            break;

        case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
            console.log('加载更新失败:ERROR_PARSE_MANIFEST');
            failed = true;
            break;

        case jsb.EventAssetsManager.UPDATE_FAILED:
            console.log('加载更新失败:UPDATE_FAILED');
            failed = true;
            break;

        case jsb.EventAssetsManager.ERROR_UPDATING:
            console.log('加载更新失败:ERROR_UPDATING >>> assetId = ' + event.getAssetId() + ',msg = ' + event.getMessage());
            failed = true;
            break;

        case jsb.EventAssetsManager.ERROR_DECOMPRESS:
            console.log('加载更新失败:ERROR_DECOMPRESS');
            failed = true;
            break;

        case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
            console.log('已经是最新版本');
            failed = true;
            break;

        case jsb.EventAssetsManager.UPDATE_PROGRESSION:
            let totalBytes: any = event.getTotalBytes();
            let downloadedBytes: any = event.getDownloadedBytes();
            let byFile: any = event.getPercentByFile();
            let percent: any = event.getPercent()
            if (!isNaN(byFile)) {
                let per = Math.ceil(byFile * 100)
            }
            let totalBytesStr: string = (totalBytes / 1024 / 1024).toFixed(2) + "MB";
            let bytesStr: string = (downloadedBytes / 1024 / 1024).toFixed(2) + 'MB';
            let showStr: string = '正在更新:' + bytesStr + "/" + totalBytesStr;
            console.log(showStr);
            break;

        case jsb.EventAssetsManager.ASSET_UPDATED:
            console.log("asset updated");
            break;

        case jsb.EventAssetsManager.UPDATE_FINISHED:
            needRestart = true;
            failed = false;
            let localManifest: any = self._assetsManager.getLocalManifest();
            let version: any = localManifest.getVersion();
            console.log('更新完成,version = ', version);
            break;

        default:
            console.log("加载异常,", event.getMessage());
            break;
    }
    if (failed) {
        console.log("下载文件失败,是否继续重试?");
        self._assetsManager.downloadFailedAssets();
    } else {
        if (needRestart) {
            let searchPaths: any = jsb.fileUtils.getSearchPaths();
            let localManifest: any = self._assetsManager.getLocalManifest();
            let newPaths: any = localManifest.getSearchPaths();
            console.log("newPaths = ", newPaths);
            Array.prototype.unshift.apply(searchPaths, newPaths);
            cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(newPaths));
            jsb.fileUtils.setSearchPaths(searchPaths);

            self.removeListener();
            cc.audioEngine.stopAll();
            cc.game.restart();
        }
    }
    console.log("\n");
}

private removeListener(): void {
    let self = this;
    if (self._checkListener) {
        cc.eventManager.removeListener(self._checkListener);
        self._checkListener = null;
    }
    if (self._updateListener) {
        cc.eventManager.removeListener(self._updateListener);
        self._updateListener = null;
    }
    if (self._assetsManager && !cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) {
        self._assetsManager.release();
    }
    if (self._assetsManager) {
        self._assetsManager = null;
    }
}

// protected onDestroy(): void {
//     if (this._assetsManager) {
//         this.removeListener();
//     }
// }

}

1赞

自己顶。。。。。。。

:joy: 快来人快来人

下午看看什么情况!要不要升级到2.x呢?

项目是在1.9.3上面开发的,尝试过升级到最新版,需要改动的地方太多,很多莫名其妙的报错,只能在1.9.3这个版本了,热更新成功,重启app后也是正常显示到新版本,重新点一下更新就有问题,

而且图中两部分只能写其中一个,如果多了case5,直接把checkLister给remove掉了,(上图是我重新修改过的,附近中可能有点不一样)

请问有使用官方的demo测试过吗?

ios
热更我自己这边 用xcode 第二次跑 就会热更失效
但是 正常跑 没问题 所以也没在意
不知道 对你有帮助没
1.8.2我的
之前 1.6.2没这个问题
不过不影响使用呢 就是 调试需要每次 删除之前的包

官方的demo是绑定manifest到节点上的,我的是获取本地文件的

调试的时候每次都是删除旧包的,更新完后用本地的manfiest检测更新,是没问题的,然后再点击一次本地的manifest检测更新,就出问题了

看了下,感觉第一次更新成功,第二次在更新第一次的会被删除重新下载
这里第一次和第二次判断的manifest文件是一样的

第二次下载目录变更难道是jsb.fileUtils.getWritablePath()变了?

https://www.jianshu.com/p/842896e5de10

是的没错,我这边打印了log,不管是模拟器,andorid 还是ios ,jsb.fileUtils.getWritablePath() 路径会发生改变,第二次的话会删除原来目录下面的文件,不知道为什么这样处理???

同时,如果我第一次没有目录的时候,jsb.fileUtils.getWritablePath(),然后写入文件,第一次总会是写文件失败,如果文件夹存在,才能够写入成功

跟使用的mac 平台没有关系

附件重新上传了

表现是不是热更新逻辑没跑起来?可能是回调函数失效了,在调用 checkUpdate 和 update 的时候加个延迟。
this.node.runAction(cc.sequence(cc.delayTime(0.1), cc.callFunc( ()=>{
this._am.checkUpdate()
} )));

还有代码中的 this._am.update(); 也加载延迟。

不是热更新逻辑没跑起来,这里也应该不是延迟的问题,我看了c++文件,里面有逻辑就是把文件删除掉的,获取可写路径第二次返回的也是错误的!!!

似乎是使用了自定义的manifest出错了的,之前我也是想把manifest中的热更新地址随时替换,就读出来从新构造下,在开始热更新就和你的表现一样的了。