新增 Expo 与 Tauri 原生宿主壳

新增 HostBridge 原生宿主契约和 H5 native_app transport

新增 Expo React Native 移动壳并收紧 WebView 外链边界

新增 Tauri 桌面壳并用 capability 收口受控命令

更新宿主壳方案、文档索引和共享记忆
This commit is contained in:
2026-06-17 21:39:34 +08:00
parent f92e791464
commit 9b7da18879
35 changed files with 16229 additions and 308 deletions

View File

@@ -23,6 +23,9 @@
微信小程序壳、未来原生 App 壳、固定内置玩法与 AI H5 沙箱之间的宿主能力边界见 [【前端架构】宿主壳能力统一协议-2026-06-17.md](./【前端架构】宿主壳能力统一协议-2026-06-17.md)。
移动端壳采用 Expo + React Native、桌面端壳采用 Tauri并统一作为 HostBridge adapter 的分阶段方案见 [【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md](./【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md)。
当前首轮工程入口:`npm run mobile-shell:dev``npm run mobile-shell:test``npm run desktop-shell:dev``npm run desktop-shell:test`
本地通过 SSH alias 管理多台服务器、查看硬件 / systemd / HTTP 健康状态并执行受控服务启停的 egui 桌面工具见 [【开发运维】本地SSH服务器管理面板技术方案-2026-06-11.md](./technical/【开发运维】本地SSH服务器管理面板技术方案-2026-06-11.md)。
生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。

View File

@@ -16,6 +16,15 @@
---
## 2026-06-17 原生移动与桌面壳统一作为 HostBridge Adapter
- 背景:后续需要移动端 App 和桌面端 App但现有主站、固定玩法 runtime、小程序壳和未来 AI H5 sandbox 已经以 H5 为主线;如果移动端重写 React Native UI、桌面端重写 Rust/Tauri UI会形成玩法、登录、支付、分享和运行态的多套实现。
- 决策:移动端原生壳采用 `Expo + React Native`,桌面端壳采用 `Tauri`。两者都只作为 `native_app` 宿主壳和 HostBridge adapter不重写现有 React H5 主站,不把固定内置玩法迁到 React Native / Rust UI也不让 AI 生成 H5 游戏直接访问完整 HostBridge。Expo 壳通过 `react-native-webview` 承接 H5 与 native 通信Tauri 壳通过受控 command 和 capabilities 承接桌面能力;新增能力必须先进入 HostBridge 契约和测试。
- 2026-06-17 首轮落地:新增 `packages/shared/src/contracts/hostBridge.ts``src/services/host-bridge/nativeAppHostBridge.ts``apps/mobile-shell/``apps/desktop-shell/`。首轮壳只声明并实现真实可用能力;登录、支付、桌面剪贴板等未接入真实 SDK / 插件前必须返回 unsupported 并让 H5 fallback生产代码禁止 mock 成功。
- 影响范围:`src/services/host-bridge/`、未来 `apps/mobile-shell/`、未来 `apps/desktop-shell/`、移动端支付 / 分享 / 深链 / 推送、桌面端系统能力、AI H5 sandbox 的 GameBridge 边界。
- 验证方式普通浏览器、小程序、Expo 壳、Tauri 壳都能返回正确 `getHostRuntime()`;未支持能力能回退 H5固定玩法在各宿主中读取同一作品数据和运行态 snapshotAI sandbox 无法直接调用 HostBridgeTauri release 不允许任意远端页面调用桌面命令。
- 关联文档:`docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md``docs/【前端架构】宿主壳能力统一协议-2026-06-17.md`
## 2026-06-17 H5 宿主壳能力统一走 HostBridge
- 背景:主站同时运行在普通浏览器、微信小程序 `web-view` 和未来可能出现的原生 App WebView 中;登录、支付、分享、订阅授权和运行态分享目标同步曾散落在业务组件与服务文件里,后续新增宿主壳会导致同一业务重复分叉。

View File

