native-h5-bridge-spec.md 6.0 KB

原生与 H5 Bridge 协议草案

本文档定义当前项目中 原生小程序H5 定制内容页 之间的基础通信协议。

目标:

  • 让 H5 能获取当前游戏上下文
  • 让 H5 能请求原生能力
  • 让原生能接收 H5 的结果回传
  • 保持协议简单、稳定、可版本化
  • 为后续拍照、录音、小游戏、结果页等扩展留出空间

0. 当前适用前提

本规范当前属于:

  • 协议与实现预留
  • 容器与回退机制先行

最近排查已经确认,当前最初使用的是个人主体小程序。
在这个前提下,web-view 能力本身可能受限。

因此:

  • Bridge 规范仍然应该先定义
  • 容器页与回退机制也应该先实现
  • 但在企业主体审核通过前,不应把 H5 接入是否成功完全归因于 bridge 代码本身

详细说明见:


1. 协议原则

原则 1:Bridge 要版本化

建议先固定:

  • content-v1
  • result-v1

后续升级时:

  • 新增 content-v2
  • 新增 result-v2

不要直接改旧协议。

原则 2:请求能力最小化

先只开放真正需要的能力,不要一开始做成“大而全总线”。

原则 3:原生控制核心状态

Bridge 只能做:

  • 展示
  • 上报
  • 请求能力

不能让 H5 直接改比赛核心状态。

原则 4:消息必须可回执

每个请求都应有明确成功/失败返回,不允许 H5 靠超时猜测。


2. 通道模型

建议统一按“请求 / 响应 / 事件”三类消息组织:

  • request H5 请求原生能力
  • response 原生返回能力执行结果
  • event 原生主动推送状态变化

推荐消息外壳:

{
  "id": "req-001",
  "channel": "request",
  "type": "getGameContext",
  "payload": {}
}

响应:

{
  "id": "req-001",
  "channel": "response",
  "type": "getGameContext",
  "ok": true,
  "payload": {}
}

3. 原生注入给 H5 的基础上下文

建议至少包含:

{
  "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"
}

对于结果页,可扩展为:

{
  "bridgeVersion": "result-v1",
  "eventId": "sample-score-o-001",
  "mode": "score-o",
  "sessionId": "session-001",
  "summary": {
    "title": "比赛结束",
    "heroValue": "120",
    "rows": []
  }
}

4. H5 -> 原生:第一阶段推荐动作

建议第一阶段只支持这几个:

close

作用:

  • 关闭当前 H5 页面

示例:

{
  "id": "req-001",
  "channel": "request",
  "type": "close",
  "payload": {}
}

getGameContext

作用:

  • 让 H5 主动获取最新上下文

takePhoto

作用:

  • 请求原生拍照

recordAudio

作用:

  • 请求原生录音

submitResult

作用:

  • 把 H5 内的任务结果、表单或作品结果提交回原生

示例:

{
  "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:统一返回结构

建议统一返回:

{
  "id": "req-002",
  "channel": "response",
  "type": "takePhoto",
  "ok": true,
  "payload": {
    "assetId": "img-001",
    "url": "https://example.com/assets/img-001.jpg"
  }
}

失败时:

{
  "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
  • 结果页不一定开放

后续可做按 bridgeVersionpageType 的能力白名单。


10. 第一阶段推荐支持范围

建议第一阶段只正式支持:

  • close
  • getGameContext
  • takePhoto
  • recordAudio
  • submitResult

这样足够承接:

  • 文创详情
  • 拍照任务
  • 语音留言
  • 结果页回传动作

11. 不建议第一阶段支持的内容

先不要一上来开放:

  • 任意写比赛状态
  • 任意切换玩法
  • 任意修改地图行为
  • 任意控制打点
  • 高频实时 telemetry 推送

这些都属于核心状态,应该继续由原生掌控。


12. 当前建议实施顺序

  1. 先实现一个通用 H5 容器页
  2. 先跑通 content-v1
  3. 先支持 5 个最小动作
  4. 再跑通一个简单结果页
  5. 最后再扩桥接能力

13. 当前建议结论

Bridge 的第一阶段目标,不是做成万能总线,而是:

稳定承接定制内容页与结果页的最小需求。

先把:

  • 关闭
  • 获取上下文
  • 拍照
  • 录音
  • 结果提交

这 5 条做稳,就足够支撑第一波客户定制需求。