-
Creator 版本:2.4.9
-
目标平台: iOS / Android
-
重现方式:热更一个版本后用更高版本覆盖安装,安卓更新不到最新版本,ios报错黑屏
-
首个报错:
-
之前哪个版本是正常的:
-
手机型号:
-
手机浏览器:
-
编辑器操作系统:
-
重现概率:
1,app的热更不支持md5cache,这个见帖子https://forum.cocos.org/t/assetbundle-md5cache/98000/9
2,按上面步骤修改后,可以热更代码,但有一个致命问题,加入从1.0.0热更到2.0.0,一切正常,但如果此时商店更新到3.0.0,直接下载覆盖安装,安卓无法更新,ios直接黑屏报错
3,ios报错信息如下:
[ devtools://devtools/bundled/js_app.html?v8only=true&ws=0.0.0.0:6086/00010002-0003-4004-8005-000600070008 ] in chrome browser to debug! For help see https://nodejs.org/en/docs/inspector JS: Enable batch GL commands optimization! JS: [WARN]: hotUpdateSearchPaths ["/var/mobile/Containers/Data/Application/DDA77D5E-9EE7-4037-96B2-5290D5D4F28E/Documents/remotePath/",""] ScriptEngine::onGetStringFromFile src/settings.2b1ec.js not found, possible missing file. ScriptEngine::runScript script src/settings.2b1ec.js, buffer is empty! [ERROR] Failed to invoke require, location: /Users/hcm-b0205/Downloads/jsb-default/frameworks/cocos2d-x/cocos/scripting/js-bindings/manual/jsb_global.cpp:300 ScriptEngine::onGetStringFromFile ./jsb-videoplayer.js not found, possible missing file. ScriptEngine::runScript script ./jsb-videoplayer.js, buffer is empty! [ERROR] Failed to invoke require, location: /Users/hcm-b0205/Downloads/jsb-default/frameworks/cocos2d-x/cocos/scripting/js-bindings/manual/jsb_global.cpp:300 ScriptEngine::evalString catch exception: ERROR: Uncaught TypeError: Cannot read property ‘debug’ of undefined, location: main.js:0:0 STACK: [0]window.boot@main.js:124 [1]anonymous@main.js:178 Uncaught Exception: - location : (see stack) - msg : Uncaught TypeError: Cannot read property ‘debug’ of undefined - detail : [0]window.boot@main.js:124 [1]anonymous@main.js:178 JS: [ERROR]: (see stack) Uncaught TypeError: Cannot read property ‘debug’ of undefined [0]window.boot@main.js:124 [1]anonymous@main.js:178 ScriptEngine::evalString script main.js, failed! 2022-07-30 15:56:34.940702+0800 肥鹅健身房[35523:1794214] [TraitCollection] Class CKBrowserSwitcherViewController overrides the -traitCollection getter, which is not supported. If you’re trying to override traits, you must use the appropriate API.
4,这个问题必现,而且很严重,所以劳烦官方看看,多谢
问题已经复现,我们查一下;
安卓没法更新的提示是什么? 是 “Failed to load local manifest” 吗?
安卓的没具体看报错,但应该也是找不到setting文件,我在想实在不行,就打包时候不勾选md5cache,这样包内资源能正常热更,剩下的远程动态资源自己后处理全部文件修改成md5模式,包括配置文件也修改,粗略看了下,这块生成规则情况比较多,不知道有没有什么成熟的方案或者代码参考
多谢,getengineversion是自己实现的吗,问题是当前安装包的版本号很难获取到吧
这个随便百度一下就能获取到了
多谢,不过最后我用了另一种后处理的方式解决了该问题
1,打包依然不选择md5cache,这样支持包内资源的热更,也符合cc的设计规则
2,剩下的就是包外动态资源md5的处理,也就是说需要对这个远程ab生成对应的md5
3,参考了生成规则,在打包完成做后处理,目前能正常生成md5的文件及配置
4,代码
build-finished后调用versionMd5.build(buildRoot + “/remote”,version);
version-md5.js
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');
const decodeUuid = require('../utils/decode-uuid');
var assetsRoot = "";
function md5Version(bundleRoot,version) {
let confUrl = bundleRoot + "/config.json";
if (!fs.existsSync(confUrl)) {
return;
}
Editor.log('md5 remote bundle:', bundleRoot);
let data = fs.readFileSync(confUrl, { encoding: "utf8" });
let conf = JSON.parse(data);
let versionData = { import: [], native: [] };
conf.versions = versionData;
versionDir(bundleRoot + "/import", conf, true);
versionDir(bundleRoot + "/native", conf, false);
let newpath=bundleRoot + "/config."+version+".json"
fs.writeFileSync(confUrl, JSON.stringify(conf));
fs.renameSync(confUrl,newpath);
Editor.log('md5 remote suc:' + bundleRoot);
}
function versionDir(dir, bundleConf, isImport) {
var stat = fs.statSync(dir);
if (!stat.isDirectory()) {
return;
}
var subpaths = fs.readdirSync(dir), subpath, md5, filename, uuid;
for (var i = 0; i < subpaths.length; ++i) {
if (subpaths[i][0] === '.') {
continue;
}
subpath = path.join(dir, subpaths[i]);
if (subpath.endsWith(".pvr")) {
continue;
}
stat = fs.statSync(subpath);
if (stat.isDirectory()) {
versionDir(subpath, bundleConf, isImport);
} else if (stat.isFile()) {
filename = subpaths[i];
filename = filename.split(".")[0];
uuid = filename;
md5 =getFileHash(subpath,uuid);
md5 = md5.substring(0, 5);
let index = getPathIndex(uuid, bundleConf);
index = index == -1 ? uuid : index;
let path = subpath.replace(filename, filename + "." + md5);
fs.renameSync(subpath, path);
if (isImport) {
bundleConf.versions.import.push(index, md5);
} else {
bundleConf.versions.native.push(index, md5);
//同时拷贝pvr
let pvrpath = subpath.replace(".png", ".pvr");
if (fs.existsSync(pvrpath)) {
fs.renameSync(pvrpath, path.replace(".png", ".pvr"));
}
}
}
}
}
function getFileHash(path,uuid){
//找出同一uuid的所有文件
let parent = path.slice(0, path.lastIndexOf('/'));
var subpaths = fs.readdirSync(parent);
let paths=[];
for (var i = 0; i < subpaths.length; ++i) {
let id = subpaths[i].split(".")[0];
if(id==uuid){
paths.push(parent+"/"+subpaths[i]);
}
}
//计算hash
let cryptoHash=crypto.createHash('md5');
for (let i = 0; i < paths.length; i++) {
cryptoHash.update(fs.readFileSync(paths[i]));
}
let hash=cryptoHash.digest('hex');
hash=hash.slice(0,5);
return hash;
}
function getPathIndex(uuid, bundleConf) {
for (let i = 0; i < bundleConf.uuids.length; i++) {
let rid = decodeUuid(bundleConf.uuids[i]);
if (rid == uuid) {
return i;
}
}
return -1;
}
module.exports = {
build: function (src,version) {
Editor.log('md5 remote start');
assetsRoot = src;
var subpaths = fs.readdirSync(assetsRoot);
for (var i = 0; i < subpaths.length; ++i) {
let bundleRoot = path.join(assetsRoot, subpaths[i]);
stat = fs.statSync(bundleRoot);
if (stat.isDirectory()) {
md5Version(bundleRoot,version);
}
}
Editor.log('md5 remote complete');
}
}
decode-uuid.js
var BASE64_KEYS = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=’;
var BASE64_VALUES = new Array(123); // max char code in base64Keys
for (let i = 0; i < 123; ++i) BASE64_VALUES[i] = 64; // fill with placeholder(’=’) index
for (let i = 0; i < 64; ++i) BASE64_VALUES[BASE64_KEYS.charCodeAt(i)] = i;
var HexChars = '0123456789abcdef'.split('');
var _t = ['', '', '', ''];
var UuidTemplate = _t.concat(_t, '-', _t, '-', _t, '-', _t, '-', _t, _t, _t);
var Indices = UuidTemplate.map(function (x, i) { return x === '-' ? NaN : i; }).filter(isFinite);
// fcmR3XADNLgJ1ByKhqcC5Z -> fc991dd7-0033-4b80-9d41-c8a86a702e59
module.exports = function (base64) {
if (base64.length !== 22) {
return base64;
}
UuidTemplate[0] = base64[0];
UuidTemplate[1] = base64[1];
for (var i = 2, j = 2; i < 22; i += 2) {
var lhs = BASE64_VALUES[base64.charCodeAt(i)];
var rhs = BASE64_VALUES[base64.charCodeAt(i + 1)];
UuidTemplate[Indices[j++]] = HexChars[lhs >> 2];
UuidTemplate[Indices[j++]] = HexChars[((lhs & 3) << 2) | rhs >> 4];
UuidTemplate[Indices[j++]] = HexChars[rhs & 0xF];
}
return UuidTemplate.join('');
};