@@ -12,6 +12,7 @@
| 后端、DDD、API、SpacetimeDB schema 和表目录 | `docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md` |
| 创作入口、草稿架和玩法链路 | `docs/【玩法创作】平台入口与玩法链路-2026-05-15.md` |
| 创作流程统一阶段计划 | `docs/planning/【玩法创作】创作流程统一总计划-2026-05-30.md` |
| 宿主壳、移动 App、桌面 App 与 AI H5 沙箱边界 | `docs/【前端架构】宿主壳能力统一协议-2026-06-17.md``docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md` |
| 本地启动、验证、部署、埋点和运营查询 | `docs/【开发运维】本地开发验证与生产运维-2026-05-15.md` |
| 微信小程序虚拟支付 | `docs/【技术方案】微信虚拟支付接入-2026-05-26.md` |
| UI 像素资产与 9-slice 规范 | `UI_CODING_STANDARD.md` |

View File

@@ -0,0 +1,290 @@
# Expo React Native 与 Tauri 宿主壳方案
更新时间:`2026-06-17`
## 结论
移动端壳采用 `Expo + React Native`,桌面端壳采用 `Tauri`。两者都只作为 Genarrative H5 主站的宿主壳,不重写现有 React 主站,不把固定玩法 runtime 迁到 React Native 或 Rust UI也不让 AI 生成 H5 游戏直接拿完整宿主能力。
固定内置玩法继续跑在现有 H5 runtime 内;移动端和桌面端通过 `HostBridge` 提供登录、支付、分享、原生页跳转、系统能力和宿主事件。AI 生成 H5 游戏继续放进独立 sandbox只能通过受限 `GameBridge` 请求允许的能力。
## 目标
1. 主站 H5 仍是唯一的产品体验主线,网页、小程序、移动 App 和桌面 App 共享同一套业务页面、玩法 runtime 和后端契约。
2. 移动端用 Expo / React Native 承接 App 外壳、WebView、深链、推送、分享、支付 SDK、系统权限和少量原生页面。
3. 桌面端用 Tauri 承接安装包、系统菜单、窗口、文件/剪贴板/外部浏览器等桌面能力,并用 Tauri capabilities 收窄前端可调用的命令。
4. H5 业务层只面向 `HostBridge` 能力,不直接判断 Expo、React Native、Tauri、iOS、Android 或桌面平台。
5. 壳层能力按能力白名单逐项开放,不提供“任意 native command”或“任意系统 API”透传。
## 非目标
- 不把现有 React H5 主站整体迁到 React Native。
- 不用 Tauri 重写桌面 UI也不引入第二套桌面业务前端。
- 不让固定玩法通过远程代码包下载流程启动。
- 不让 AI 生成 H5 游戏直接访问登录、支付、token、完整用户资料、系统文件或宿主私有 API。
- 不在第一阶段解决 App Store / 应用商店全部上架材料,只先固定工程边界和验证路线。
## 总体架构
```text
现有 React H5 主站
-> HostBridge
-> browser adapter
-> wechat mini program adapter
-> native app adapter
-> Expo React Native shell
-> Tauri shell
AI 生成 H5 游戏 iframe
-> GameBridge
-> H5 parent runtime
-> HostBridge 能力子集或后端 API
```
核心原则:`HostBridge` 是 H5 与宿主壳之间唯一的通用协议;`GameBridge` 是 AI 游戏 sandbox 与父页面之间的受限协议。两个协议不能合并。
## 工程布局建议
```text
apps/
mobile-shell/ # Expo + React Native App 壳
desktop-shell/ # Tauri 桌面 App 壳
packages/
shared/
src/contracts/
hostBridge.ts # HostBridge 消息契约,供 H5 / RN / Tauri 对齐
src/
services/host-bridge/
hostBridge.ts
nativeAppHostBridge.ts
```
已落地:`packages/shared/src/contracts/hostBridge.ts` 保存消息 envelope、method、payload 和错误码H5、Expo 壳与 Tauri 壳共享同一份协议类型。
## HostBridge 消息协议
H5 进入原生 App 壳时由壳层附加稳定 query
```text
?clientRuntime=native_app
&clientType=native_app
&hostShell=expo_mobile|tauri_desktop
&hostPlatform=ios|android|macos|windows|linux
&hostVersion=0.1.0
&bridgeVersion=1
```
消息 envelope 统一为 JSON
```ts
type HostBridgeRequest = {
bridge: 'GenarrativeHostBridge';
version: 1;
id: string;
method: HostBridgeMethod;
payload?: unknown;
timeoutMs?: number;
};
type HostBridgeResponse = {
bridge: 'GenarrativeHostBridge';
version: 1;
id: string;
ok: boolean;
result?: unknown;
error?: {
code: string;
message: string;
};
};
type HostBridgeEvent = {
bridge: 'GenarrativeHostBridge';
version: 1;
event: string;
payload?: unknown;
};
```
首批 method
| method | 用途 | Expo 壳 | Tauri 壳 |
| --- | --- | --- | --- |
| `host.getRuntime` | 返回宿主、平台、版本和能力清单 | 支持 | 支持 |
| `auth.requestLogin` | 打开宿主登录或账号绑定流程 | 支持 | 可先返回不支持 |
| `payment.request` | 发起宿主支付 | 依平台策略接入 | 桌面二维码 / 外部浏览器 |
| `share.setTarget` | 同步当前作品分享目标 | 支持 | 未接入前不声明 |
| `share.open` | 打开系统分享面板 | 支持 | 可先复制链接 / 打开系统分享 |
| `navigation.openNativePage` | 打开受控原生页面 | 支持 | 支持设置 / 关于等 |
| `app.openExternalUrl` | 用系统浏览器打开外链 | 支持 | 支持 |
| `clipboard.writeText` | 写剪贴板 | 可选 | 可选 |
| `haptics.impact` | 轻量触感反馈 | 可选 | 不支持 |
每个 method 都必须有明确 payload schema、超时、错误码和能力开关H5 看到不支持时回退到现有浏览器路径。
## Expo React Native 壳
Expo 壳只负责 App 外壳和原生能力,不承接玩法业务。
推荐能力:
-`react-native-webview` 加载 Genarrative H5。
- H5 到 RN`window.ReactNativeWebView.postMessage(JSON.stringify(request))`
- RN 到 H5通过 WebView ref 注入脚本,向 H5 派发统一 bridge response / event。
- 使用 development build不依赖 Expo Go 作为真实集成环境;需要自定义原生配置时用 config plugin / prebuild 管理。
- App 壳维护启动页、深链、系统分享、推送、权限、App 版本、崩溃日志和支付 SDK。
- 登录首期优先复用 H5 账号体系;后续再逐项接入 Apple / Android / 微信等原生登录能力。
- 支付必须按上架渠道拆分iOS / Android 虚拟内容优先评估 IAP / Google Play Billing 或国内渠道要求H5 支付、小程序虚拟支付和桌面二维码支付不能直接照搬到 App Store 包。
移动端推荐首屏流程:
```text
Expo App 启动
-> 读取环境和远端 H5 URL
-> WebView 加载 /?clientRuntime=native_app&hostShell=expo_mobile...
-> H5 getHostRuntime() 识别 native_app
-> H5 通过 HostBridge 请求宿主能力
-> RN 壳按 allowlist 执行并回包
```
第一版移动端不建议做大量 RN 原生 Tab / 页面。当前 H5 已有移动端一级 Tab重复实现会带来导航状态、登录态、返回栈和 UI 双维护成本。
## Tauri 桌面壳
Tauri 壳同样只负责桌面宿主能力,不承接玩法业务。
推荐能力:
- Release 包默认打包当前 H5 `dist`,保证桌面包版本可复现。
- Dev 模式允许加载本地 Vite URL方便调试。
- H5 通过 `window.__TAURI__.core.invoke('host_bridge_request', request)` 或后续封装的 `nativeAppHostBridge` 调用桌面能力。
- Rust 侧只暴露一个受控 `host_bridge_request` command再在 Rust 内部按 method 白名单分发。
- Tauri capabilities 只授予主窗口所需命令默认不开放文件系统、shell、全局剪贴板或任意插件能力。
- 桌面支付首期走现有 H5 / 二维码 / 外部浏览器路径,不在 Rust 侧保存支付凭据。
- 文件导出、作品卡保存、图片拖拽导入、系统托盘、自动更新等桌面能力按后续需求逐项开放。
桌面 release 和 dev 模式:
```text
release:
Tauri binary
-> packaged web assets
-> /index.html?clientRuntime=native_app&hostShell=tauri_desktop...
dev:
Tauri binary
-> http://127.0.0.1:<vite-port>/?clientRuntime=native_app&hostShell=tauri_desktop...
```
如果未来希望桌面端加载远端 H5 URL必须额外做 origin allowlist、版本协商和 Tauri API 暴露限制;不能让任意远端页面拿到桌面命令。
## AI H5 沙箱边界
移动端和桌面端统一后AI 生成 H5 游戏仍不能直接接入 `HostBridge`
AI H5 游戏运行结构:
```text
平台 H5 runtime
-> sandbox iframe
-> AI 生成 H5 游戏
-> window.parent.postMessage(GameBridgeRequest)
```
GameBridge 只允许:
- 读取启动参数和只读资产 URL。
- 上报 ready、progress、score、event、error。
- 提交候选结果给父页面,由父页面和后端裁决。
- 请求有限的音频、震动、全屏等运行态能力。
GameBridge 禁止:
- 登录、支付、订阅授权。
- 读取 token、cookie、完整用户资料。
- 任意网络代理。
- 任意本地文件、剪贴板和系统命令。
- 直接调用 Expo / Tauri / 小程序宿主能力。
## 安全约束
- HostBridge request 必须校验 `bridge``version``id``method` 和 payload shape。
- 壳层只接受来自允许 origin / packaged asset 的消息。
- 每个请求必须有超时,重复 `id` 不得重复执行支付、登录等非幂等动作。
- 能力按 `capabilities` 下发H5 根据能力决定是否展示入口或走 fallback。
- 宿主壳不得把长期 token、支付密钥或用户敏感资料回传给 H5。
- Tauri 禁止把 shell / fs 等高危插件作为默认能力暴露给主 WebView。
- RN WebView 禁止打开任意 URL 后仍保留完整 HostBridge跳外链应使用系统浏览器或降级能力。
- AI sandbox iframe 必须使用独立 CSP、`sandbox` 属性和单独 GameBridge allowlist。
## 分阶段落地
### Phase 1补齐 H5 native_app adapter
-`src/services/host-bridge/` 增加 `nativeAppHostBridge` transport。
- 定义 HostBridge envelope、method、错误码和超时策略。
- `getHostRuntime()` 继续识别 `clientRuntime=native_app`
- 现有业务入口只通过 HostBridge 调用登录、支付、分享、原生页跳转。
- 增加 H5 单测覆盖:支持、超时、不支持、错误回包、浏览器 fallback。
当前状态:已新增 `src/services/host-bridge/nativeAppHostBridge.ts`,支持 React Native WebView `postMessage` 和 Tauri `invoke('host_bridge_request')` 两种真实 transport。登录、支付和原生页跳转如果宿主明确返回 `unsupported_method` / `unsupported_capability`H5 回退到原有路径;生产代码不返回 mock 成功。
### Phase 2Expo 移动壳 MVP
- 新增 `apps/mobile-shell/`
- 接入 `react-native-webview`,加载 H5 URL 并附加宿主 query。
- 实现 HostBridge RN transportruntime、openExternalUrl、share、clipboard、haptics。
- Android 返回键与 H5 history 对齐。
- iOS / Android 深链打开作品详情、创作页和邀请码。
- 登录和支付先 fallback 到 H5只把能力边界跑通。
当前状态:已新增 `apps/mobile-shell/`,通过 Expo development build 运行,`react-native-webview` 加载 H5 URL 并附加 `native_app` 宿主 query。首轮真实能力包括 `host.getRuntime``share.open``share.setTarget``app.openExternalUrl``clipboard.writeText``haptics.impact` 和 Android 返回键回退;登录、支付和原生页跳转尚未接入渠道 SDK 时明确返回 unsupported让 H5 fallback 承接。
### Phase 3Tauri 桌面壳 MVP
- 新增 `apps/desktop-shell/`
- 配置 Tauri dev / release web asset 加载。
- Rust 暴露 `host_bridge_request` command。
- capabilities 只开放该 command 和必要窗口能力。
- 实现 runtime、openExternalUrl、clipboard、share fallback、窗口标题同步。
- 验证 macOS / Windows / Linux 至少一条本地 smoke。
当前状态:已新增 `apps/desktop-shell/`Tauri dev 直接加载本地主站 Viterelease 打包根 `dist` 主站资产。Rust 侧只把 `host_bridge_request` command 授给主窗口,`app.openExternalUrl` 由 Rust 内部通过 opener 插件执行,不把 opener 插件直接暴露给前端;首轮真实能力为 `host.getRuntime``app.openExternalUrl`。剪贴板、分享面板、登录和支付未接入真实插件 / 渠道前不声明支持,不返回 mock 成功。
### Phase 4宿主能力扩展
- 移动端接入系统分享、推送、原生登录和渠道支付。
- 桌面端接入自动更新、文件导出、图片拖拽导入和系统托盘。
- 所有新增能力先更新 HostBridge 契约和测试,再落壳实现。
### Phase 5AI H5 sandbox
- 定义 `GameBridge` 契约。
- 生成代码包只进入 sandbox iframe。
- 父页面负责资产授权、事件转发和后端裁决。
- Expo / Tauri 壳只感知父页面 HostBridge不直接感知 AI 游戏代码。
## 验收清单
- 普通浏览器、小程序、Expo 壳、Tauri 壳都能返回正确 `getHostRuntime()`
- 未支持的宿主能力不会阻断主流程H5 fallback 可用。
- 固定玩法在四类宿主里读取同一作品数据和运行态 snapshot不走代码包下载。
- 支付、登录、分享都有幂等、超时和错误回包。
- AI sandbox 无法调用 HostBridge也无法读取 H5 登录态。
- Tauri release 包不允许任意远端页面调用桌面命令。
- Expo WebView 外链离开主站后不保留完整 HostBridge。
## 参考资料
- Expo development builds`https://docs.expo.dev/develop/development-builds/introduction/`
- Expo custom native code`https://docs.expo.dev/workflow/customizing/`
- Expo config plugins`https://docs.expo.dev/config-plugins/introduction/`
- React Native WebView guide`https://github.com/react-native-webview/react-native-webview/blob/master/docs/Guide.md`
- Tauri commands`https://v2.tauri.app/develop/calling-rust/`
- Tauri capabilities`https://v2.tauri.app/security/capabilities/`
- Tauri permissions`https://v2.tauri.app/security/permissions/`
## 关联文档
- `docs/【前端架构】宿主壳能力统一协议-2026-06-17.md`
- `src/services/host-bridge/hostBridge.ts`

View File

@@ -64,5 +64,6 @@ AI H5 sandbox
## 后续
- 设计 `native_app``postMessage` 消息格式和回包超时策略。
- 原生 App 壳的移动端采用 `Expo + React Native`,桌面端采用 `Tauri`;壳层只作为 HostBridge adapter不重写现有 H5 主站和固定玩法 runtime。详细方案见 `docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md`
- 为 AI H5 sandbox 单独定义 GameBridge禁止直接依赖 HostBridge。
- 将宿主能力、支付渠道和分享策略补充进移动端发布检查清单。