Files
cmr-mini/doc/experience/原生与H5桥接规范.md

388 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 原生与 H5 Bridge 协议草案
> 文档版本v1.0
> 最后更新2026-04-02 08:28:05
本文档定义当前项目中 **原生小程序****H5 定制内容页** 之间的基础通信协议。
目标:
- 让 H5 能获取当前游戏上下文
- 让 H5 能请求原生能力
- 让原生能接收 H5 的结果回传
- 保持协议简单、稳定、可版本化
- 为后续拍照、录音、小游戏、结果页等扩展留出空间
---
## 0. 当前适用前提
本规范当前属于:
- 协议与实现预留
- 容器与回退机制先行
最近排查已经确认,当前最初使用的是**个人主体**小程序。
在这个前提下,`web-view` 能力本身可能受限。
因此:
- Bridge 规范仍然应该先定义
- 容器页与回退机制也应该先实现
- 但在企业主体审核通过前,不应把 H5 接入是否成功完全归因于 bridge 代码本身
详细说明见:
- [platform-capability-notes.md](D:/dev/cmr-mini/doc/debug/平台能力说明.md)
---
## 1. 协议原则
### 原则 1Bridge 要版本化
建议先固定:
- `content-v1`
- `result-v1`
后续升级时:
- 新增 `content-v2`
- 新增 `result-v2`
不要直接改旧协议。
### 原则 2请求能力最小化
先只开放真正需要的能力,不要一开始做成“大而全总线”。
### 原则 3原生控制核心状态
Bridge 只能做:
- 展示
- 上报
- 请求能力
不能让 H5 直接改比赛核心状态。
### 原则 4消息必须可回执
每个请求都应有明确成功/失败返回,不允许 H5 靠超时猜测。
---
## 2. 通道模型
建议统一按“请求 / 响应 / 事件”三类消息组织:
- `request`
H5 请求原生能力
- `response`
原生返回能力执行结果
- `event`
原生主动推送状态变化
推荐消息外壳:
```json
{
"id": "req-001",
"channel": "request",
"type": "getGameContext",
"payload": {}
}
```
响应:
```json
{
"id": "req-001",
"channel": "response",
"type": "getGameContext",
"ok": true,
"payload": {}
}
```
---
## 3. 原生注入给 H5 的基础上下文
建议至少包含:
```json
{
"bridgeVersion": "content-v1",
"eventId": "sample-score-o-001",
"mode": "score-o",
"sessionId": "session-001",
"sessionStatus": "running",
"controlId": "control-3",
"controlKind": "control",
"title": "湖边步道",
"body": "这里适合短暂停留观察周边地形。",
"theme": "default-race"
}
```
对于结果页,可扩展为:
```json
{
"bridgeVersion": "result-v1",
"eventId": "sample-score-o-001",
"mode": "score-o",
"sessionId": "session-001",
"summary": {
"title": "比赛结束",
"heroValue": "120",
"rows": []
}
}
```
---
## 4. H5 -> 原生:第一阶段推荐动作
建议第一阶段只支持这几个:
### `close`
作用:
- 关闭当前 H5 页面
示例:
```json
{
"id": "req-001",
"channel": "request",
"type": "close",
"payload": {}
}
```
### `getGameContext`
作用:
- 让 H5 主动获取最新上下文
### `takePhoto`
作用:
- 请求原生拍照
### `recordAudio`
作用:
- 请求原生录音
### `submitResult`
作用:
- 把 H5 内的任务结果、表单或作品结果提交回原生
示例:
```json
{
"id": "req-002",
"channel": "request",
"type": "submitResult",
"payload": {
"taskId": "photo-task-1",
"status": "completed",
"assetId": "img-001"
}
}
```
---
## 5. 建议第二阶段可扩展动作
等第一阶段跑稳后,再逐步加入:
- `uploadImage`
- `uploadAudio`
- `getLocation`
- `openMiniGame`
- `submitForm`
- `share`
- `restartSession`
这些先不要第一阶段全开。
---
## 6. 原生 -> H5统一返回结构
建议统一返回:
```json
{
"id": "req-002",
"channel": "response",
"type": "takePhoto",
"ok": true,
"payload": {
"assetId": "img-001",
"url": "https://example.com/assets/img-001.jpg"
}
}
```
失败时:
```json
{
"id": "req-002",
"channel": "response",
"type": "takePhoto",
"ok": false,
"error": {
"code": "USER_CANCELLED",
"message": "用户取消拍照"
}
}
```
---
## 7. 原生 -> H5推荐事件
原生可按需主动推送轻量事件:
- `contextUpdated`
- `sessionFinished`
- `sessionExited`
- `networkChanged`
但第一阶段要克制,避免高频推送。
不建议第一阶段主动高频推:
- GPS 实时位置流
- 指北针实时角度
- HUD 高频数字
这些不适合让 H5 主导。
---
## 8. 错误码建议
建议第一阶段统一几类错误:
- `USER_CANCELLED`
- `PERMISSION_DENIED`
- `NETWORK_ERROR`
- `UNSUPPORTED_ACTION`
- `BRIDGE_NOT_READY`
- `INTERNAL_ERROR`
这样 H5 侧更容易统一处理。
---
## 9. 安全与边界
### 9.1 H5 不直接改核心比赛状态
H5 不能直接决定:
- 是否打点成功
- 是否跳点成功
- 是否比赛结束
### 9.2 H5 只能请求能力
原生决定是否执行:
- 拍照
- 录音
- 上传
- 页面关闭
### 9.3 Bridge 能力按页面类型开放
例如:
- 内容页开放 `takePhoto`
- 结果页不一定开放
后续可做按 `bridgeVersion``pageType` 的能力白名单。
---
## 10. 第一阶段推荐支持范围
建议第一阶段只正式支持:
- `close`
- `getGameContext`
- `takePhoto`
- `recordAudio`
- `submitResult`
这样足够承接:
- 文创详情
- 拍照任务
- 语音留言
- 结果页回传动作
---
## 11. 不建议第一阶段支持的内容
先不要一上来开放:
- 任意写比赛状态
- 任意切换玩法
- 任意修改地图行为
- 任意控制打点
- 高频实时 telemetry 推送
这些都属于核心状态,应该继续由原生掌控。
---
## 12. 当前建议实施顺序
1. 先实现一个通用 H5 容器页
2. 先跑通 `content-v1`
3. 先支持 5 个最小动作
4. 再跑通一个简单结果页
5. 最后再扩桥接能力
---
## 13. 当前建议结论
Bridge 的第一阶段目标,不是做成万能总线,而是:
**稳定承接定制内容页与结果页的最小需求。**
先把:
- 关闭
- 获取上下文
- 拍照
- 录音
- 结果提交
这 5 条做稳,就足够支撑第一波客户定制需求。