v2.4.14热更后无法找到spine使用的多张图片?

热更的新版本使用的spine动画 使用了多张图片
结果热更后报错,找不到spine动画的图片
这个大家有遇到过吗?

是不是超过20482048了?我这边有多张的没有问题,不超过20482048就行.

不确定,多张都是 1024*1024的
现在是 更新 357个文件,大概42mb
更新很难成功,就是下载到70%左右 提示更新失败
有时更到100% 提示更新失败
基本全部更新完 没提示失败
但重启后到 游戏封面,有个多图的spine动画不显示,游戏卡死了
android studio 后台提示

是游戏直接重启,cc.game.restart吗??
还是apk杀进程重启?
如果是cc.game.restart重启失败的话,杀进程重进,能进去吗,如果能重新进游戏,那就是cc.game.restart问题.
重启方式就改成apk重启(apk重启不难,直接问AI要代码).
更新完成后,有对比过文件是否正确?文件是否完整?
这些都可能是查问题的方向.

cc.game.restart重启失败的 杀进程重进也不行

import * as Tool from ‘./Tool’

const maxRetry = 95; // 最大重试次数

let HotUpdate = cc.Class({

extends: cc.Component,

properties: {

    manifestUrl: { default: null, type: cc.Asset, tooltip: '编译后的project.manifest文件' },

    PROMPT_INFORMATION: { default: null, type: cc.Component, tooltip: '提示信息' },

    DOWNLOAD_PROGRESS: { default: null, type: cc.ProgressBar, tooltip: '下载进度条' },

    DOWNLOAD_INFO: { default: null, type: cc.Component, tooltip: '下载进度比率' },

    NETWORK_WAITING: { default: null, type: cc.Node, tooltip: '联网等待动画' },

    SKIP_BT: { default: null, type: cc.Node, tooltip: '跳过按钮' },

    UPDATA_BT: { default: null, type: cc.Node, tooltip: '更新按钮' },

    LOG: { default: null, type: cc.Label, tooltip: 'LOG' },

    _updating: false,

    _canRetry: false,

    _storagePath: '',

    _versionB: '',//服务器版本

    _updateFileIndex:0,

    _retryCount : 0,

},

//网络通信中 需要等待网络

network_ing() {

    this.NETWORK_WAITING.active = true;

    this.SKIP_BT.active = false;

    this.UPDATA_BT.active = false;

},

//网络通信 结束

network_over() {

    this.NETWORK_WAITING.active = false;

    this.SKIP_BT.active = true;

},

//资源检测中

checkCb: function (event) {

    switch (event.getEventCode()) {

        case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST://0

            //'No local manifest file found, hot update skipped.';

            this.PROMPT_INFORMATION.string = '找不到本地清单文件,已跳过热更新。';

            this.network_over();

            break;

        case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST://1

        case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST://2

            //'Fail to download manifest file, hot update skipped.';

            this.PROMPT_INFORMATION.string = '下载清单文件失败,已跳过热更新。';

            this.network_over();

            break;

        case jsb.EventAssetsManager.ALREADY_UP_TO_DATE://4

            //'Already up to date with the latest remote version.';

            this.PROMPT_INFORMATION.string = '已经是最新的远程版本。';

            this.network_over();

            break;

        case jsb.EventAssetsManager.NEW_VERSION_FOUND://3

            let totalBytes = this._am.getTotalBytes();

            //'New version found, please try to update. (' + this._am.getTotalBytes() + ')';

            //console.error('this._am:', this._am);

            if (totalBytes == 0) {

                this.reStartGame(null);

            } else {

                let KB = totalBytes/1024;

                let MB = KB/1024;

                let BYTE = totalBytes;

                if (MB > 1) {

                    BYTE = Math.floor(MB) + 'MB';

                } else if (KB > 1) {

                    BYTE = Math.floor(KB) + 'KB';

                }

                this.PROMPT_INFORMATION.string = `找到新版本:${this._versionB} (${BYTE})`;

                //console.error('checkCb NEW_VERSION_FOUND totalBytes:', totalBytes);

                this.UPDATA_BT.active = true;

                this.network_over();

            }

            break;

        default:

            return;

    }

    this._am.setEventCallback(null);

    this._checkListener = null;

    this._updating = false;

},

//资源下载中

updateCb: function (event) {

    var needRestart = false;

    var failed = false;

    console.error('HotUpdate.. updateCb.event:', event);

    console.error('HotUpdate.. this._am:', this._am);

    let fileInfo = this.splitPath(event.getAssetId());

    let filePath = fileInfo[0];

    let fileName = fileInfo[1];

    //https://github.com/cocos-creator-packages/jsb-adapter/blob/master/engine/jsb-assets-manager.js

    // jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST = 0;

    // jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST = 1;

    // jsb.EventAssetsManager.ERROR_PARSE_MANIFEST = 2;

    // jsb.EventAssetsManager.NEW_VERSION_FOUND = 3;

    // jsb.EventAssetsManager.ALREADY_UP_TO_DATE = 4;

    // jsb.EventAssetsManager.UPDATE_PROGRESSION = 5;

    // jsb.EventAssetsManager.ASSET_UPDATED = 6;

    // jsb.EventAssetsManager.ERROR_UPDATING = 7;

    // jsb.EventAssetsManager.UPDATE_FINISHED = 8;

    // jsb.EventAssetsManager.UPDATE_FAILED = 9;

    // jsb.EventAssetsManager.ERROR_DECOMPRESS = 10;

    switch (event.getEventCode())

    {

        case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST://0

            //'No local manifest file found, hot update skipped.';

            this.PROMPT_INFORMATION.string = '找不到本地清单文件,已跳过热更新。';

            failed = true;

            this.network_over();

            break;

        case jsb.EventAssetsManager.UPDATE_PROGRESSION: //5 下载进度

            // console.error('panel_info_string:event.getPercent():', event.getPercent());

            // console.error('panel_info_string:event.getPercentByFile():', event.getPercentByFile());

            // console.error('HotUpdate.. updateCb.event.getMessage=', event.getMessage());

            // console.error('HotUpdate.. updateCb.event.getAssetId=', event.getAssetId());

            let loadedFiles = event.getDownloadedFiles() + ' / ' + event.getTotalFiles();

            let loadedBytes = event.getDownloadedBytes() + ' / ' + event.getTotalBytes();

            // console.error('panel_info_string:loadedFiles:', loadedFiles);

            // console.error('panel_info_string:loadedBytes:', loadedBytes);

            this.LOG.string = event.getMessage() + '\n' + filePath + '\n' + fileName;

            let percent = event.getPercent() || 0;

            if (percent > 1) {

                percent = 1;

            }

            this.DOWNLOAD_PROGRESS.progress = percent;

            this.DOWNLOAD_INFO.string = Math.ceil(percent * 100) + '%';

            this.PROMPT_INFORMATION.string = '更新下载中...';

            let msg = event.getMessage();

            if (msg&&msg.length>0) {

                //this.PROMPT_INFORMATION.string = msg; //'Start to update 7 files from remote package.'

                console.error('HotUpdate.. updateCb.更新下载中 msg:', msg);

            }

            this.network_ing();

            break;

        case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST://1

        case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST://2

            //'Fail to download manifest file, hot update skipped.';

            this.PROMPT_INFORMATION.string = '下载清单文件失败,已跳过热更新。';

            failed = true;

            this.network_over();

            break;

        case jsb.EventAssetsManager.ALREADY_UP_TO_DATE://4

            //'Already up to date with the latest remote version.';

            this.PROMPT_INFORMATION.string = '已经是最新的远程版本。';

            failed = true;

            this.network_over();

            break;

        case jsb.EventAssetsManager.UPDATE_FINISHED://8

            //'Update finished. ' + event.getMessage();

            //console.error('HotUpdate.. updateCb.更新完成。=', event.getAssetId());

            this.PROMPT_INFORMATION.string = '更新完成。' + event.getMessage();

            needRestart = true;

            this.network_over();

            break;

        case jsb.EventAssetsManager.UPDATE_FAILED://9

            const errorMessage = event.getMessage() || '未提供错误信息';

            Tool.print2jni(`HotUpdate.. updateCb.更新失败=${event.getAssetId()}, 错误信息: ${errorMessage}`);

            this.PROMPT_INFORMATION.string = `更新失败: ${event.getAssetId()}, 原因: ${errorMessage}`;

            this.LOG.string = `更新失败: ${errorMessage}\n${filePath}\n${fileName}`;

            //let panel.retryBtn.active = true;

            this._updating = false;

            this._canRetry = true;

            this.network_over();

            break;

        case jsb.EventAssetsManager.ERROR_UPDATING://7

            //'Asset update error: ' + event.getAssetId() + ', ' + event.getMessage();

            Tool.print2jni('HotUpdate.. updateCb.资源更新错误=', event.getAssetId());

            this.PROMPT_INFORMATION.string = '资源更新错误: ' + event.getMessage();

            this.LOG.string = event.getMessage() + '\n' + filePath + '\n' + fileName;

            //console.error('panel_info_string:this.PROMPT_INFORMATION.string:', this.PROMPT_INFORMATION.string);

            //this.network_over();

            const failedAsset = event.getAssetId();

            if (this._retryCount < maxRetry) {

                this._retryCount++;

                console.warn(`重试下载 ${failedAsset}, 次数: ${this._retryCount}`);

                //assetsManager.downloadFailedAssets(); // 重试失败文件

                this._am.downloadFailedAssets(); // 重试失败文件

            } else {

                console.error('文件下载失败超过重试次数');

                this.PROMPT_INFORMATION.string = '文件下载失败超过重试次数';

                // 清除缓存并重置

                //this._am.removeStorage();

                this._retryCount = 0;

            }

            break;

        case jsb.EventAssetsManager.ERROR_DECOMPRESS://10

            const decompressError = event.getMessage() || '未提供解压缩错误信息';

            console.error(`HotUpdate.. updateCb.解压缩错误=${event.getAssetId()}, 错误信息: ${decompressError}`);

            this.PROMPT_INFORMATION.string = `解压缩错误: ${decompressError}`;

            this.LOG.string = `解压缩错误: ${decompressError}\n${filePath}\n${fileName}`;

            this.network_over();

            break;

        case jsb.EventAssetsManager.ASSET_UPDATED://6

            this._updateFileIndex += 1;

            //console.error(`HotUpdate.. updateCb.${this._updateFileIndex}.资源下载中= ${event.getAssetId()}`);

            this.PROMPT_INFORMATION.string = '资源下载中...';//event.getMessage()

            this.LOG.string = event.getMessage() + '\n' + filePath + '\n' + fileName;

            this.network_ing();

            break;

        default:

            break;

    }

    // console.error('updateCb:failed:', failed);

    // console.error('updateCb:needRestart:', needRestart);

    if (failed) {

        this._am.setEventCallback(null);

        this._updateListener = null;

        this._updating = false;

    }

    if (this._canRetry) {

        this.checkUpdate();

    }

    if (needRestart) {

        try {

            this._am.setEventCallback(null);

            this._updateListener = 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));

            //console.error('updateCb:searchPaths:', searchPaths);

            jsb.fileUtils.setSearchPaths(searchPaths);

            //cc.audioEngine.stopAll();

            //console.error('updateCb:needRestart:', needRestart, 'VVV this.reStartGame(null); VVV');

            this.reStartGame(null);

        } catch (error) {

            console.error('设置搜索路径或重启游戏时出错:', error);

            this.PROMPT_INFORMATION.string = `设置搜索路径或重启游戏时出错: ${error.message}`;

            this.network_over();

        }

    }

},

