热更的新版本使用的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下载的文件,剩下就简单了.
我试试啊,但一般都是 下载70% 就提示失败了
一般来讲,下载失败,继续重新下载3-5次.再提示失败,会比较好的,不要一次失败就提示失败.
从理论上看 和这个没关系应该,热更新不会和业务逻辑层的资源类型有联系,这个是物理文件层的硬性对比来决定的,把需要更新的文件范围缩小到几个 找出出问题的那个 再看问题就好说了,
问下,spine资源能独立调节缩放吗,不通过node节点调
可以的,js代码也可以,spine组件也可以
我感觉是底层代码切割不理想,所以 模块设置 全选 就解决这个问题了!

