From 7fb0c194f713b4177ec4e90e5d818eeaba024180 Mon Sep 17 00:00:00 2001 From: lanterngamescn Date: Thu, 25 Jun 2026 07:44:57 +0800 Subject: [PATCH] =?UTF-8?q?M0:=20App=20=E5=85=A5=E5=8F=A3=E4=B8=8E?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E5=A3=B3=EF=BC=88T-M0-07=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 框架 §4 路由骨架,Navigation + NavPathStack: - AppRoutes:路由名(Splash/BridgeGame/GenericWeb)、容器参数类型、前后台事件名 - Index:@Entry 导航宿主,初始进 Splash,navDestination 按名分发 - SplashPage:启动引导壳(weclomeactivity1),replacePathByName 进大厅 - BridgeGameContainer:大厅容器壳(webviewActivity),pushPathByName+onPop 演示 打开通用网页并接收 101 回传 - GenericWebContainer:通用网页容器壳(openwebActivity1),pop(result) 模拟 backgameData 带数据返回(§11.2 结果码 101 语义) - EntryAbility:onForeground/onBackground 经 EventBus 广播应用前后台事件 (M3 容器订阅后 callHandler('appservice','1'/'2')) - build 编译通过 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../main/ets/entryability/EntryAbility.ets | 8 +++- .../main/ets/pages/BridgeGameContainer.ets | 43 +++++++++++++++++ .../main/ets/pages/GenericWebContainer.ets | 37 +++++++++++++++ entry/src/main/ets/pages/Index.ets | 47 ++++++++++++------- entry/src/main/ets/pages/SplashPage.ets | 34 ++++++++++++++ entry/src/main/ets/routes/AppRoutes.ets | 40 ++++++++++++++++ 6 files changed, 191 insertions(+), 18 deletions(-) create mode 100644 entry/src/main/ets/pages/BridgeGameContainer.ets create mode 100644 entry/src/main/ets/pages/GenericWebContainer.ets create mode 100644 entry/src/main/ets/pages/SplashPage.ets create mode 100644 entry/src/main/ets/routes/AppRoutes.ets diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index 091797f..95070a5 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -1,6 +1,8 @@ import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { window } from '@kit.ArkUI'; +import { EventBus } from 'common'; +import { AppEvents } from '../routes/AppRoutes'; const DOMAIN = 0x0000; @@ -37,12 +39,14 @@ export default class EntryAbility extends UIAbility { } onForeground(): void { - // Ability has brought to foreground + // 前台:广播应用前台事件,M3 容器订阅后 callHandler('appservice','1')(§9) hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + EventBus.emit(AppEvents.FOREGROUND); } onBackground(): void { - // Ability has back to background + // 后台:广播应用后台事件,M3 容器订阅后 callHandler('appservice','2')(§9) hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + EventBus.emit(AppEvents.BACKGROUND); } } \ No newline at end of file diff --git a/entry/src/main/ets/pages/BridgeGameContainer.ets b/entry/src/main/ets/pages/BridgeGameContainer.ets new file mode 100644 index 0000000..9478192 --- /dev/null +++ b/entry/src/main/ets/pages/BridgeGameContainer.ets @@ -0,0 +1,43 @@ +import { RouteName, BridgeGameParams, GenericWebParams, GenericWebResult } from '../routes/AppRoutes'; + +/** + * 大厅/子游戏容器壳(对应 webviewActivity,框架 §7.1)。 + * M0:仅路由壳,演示打开通用网页容器并接收 101 回传。 + * M2:填入 Web 组件 + BridgeController(桥协议 + §8/§9 handler)。 + */ +@Component +export struct BridgeGameContainer { + pathStack: NavPathStack = new NavPathStack(); + params: BridgeGameParams = { entryUrl: '', launchType: '0' }; + @State private lastWebResult: string = '(无)'; + + /** 打开通用网页容器(§11.2 路径 B),onPop 接收子页回传(结果码 101 语义)。 */ + private openGenericWeb(): void { + const params: GenericWebParams = { url: '', title: '活动页', data: 'hello', orientation: '0' }; + this.pathStack.pushPathByName(RouteName.GENERIC_WEB, params, (popInfo: PopInfo) => { + const result = popInfo.result as GenericWebResult; + this.lastWebResult = result !== undefined ? result.data : '(空)'; + }, false); + } + + build() { + NavDestination() { + Column({ space: 16 }) { + Text('BridgeGameContainer 壳') + .fontSize(20) + .fontWeight(FontWeight.Bold) + Text(`launchType=${this.params.launchType}`) + .fontSize(14) + .fontColor(Color.Gray) + Text(`通用网页回传:${this.lastWebResult}`) + .fontSize(14) + Button('打开通用网页(测回传)') + .onClick(() => this.openGenericWeb()) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + } + .hideTitleBar(true) + } +} diff --git a/entry/src/main/ets/pages/GenericWebContainer.ets b/entry/src/main/ets/pages/GenericWebContainer.ets new file mode 100644 index 0000000..44087a8 --- /dev/null +++ b/entry/src/main/ets/pages/GenericWebContainer.ets @@ -0,0 +1,37 @@ +import { GenericWebParams, GenericWebResult } from '../routes/AppRoutes'; + +/** + * 通用网页容器壳(对应 openwebActivity1,框架 §7.2)。 + * M0:仅路由壳,演示 backgameData(data) → pop 回传上层(结果码 101 语义)。 + * M4:填入 Web 组件 + SettingsProxy(settings 6 方法 + getWebdata/gamebackkeydown/backgameData 直调)。 + */ +@Component +export struct GenericWebContainer { + pathStack: NavPathStack = new NavPathStack(); + params: GenericWebParams = { url: '', title: '', data: '', orientation: '0' }; + + /** 模拟 settings.backgameData(data):带数据返回上层(§11.3)。 */ + private backWithData(): void { + const result: GenericWebResult = { data: `from-web:${this.params.data}` }; + this.pathStack.pop(result, false); + } + + build() { + NavDestination() { + Column({ space: 16 }) { + Text('GenericWebContainer 壳') + .fontSize(20) + .fontWeight(FontWeight.Bold) + Text(`title=${this.params.title} data=${this.params.data}`) + .fontSize(14) + .fontColor(Color.Gray) + Button('backgameData 返回(带数据)') + .onClick(() => this.backWithData()) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + } + .hideTitleBar(true) + } +} diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 8e2d24a..d9a4e06 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -1,23 +1,38 @@ +import { RouteName, BridgeGameParams, GenericWebParams } from '../routes/AppRoutes'; +import { SplashPage } from './SplashPage'; +import { BridgeGameContainer } from './BridgeGameContainer'; +import { GenericWebContainer } from './GenericWebContainer'; + +/** + * 应用导航宿主(@Entry)。持有全局 NavPathStack,初始进入 Splash。 + * 各容器作为 NavDestination 子页,经 navDestination builder 按路由名分发。 + */ @Entry @Component struct Index { - @State message: string = 'Hello World'; + private pathStack: NavPathStack = new NavPathStack(); + + aboutToAppear(): void { + // 启动即进入引导页(对应 weclomeactivity1 为 Launcher) + this.pathStack.pushPathByName(RouteName.SPLASH, '', false); + } + + @Builder + pageMap(name: string, param: object) { + if (name === RouteName.SPLASH) { + SplashPage({ pathStack: this.pathStack }) + } else if (name === RouteName.BRIDGE_GAME) { + BridgeGameContainer({ pathStack: this.pathStack, params: param as BridgeGameParams }) + } else if (name === RouteName.GENERIC_WEB) { + GenericWebContainer({ pathStack: this.pathStack, params: param as GenericWebParams }) + } + } build() { - RelativeContainer() { - Text(this.message) - .id('HelloWorld') - .fontSize($r('app.float.page_text_font_size')) - .fontWeight(FontWeight.Bold) - .alignRules({ - center: { anchor: '__container__', align: VerticalAlign.Center }, - middle: { anchor: '__container__', align: HorizontalAlign.Center } - }) - .onClick(() => { - this.message = 'Welcome'; - }) + Navigation(this.pathStack) { } - .height('100%') - .width('100%') + .navDestination(this.pageMap) + .hideNavBar(true) + .mode(NavigationMode.Stack) } -} \ No newline at end of file +} diff --git a/entry/src/main/ets/pages/SplashPage.ets b/entry/src/main/ets/pages/SplashPage.ets new file mode 100644 index 0000000..ac36808 --- /dev/null +++ b/entry/src/main/ets/pages/SplashPage.ets @@ -0,0 +1,34 @@ +import { RouteName, BridgeGameParams } from '../routes/AppRoutes'; + +/** + * 启动引导页壳(对应 weclomeactivity1)。 + * M0:仅路由壳,点击进入大厅容器。M2:接入 StartupOrchestrator(配置/资源/app_data 注入)后再跳。 + */ +@Component +export struct SplashPage { + pathStack: NavPathStack = new NavPathStack(); + + private enterHall(): void { + const params: BridgeGameParams = { entryUrl: '', launchType: '0' }; + this.pathStack.replacePathByName(RouteName.BRIDGE_GAME, params, false); + } + + build() { + NavDestination() { + Column({ space: 16 }) { + Text('TSGame 启动引导') + .fontSize(22) + .fontWeight(FontWeight.Bold) + Text('M0 脚手架 · 路由壳') + .fontSize(14) + .fontColor(Color.Gray) + Button('进入大厅') + .onClick(() => this.enterHall()) + } + .width('100%') + .height('100%') + .justifyContent(FlexAlign.Center) + } + .hideTitleBar(true) + } +} diff --git a/entry/src/main/ets/routes/AppRoutes.ets b/entry/src/main/ets/routes/AppRoutes.ets new file mode 100644 index 0000000..a258b5c --- /dev/null +++ b/entry/src/main/ets/routes/AppRoutes.ets @@ -0,0 +1,40 @@ +/** + * 应用路由与事件常量(框架 §4 路由骨架)。 + * + * 三个目的地对应设计文档容器:Splash(启动引导,weclomeactivity1) / + * BridgeGame(大厅+子游戏,webviewActivity) / GenericWeb(通用网页,openwebActivity1)。 + * 容器间回传用 NavPathStack 的 onPop 回调实现(映射 §11.2 结果码 101 语义)。 + */ +export class RouteName { + static readonly SPLASH: string = 'Splash'; + static readonly BRIDGE_GAME: string = 'BridgeGame'; + static readonly GENERIC_WEB: string = 'GenericWeb'; +} + +/** 大厅/子游戏容器参数。 */ +export interface BridgeGameParams { + /** 入口 URL(file://.../gamehall/index.html?Launchtype=0 或 http://...) */ + entryUrl: string; + /** 启动类型:"0"大厅/"1"子游戏 */ + launchType: string; +} + +/** 通用网页容器参数(§11.2 OpenurlTitleData 透传)。 */ +export interface GenericWebParams { + url: string; + title: string; + data: string; + /** "1" 竖屏 / 其他 横屏 */ + orientation: string; +} + +/** 通用网页容器回传结果(§11.2 结果码 101 语义)。 */ +export interface GenericWebResult { + data: string; +} + +/** 应用级事件名(前后台,经 EventBus;M3 容器订阅后 callHandler('appservice',...))。 */ +export class AppEvents { + static readonly FOREGROUND: string = 'app.foreground'; + static readonly BACKGROUND: string = 'app.background'; +}