reStartGame(event) {

    cc.audioEngine.stopMusic();

    cc.game.restart();

},



retry: function () {

    if (!this._updating && this._canRetry) {

        //let panel.retryBtn.active = false;

        this._canRetry = false;

        //'Retry failed Assets...';

        this.PROMPT_INFORMATION.string = '重新下载失败的资源...';

        this._am.downloadFailedAssets();

    }

},

//开始检测更新,是否有新版需要更新

checkUpdate: function () {

    //console.error('checkUpdate:0:');

    if (this._updating) {

        //'Checking or updating ...';

        this.PROMPT_INFORMATION.string = '检查更新中...';

        this.network_ing();

        return;

    }

    //console.error('checkUpdate:this._am.getState():', this._am.getState());

   

    //https://github.com/cocos-creator-packages/jsb-adapter/blob/master/engine/jsb-assets-manager.js

    // jsb.AssetsManager.State = {

    //     UNINITED : 0,

    //     UNCHECKED : 1,

    //     PREDOWNLOAD_VERSION : 2,

    //     DOWNLOADING_VERSION : 3,

    //     VERSION_LOADED : 4,

    //     PREDOWNLOAD_MANIFEST : 5,

    //     DOWNLOADING_MANIFEST : 6,

    //     MANIFEST_LOADED : 7,

    //     NEED_UPDATE : 8,

    //     READY_TO_UPDATE : 9,

    //     UPDATING : 10,

    //     UNZIPPING : 11,

    //     UP_TO_DATE : 12,

    //     FAIL_TO_UPDATE : 13

    // };

    if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {

        // Resolve md5 url

        var url = this.manifestUrl.nativeUrl;

        //console.error('checkUpdate:Resolve 1 url:',url);

        if (cc.loader.md5Pipe) {

            url = cc.loader.md5Pipe.transformURL(url);

            //console.error('checkUpdate:Resolve 2 url:', url);

        }

        this._am.loadLocalManifest(url);

    }

    if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {

        //'Failed to load local manifest ...';

        this.PROMPT_INFORMATION.string = '无法加载本地清单...';

        this.network_over();

        return;

    }

    this._am.setEventCallback(this.checkCb.bind(this));

    this._am.checkUpdate();

    this._updating = true;

},

