实现子游戏按需下载,修复点子游戏白屏(§11.1 路径A)
根因:整包 gamehall.zip 顶层只含 gamehall,子游戏需按需单独下载;原 switchGame 直接 loadUrl 不存在的目录 → ArkWeb invalidFileUrl → 白屏。 对齐 Android NewwebviewActivity 的 updategamezip: - ConfigManager.resolveGame(remote, gameid):以 gamedownloadurl 为 gameid 经 agent→game→channel→market 分层解析子游戏 game_zip/game_version(复用 VersionResolver)。 - ResourceManager.updateSubgame:下载→暂存解压→校验 <dir>/index.html→原子换入 urlpath/<dir>。 另加 subgameInstalled/subgameLocalVersion/subgameLocalGameId。 - BridgeGameContainer.switchGame 改 async + prepareSubgame:目录缺失先下载、已装比对远程 版本更高才更新;下载期复用启动页同款金色进度条;远程配置 10 分钟缓存(对齐 gameconfigtime)。 - SwitchGamePayload 增 gameId(gamedownloadurl)。 真机验证:点三个老K → 下载 sangelaok.zip(9.4M) → 解压加载,子游戏正常渲染 (V1.155 与配置 game_version=155 一致);日志不再 invalidFileUrl。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e75f567948
commit
de5b950d9b
@@ -88,6 +88,21 @@ export class ConfigManager {
|
||||
return VersionResolver.resolve(remote, this.matchKeys(fallbackGameId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 子游戏版本决策:以**指定 gameid**(SwitchOverGameData 的 gamedownloadurl / 子游戏 version.xml 的 gameid)
|
||||
* 经 agent→game→channel→market 分层解析 game_zip/game_version(agent/channel/market 取本地)。
|
||||
* 复刻 Android downloadgame2/downloadgame3 的层级遍历。
|
||||
*/
|
||||
resolveGame(remote: RemoteConfig, gameid: string): VersionDecision {
|
||||
const keys: MatchKeys = {
|
||||
agentid: this.local.agent,
|
||||
channelid: this.local.channel,
|
||||
marketid: this.local.market,
|
||||
gameid,
|
||||
};
|
||||
return VersionResolver.resolve(remote, keys);
|
||||
}
|
||||
|
||||
/** 便捷:拉取 + 解析一步到位(gameid 回退值由调用方提供)。 */
|
||||
async resolve(fallbackGameId: string = ''): Promise<VersionDecision> {
|
||||
const remote: RemoteConfig = await this.fetchRemote();
|
||||
|
||||
@@ -102,6 +102,63 @@ export class ResourceManager {
|
||||
return this.readVersionXml().gameId;
|
||||
}
|
||||
|
||||
// ── 子游戏(§11.1 路径 A 按需下载)─────────────────────────────────────────
|
||||
|
||||
/** 子游戏入口路径 `<urlpath>/<dir>/index.html`。 */
|
||||
subgameIndexPath(dir: string): string {
|
||||
return `${this.cachedPaths.urlpath}/${dir}/index.html`;
|
||||
}
|
||||
|
||||
/** 子游戏资源是否就绪(index.html 存在)。 */
|
||||
subgameInstalled(dir: string): boolean {
|
||||
return FileSystem.exists(this.subgameIndexPath(dir));
|
||||
}
|
||||
|
||||
/** 子游戏本地 version.xml 信息(缺失 → 空信息)。 */
|
||||
private subgameVersionXml(dir: string): VersionXmlInfo {
|
||||
const p: string = `${this.cachedPaths.urlpath}/${dir}/version.xml`;
|
||||
return FileSystem.exists(p) ? VersionXml.parse(FileSystem.readText(p)) : { version: 0, gameName: '', gameId: '' };
|
||||
}
|
||||
|
||||
/** 子游戏本地版本号(缺失 0)。 */
|
||||
subgameLocalVersion(dir: string): number {
|
||||
return this.subgameVersionXml(dir).version;
|
||||
}
|
||||
|
||||
/** 子游戏本地 version.xml 的 game id(查更新时优先用它解析远程版本;缺失 '')。 */
|
||||
subgameLocalGameId(dir: string): string {
|
||||
return this.subgameVersionXml(dir).gameId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载并安装子游戏 zip 到 `urlpath`(复刻 Android runzip:删旧目录 → 解压到 urlpath)。
|
||||
* zip 顶层即 `<dir>/`,解压后得 `urlpath/<dir>/...`。**原子化**:下载→解压暂存→校验
|
||||
* `<dir>/index.html`→删旧换入,任一步失败旧资源保持不动。
|
||||
*/
|
||||
async updateSubgame(dir: string, downloadUrl: string, onProgress?: ProgressCallback): Promise<void> {
|
||||
const url: string = downloadUrl.includes('?') ? downloadUrl : `${downloadUrl}?a=${Date.now()}`;
|
||||
const zipPath: string = `${this.cachedPaths.upurlpath}/dowlod_zip/${Date.now()}_${dir}.zip`;
|
||||
const staging: string = `${this.cachedPaths.urlpath}/.staging_${dir}_${Date.now()}`;
|
||||
const target: string = `${this.cachedPaths.urlpath}/${dir}`;
|
||||
try {
|
||||
await Downloader.download(url, zipPath, onProgress);
|
||||
FileSystem.rmrf(staging);
|
||||
FileSystem.ensureDir(staging);
|
||||
await Unzipper.unzip(zipPath, staging);
|
||||
const staged: string = `${staging}/${dir}`;
|
||||
if (!FileSystem.exists(`${staged}/index.html`)) {
|
||||
throw new Error(`subgame package missing ${dir}/index.html`);
|
||||
}
|
||||
FileSystem.rmrf(target);
|
||||
FileSystem.ensureDir(this.cachedPaths.urlpath);
|
||||
FileSystem.rename(staged, target);
|
||||
ResourceManager.log.i(`subgame ${dir} updated from ${url}`);
|
||||
} finally {
|
||||
FileSystem.rmrf(zipPath);
|
||||
FileSystem.rmrf(staging);
|
||||
}
|
||||
}
|
||||
|
||||
/** 持久化路径到 KvStore(供容器/重启读取)。 */
|
||||
async persistPaths(): Promise<void> {
|
||||
this.kv.putString(KEY_URLPATH, this.cachedPaths.urlpath);
|
||||
|
||||
Reference in New Issue
Block a user