diff --git a/apps/mobile-shell/scripts/check-config.mjs b/apps/mobile-shell/scripts/check-config.mjs index 8a4cf7aa9..6c15f81d8 100644 --- a/apps/mobile-shell/scripts/check-config.mjs +++ b/apps/mobile-shell/scripts/check-config.mjs @@ -1802,6 +1802,8 @@ for (const runtimeSnippet of [ 'const platform = getMobileRuntimePlatform();', 'platform,', 'capabilities: resolveMobileHostCapabilities(platform)', + 'getMobileHostBridgeRuntimeResponse(request: HostBridgeRequest)', + 'ok(request, getMobileHostBridgeRuntime())', ]) { if (!hostBridgeRuntimeSource.includes(runtimeSnippet)) { throw new Error(`mobile shell runtime response missing ${runtimeSnippet}`); @@ -1809,7 +1811,8 @@ for (const runtimeSnippet of [ } if ( - !dispatchSource.includes('getMobileHostBridgeRuntime()') || + !dispatchSource.includes('getMobileHostBridgeRuntimeResponse(request)') || + dispatchSource.includes('ok(request, getMobileHostBridgeRuntime') || dispatchSource.includes('MOBILE_SHELL_HOST_VERSION') || dispatchSource.includes('HOST_BRIDGE_VERSION') || dispatchSource.includes('resolveMobileHostCapabilities(') || diff --git a/apps/mobile-shell/src/host-bridge/dispatch.ts b/apps/mobile-shell/src/host-bridge/dispatch.ts index 72cb7fb90..cec5a9b06 100644 --- a/apps/mobile-shell/src/host-bridge/dispatch.ts +++ b/apps/mobile-shell/src/host-bridge/dispatch.ts @@ -35,7 +35,7 @@ import { reloadMobileHostBridgeWebView, } from './navigation'; import { getMobileHostBridgeNetworkStatus } from './network'; -import { getMobileHostBridgeRuntime } from './runtime'; +import { getMobileHostBridgeRuntimeResponse } from './runtime'; let navigation: MobileHostBridgeNavigation | null = null; @@ -50,7 +50,7 @@ export async function dispatchMobileHostBridgeRequest( ) { switch (request.method) { case 'host.getRuntime': - return ok(request, getMobileHostBridgeRuntime()); + return getMobileHostBridgeRuntimeResponse(request); case 'appearance.getColorScheme': return getMobileHostBridgeAppearanceColorScheme(request); case 'app.openExternalUrl': diff --git a/apps/mobile-shell/src/host-bridge/runtime.ts b/apps/mobile-shell/src/host-bridge/runtime.ts index 699e16887..0c5a8bc62 100644 --- a/apps/mobile-shell/src/host-bridge/runtime.ts +++ b/apps/mobile-shell/src/host-bridge/runtime.ts @@ -2,10 +2,12 @@ import { Platform } from 'react-native'; import { HOST_BRIDGE_VERSION, + type HostBridgeRequest, type HostBridgeRuntimeResult, } from '../../../../packages/shared/src/contracts/hostBridge'; import { MOBILE_SHELL_HOST_VERSION } from '../shell/runtime'; import { resolveMobileHostCapabilities } from './capabilities'; +import { ok } from './protocol'; export function getMobileRuntimePlatform() { return Platform.OS === 'ios' ? 'ios' : 'android'; @@ -21,3 +23,7 @@ export function getMobileHostBridgeRuntime(): HostBridgeRuntimeResult { capabilities: resolveMobileHostCapabilities(platform), }; } + +export function getMobileHostBridgeRuntimeResponse(request: HostBridgeRequest) { + return ok(request, getMobileHostBridgeRuntime()); +} diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index c38325140..8e1f7b1d1 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -76,7 +76,7 @@ - 2026-06-18 移动壳默认入口:Expo 壳默认 H5 地址固定为 `https://app.genarrative.world/`,开发联调本机 Vite 必须显式设置 `EXPO_PUBLIC_GENARRATIVE_WEB_URL=http://127.0.0.1:3000/`、`http://localhost:3000/` 或 `http://[::1]:3000/`;生产包不得在未配置环境变量时加载设备本机 localhost,也不得通过环境变量把第三方外域 H5 放入带完整 HostBridge 的 WebView。 - 2026-06-18 移动壳安装包身份:Expo 移动壳的 iOS bundle identifier 与 Android package 统一固定为 `world.genarrative.mobile`,应用版本固定为 `0.1.0`,iOS `buildNumber` 从字符串 `"1"` 起步,Android `versionCode` 从整数 `1` 起步;后续分发安装包时递增构建号 / versionCode,产品版本号按发布节奏调整。移动壳配置检查会校验 `app.json` 与 `package.json` 版本一致,并拒绝缺失或漂移的包标识,当前不写入假商店元数据、假更新端点或占位渠道 SDK 配置。 - 2026-06-19 移动壳 HostBridge 版本运行时来源:Expo 移动壳的 H5 入口 query 和 `host.getRuntime` 回包都读取 `MOBILE_SHELL_HOST_VERSION`,该值必须从移动壳 `app.json` 的 Expo `version` 配置解析,异常配置只回退到与 `app.json` / `package.json` 一致的受检 fallback;配置检查会拒绝 `App.tsx`、`bridge.ts` 或 `runtime.ts` 重新散落硬编码版本,避免安装包版本升级时 H5 首屏上下文与 runtime 回读分叉。 -- 2026-06-19 移动壳 runtime 桥接边界:Expo `host.getRuntime` 的平台归一、hostVersion、bridgeVersion 和 capability 清单组装统一收口在 `apps/mobile-shell/src/host-bridge/runtime.ts`;`dispatch.ts` 只负责把 `host.getRuntime` 委托给 `getMobileHostBridgeRuntime()`。移动壳配置检查会拒绝分发层重新读取 `MOBILE_SHELL_HOST_VERSION`、`HOST_BRIDGE_VERSION`、`resolveMobileHostCapabilities(...)` 或 `Platform.OS`,避免入口 URL、runtime 回包和能力清单继续分叉。 +- 2026-06-19 移动壳 runtime 桥接边界:Expo `host.getRuntime` 的平台归一、hostVersion、bridgeVersion、capability 清单组装和 HostBridge 成功响应包装统一收口在 `apps/mobile-shell/src/host-bridge/runtime.ts`;`dispatch.ts` 只负责把 `host.getRuntime` 委托给 `getMobileHostBridgeRuntimeResponse(...)`。移动壳配置检查会拒绝分发层重新读取 `MOBILE_SHELL_HOST_VERSION`、`HOST_BRIDGE_VERSION`、`resolveMobileHostCapabilities(...)`、`Platform.OS` 或包装 runtime 成功响应,避免入口 URL、runtime 回包和能力清单继续分叉。 - 2026-06-19 桌面壳 runtime 桥接边界:Tauri `host.getRuntime` 的平台归一、hostVersion、bridgeVersion 和 capability 清单组装统一收口在 `apps/desktop-shell/src-tauri/src/host_bridge/runtime.rs`;`dispatch.rs` 只负责把 `host.getRuntime` 委托给 `desktop_runtime()` 并序列化返回。桌面壳配置检查会拒绝分发层重新读取 `env!("CARGO_PKG_VERSION")`、`HOST_BRIDGE_VERSION`、`capabilities()` 或 `desktop_platform()`,避免入口 URL、runtime 回包和能力清单继续分叉。 - 2026-06-18 移动壳发布通道边界:Expo 移动壳默认显式关闭 OTA 更新,只允许 `updates.enabled=false`;在真实发布通道、更新端点、签名 / 回滚策略和团队发布流程落地前,不得配置 `runtimeVersion`、release channel、EAS channel、`expo-updates` 插件或移动端 crash / analytics / CodePush 依赖。移动壳配置检查和 Expo public config smoke 会拒绝这些发布通道能力被提前打开,根 `package-lock.json` 也不得解析 `expo-updates`、Sentry、Firebase Analytics、PostHog、Amplitude、Segment、CodePush 等真实发布 / 观测 SDK。 - 2026-06-18 移动壳观测与渠道 SDK 初始化边界:移动壳生产入口、HostBridge、启动 URL 和 runtime 配置不得提前初始化 Sentry、Firebase Analytics、PostHog、Amplitude、Segment、CodePush 或 Expo Updates;这些 SDK 必须等真实发布通道、采集字段、用户授权、隐私披露、签名 / 回滚策略和团队发布流程落地后逐项接入。配置检查会同时拒绝相关依赖、锁文件解析、Expo 配置和源码初始化片段;`expo-application` 可能由 Expo 自身传递解析,但项目不得主动 direct 依赖它实现渠道逻辑。