//开始更新资源

hotUpdate: function () {

    this.UPDATA_BT.active = false;

    if (this._am && !this._updating) {

        this._am.setEventCallback(this.updateCb.bind(this));

        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);

        }

        this._failCount = 0;

        this._am.update();

        this._updating = true;

        //console.error('hotUpdate:updateing');

        this.network_ing();

    } else {

        //console.error('hotUpdate:network_over');

        this.network_over();

    }

},

onEnable: function () {

    this.network_ing();

    this.checkUpdate();

},

// use this for initialization

onLoad: function () {

    if (!cc.sys.isNative) {

        console.error('Hot update is only available in Native build');

        return;

    }

    this.LOG.active = true;

    //this.LOG.string += '123\n';

    this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'blackjack-remote-asset');

    //console.error('Storage path for remote asset : ' + this._storagePath);

    // 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) {

    this.versionCompareHandle = (versionA, versionB) => {

        this._versionB = versionB;

        //console.error('JS Custom Version Compare: client_version_A:' + versionA + '  server_version_B:' + 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;

        }

    };

    //https://github.com/cocos-creator/cocos2d-x-lite/blob/develop/extensions/assets-manager/AssetsManagerEx.h#L149

    // Init with empty manifest url for testing custom manifest

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

    //var panel = let panel;

    // 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((path, asset) => {

        try {

            // 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;

            // console.error('setVerifyCallback path:', path);

            // console.error('setVerifyCallback asset:', asset);

            // this.LOG.string += expectedMD5 + ' ' + size + '\n';

            if (compressed) {

                console.error('Verification passed (compressed):', relativePath);

            } else {

                console.error('Verification passed:', relativePath, `(${expectedMD5})`);

            }

            return true;

        } catch (error) {

            console.error('文件验证失败:', error);

            this.PROMPT_INFORMATION.string = `文件验证失败: ${error.message}`;

            this.network_over();

            return false;

        }

    });

    //'Hot update is ready, please check or directly update.';

    this.PROMPT_INFORMATION.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.

        //当并发任务太多时,某些Android设备可能会减慢下载过程。该值可能不准确,请进行更多测试,找出最适合您的游戏。

        this._am.setMaxConcurrentTask(2);

        //'Max concurrent tasks count have been limited to 2';

        //this.PROMPT_INFORMATION.string = '最大并发任务数限制为2';

    }*/

    this._am.setMaxConcurrentTask(1);

    this.DOWNLOAD_PROGRESS.progress = 0;

    this.DOWNLOAD_INFO.string = '';

},

