M4: 通用网页容器 + SettingsProxy + NavProvider + 子游戏切换

T-M4-01/02/03 GenericWebContainer(§11.3 第二套机制,不挂桥):
  - javaScriptProxy 注入 settings 对象 6 方法(SettingsProxy,函数回调避开 ArkTS 对象字面量限制)
  - 首次 100% runJavaScript 直调 getWebdata('<data>');返回键 isbackfinishweb→gamebackkeydown /
    isexitdialogeshow→退出确认→backgameData();关闭 pop({data}) 101 语义回上层
  - orientation "1"竖/其他横(window.setPreferredOrientation);browser 隐式 want
T-M3-06 NavProvider:OpenurlTitleData(开通用容器,onPop→callHandler getWebdata)、
  SwitchOverGameData(同容器 loadUrl 切子游戏+重注入 app_data(launchtype'1')+方向+复位首屏标志)、
  getGameinstall(同步 1/0 查 <解压根>/<dir>/index.html)、backgameData(重载大厅+待加载后 getWebdata)
导航解耦:common NavEvents(名+具名 payload interface);NavProvider 发 EventBus → BridgeGameContainer 执行
  (容器持 pathStack/controller)。EventBus payload 放宽为 Object(ArkTS 禁 Record 字面量),用 GenericEventData
domain AppDataInjector.buildValues 复用(StartupOrchestrator + 子游戏切换共用,去重)
组装根装配 NavProvider

devecocli build 通过。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
lanterngamescn
2026-06-25 20:58:10 +08:00
parent ef04f4e9e1
commit 98854f7312
12 changed files with 418 additions and 87 deletions
@@ -0,0 +1,77 @@
/**
* 导航能力(契约 §8.8/§8.9/§8.10/§11T-M3-06)。
* - OpenurlTitleData:打开通用网页容器(路径 B,§11.2),关闭回传 → 上层 getWebdata。
* - SwitchOverGameData:容器内切换子游戏(路径 A,§11.1),同容器 loadUrl。
* - getGameinstall:同步返回子游戏资源是否就绪("1"/"0")。
* - backgameData:子游戏带数据返回大厅。
*
* 容器持 pathStack/WebviewController,本 Provider 经 EventBus 发导航事件,由 BridgeGameContainer 执行。
*/
import { common } from '@kit.AbilityKit';
import { FileSystem } from 'platform';
import { ResourceManager, ConfigManager } from 'domain_resource';
import { BridgeController } from 'feature_bridge';
import { InboundHandlers, OpenUrlTitleDataReq, SwitchOverGameReq } from 'contracts';
import { EventBus, NavEvents, OpenGenericWebPayload, SwitchGamePayload, BackGamePayload, Logger } from 'common';
import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider';
export class NavProvider implements CapabilityProvider {
readonly name: string = 'nav';
private readonly log: Logger = Logger.tag('NavProvider');
private context: common.UIAbilityContext | undefined = undefined;
private config: ConfigManager | undefined = undefined;
register(bridge: BridgeController, ctx: CapabilityContext): void {
this.context = ctx.uiAbilityContext;
this.config = ctx.config;
bridge.registerHandler(InboundHandlers.OpenUrlTitleData, (data: string, _cb: (resp: string) => void) => {
this.openUrl(data);
});
bridge.registerHandler(InboundHandlers.SwitchOverGameData, (data: string, _cb: (resp: string) => void) => {
this.switchGame(data);
});
bridge.registerHandler(InboundHandlers.GetGameInstall, (data: string, cb: (resp: string) => void) => {
cb(this.isGameInstalled(data) ? '1' : '0');
});
bridge.registerHandler(InboundHandlers.BackGameData, (data: string, _cb: (resp: string) => void) => {
const payload: BackGamePayload = { data };
EventBus.emit(NavEvents.BACK_GAME, payload);
});
}
private openUrl(data: string): void {
let req: OpenUrlTitleDataReq;
try {
req = JSON.parse(data) as OpenUrlTitleDataReq;
} catch (e) {
this.log.w(`OpenurlTitleData bad json: ${(e as Error).message}`);
return;
}
const payload: OpenGenericWebPayload = { url: req.url, title: req.title, data: req.data, orientation: '' };
EventBus.emit(NavEvents.OPEN_GENERIC_WEB, payload);
}
private switchGame(data: string): void {
let req: SwitchOverGameReq;
try {
req = JSON.parse(data) as SwitchOverGameReq;
} catch (e) {
this.log.w(`SwitchOverGameData bad json: ${(e as Error).message}`);
return;
}
const payload: SwitchGamePayload = { webtype: req.webtype, dir: req.Gamedirectory, data: req.data };
EventBus.emit(NavEvents.SWITCH_GAME, payload);
}
/** 子游戏资源是否就绪:<解压根>/<dir>/index.html 存在。 */
private isGameInstalled(dir: string): boolean {
const ctx = this.context;
const cfg = this.config;
if (ctx === undefined || cfg === undefined || dir === '') {
return false;
}
const urlpath: string = `${ResourceManager.resourceRoot(ctx)}/${cfg.getLocal().gamedir}`;
return FileSystem.exists(`${urlpath}/${dir}/index.html`);
}
}