@@ -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 2: Expo 移动壳 MVP
- 新增 `apps/mobile-shell/` 。
- 接入 `react-native-webview` ,加载 H5 URL 并附加宿主 query。
- 实现 HostBridge RN transport: runtime、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 3: Tauri 桌面壳 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 直接加载本地主站 Vite, release 打包根 `dist` 主站资产。Rust 侧只把 `host_bridge_request` command 授给主窗口,`app.openExternalUrl` 由 Rust 内部通过 opener 插件执行,不把 opener 插件直接暴露给前端;首轮真实能力为 `host.getRuntime` 和 `app.openExternalUrl` 。剪贴板、分享面板、登录和支付未接入真实插件 / 渠道前不声明支持,不返回 mock 成功。
### Phase 4: 宿主能力扩展
- 移动端接入系统分享、推送、原生登录和渠道支付。
- 桌面端接入自动更新、文件导出、图片拖拽导入和系统托盘。
- 所有新增能力先更新 HostBridge 契约和测试,再落壳实现。
### Phase 5: AI 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`