onDestroy: function () {

    if (this._updateListener) {

        this._am.setEventCallback(null);

        this._updateListener = null;

    }

},

/**

 * 将输入的文件路径字符串按最后一个 '/' 分割成两部分

 * @param {string} path - 输入的文件路径字符串

 * @returns {Object} - 包含 dirPath(目录路径)和 fileName(文件名)的对象

 */

splitPath: function (path) {

    let dirPath = '';

    let fileName = path;

    const lastSlashIndex = path.lastIndexOf('/');

    if(lastSlashIndex === -1) {

        // 若字符串中没有 '/',目录路径为空,文件名就是原字符串

        return [dirPath, fileName];

    }

    dirPath = path.substring(0, lastSlashIndex);// 截取目录路径

    fileName = path.substring(lastSlashIndex + 1);// 截取文件名

    return [dirPath, fileName];

},

});

查问题方向,应该就只剩下这个了.

没有这部分 这部分代码 引擎有提供没?

在模拟器里面,把下载好的文件都复制出来,跟热更新文件做个对比就好了.看看
类似操作:MuMu模拟器12如何将文件/图片从模拟器内导出到电脑?_MuMu模拟器_安卓模拟器

只要找到apk下载的文件,剩下就简单了.

1赞

我试试啊,但一般都是 下载70% 就提示失败了

一般来讲,下载失败,继续重新下载3-5次.再提示失败,会比较好的,不要一次失败就提示失败.

我感觉是下载新资源后 spine动画都无法运行,引起客户端freeze

这里有设置 spine动画的支持

从理论上看 和这个没关系应该,热更新不会和业务逻辑层的资源类型有联系,这个是物理文件层的硬性对比来决定的,把需要更新的文件范围缩小到几个 找出出问题的那个 再看问题就好说了,

问下,spine资源能独立调节缩放吗,不通过node节点调

可以的,js代码也可以,spine组件也可以

我感觉是底层代码切割不理想,所以 模块设置 全选 就解决这个问题了!