Appearance
Native 与 H5 交互协议
通信入口
| 方向 | 入口 | 参数 | 返回 |
|---|---|---|---|
| H5 → App | window.htmlToFlutterEvent.postMessage(message) | JSON 字符串 | Promise,完成值为结果 JSON 字符串 |
| App → H5 | window.flutterToHtmlEvent(message) | JavaScript 对象 | H5 处理结果,可能为空 |
H5 入口名称在纯原生、uni-app 和 Flutter 中保持一致。各容器负责实现传输层,不能只把 H5 的调用改为 uni.postMessage 或系统消息方法而省略结果回传。
H5 → App
请求参数
| 参数名 | 类型 | 必填 | 描述 | 示例值 |
|---|---|---|---|---|
| event | String | 是 | 事件名,区分大小写 | getAppInfo |
| data | Object / Array / String / Number / Boolean | 否 | 按事件定义传入;无参数可省略 | {} |
| callback | String | 否 | 兼容回调的全局函数路径;函数接收结果 JSON 字符串 | globalCallback |
请求与结果示例
javascript
async function queryAppInfo() {
var text = await window.htmlToFlutterEvent.postMessage(JSON.stringify({
event: 'getAppInfo',
data: {}
}));
var result = typeof text === 'string' ? JSON.parse(text) : text;
if (Number(result.code) !== 200) {
throw new Error(result.message || '获取应用信息失败');
}
return result.data;
}json
{
"event": "getAppInfo",
"timestamp": "2026-11-02T08:00:00.000Z",
"code": 200,
"message": "",
"data": {
"appName": "示例应用",
"packageName": "com.example.live",
"version": "1.0.0",
"buildNumber": "1",
"platform": "Android",
"scheme": "examplelive://"
}
}| 参数名 | 类型 | 必填 | 描述 | 示例值 |
|---|---|---|---|---|
| event | String | 是 | 对应请求事件 | getAppInfo |
| timestamp | String | 是 | App 生成结果的 ISO 8601 时间 | 2026-11-02T08:00:00.000Z |
| code | Number / String | 是 | 业务状态码,兼容数字及数字字符串 | 200 |
| message | String | 是 | 结果说明 | 未知事件 |
| data | Object / Array / String / Number / Boolean / Null | 是 | 事件结果,无数据时为 null | {} |
这些状态码属于桥接业务结果,与 HTTP 状态码分开处理:
| code | 说明 |
|---|---|
| 200 | 执行成功 |
| 400 | 参数错误、未知事件或当前容器未支持的事件 |
| 401 | 未取得所需用户身份;调用方同时兼容 "401" |
| 500 | Native 能力执行失败 |
callback 兼容示例
javascript
window.globalCallback = function (resultText) {
var result = JSON.parse(resultText);
console.log(result.event, result.code);
};
window.htmlToFlutterEvent.postMessage(JSON.stringify({
event: 'getAppInfo',
data: {},
callback: 'globalCallback'
}));同一请求可以同时完成 Promise 和调用 callback,业务方选择一个入口消费结果,避免重复处理。Promise 完成表示本次事件已得到结果;对于启动外部应用等事件,实际业务完成状态还需按对应业务流程确认。
openNativePage 示例:打开 App 内页面
openNativePage 用于演示自定义事件,由接入方在 App 分发方法中实现。H5 传入业务页面标识,App 将其映射到自己的 Activity、ViewController 或路由页面。
| 参数名 | 类型 | 必填 | 描述 | 示例值 |
|---|---|---|---|---|
| event | String | 是 | 固定为 openNativePage | openNativePage |
| data | Object | 是 | 目标页面及业务参数 | 见下方示例 |
| data.page | String | 是 | App 约定的页面标识,示例支持订单详情页 | orderDetail |
| data.params | Object | 是 | 目标页面参数 | {"orderId":"order_12345"} |
| data.params.orderId | String | 是 | 订单详情页所需的订单标识 | order_12345 |
各技术栈使用相同的 H5 调用示例:
javascript
async function onOpenNativePageClick() {
if (!window.htmlToFlutterEvent ||
typeof window.htmlToFlutterEvent.postMessage !== 'function') {
throw new Error('App 通道尚未就绪');
}
var responseText = await window.htmlToFlutterEvent.postMessage(JSON.stringify({
event: 'openNativePage',
data: { page: 'orderDetail', params: { orderId: 'order_12345' } }
}));
var result = typeof responseText === 'string' ? JSON.parse(responseText) : responseText;
if (!result || Number(result.code) !== 200) {
throw new Error(result && result.message || '打开 App 页面失败');
}
return result.data;
}json
{
"event": "openNativePage",
"timestamp": "2026-11-02T08:00:00.000Z",
"code": 200,
"message": "",
"data": { "page": "orderDetail" }
}200 表示 App 已发起跳转,目标页面的后续业务结果另行定义。未知页面或订单参数缺失返回 400,无法发起跳转返回 500。App 按约定的页面标识分发,示例不直接执行 H5 传入的任意路由地址。
需要适配的事件(按需接入)
下表是通用容器的对接范围。各 App 应根据所接入 H5 页面完成对应处理;示例包含 getAppInfo、openNativePage 及未知事件响应,其他事件需自行补齐。
| event | data 类型及内容 | 处理及结果 |
|---|---|---|
| getAppInfo | 可省略 | 返回上方示例中的应用信息对象,内容与 UA 一致 |
| openNativePage | Object,包含 page、params | 扩展示例:将业务标识映射到 App 页面并发起跳转,参数见上节 |
| getUserInfo | 可省略 | 返回已约定的用户展示信息;无身份时返回 401,不得直接暴露完整 App 登录凭证 |
| getLoginState | 可省略 | 返回 Boolean 登录状态 |
| getTabBarHeight | 可省略 | 返回 Number,H5 底部占位高度;无底栏时为 0,按页面 CSS 像素口径适配 |
| getSafeArea | 可省略 | 返回 {top, bottom},按 WebView 实际占位换算,避免重复留白 |
| setAppBarTitle | String 标题 | 更新原生导航栏标题 |
| goBack | 可省略 | WebView 可返回时返回上一页,否则关闭容器 |
| closeWebView / closeWebPage | 可省略 | 关闭容器,执行关闭前的通知和清理 |
| refreshWebView | 可省略 | 刷新页面,新文档需要重新安装 Bridge |
| launchUrl | String 外部 URL | 按 App 允许的目标处理外部应用唤起,失败返回 500 |
| wxShareLinkCard | Object,包含 url、title、description | 通过已配置的微信能力分享链接 |
| wxShareText | Object,包含 description | 通过已配置的微信能力分享文本 |
| horizontalScreen / verticalScreen | 可省略 | 切换原生页面方向,并同步容器布局 |
H5 初始化可能查询 getAppInfo、getUserInfo、getTabBarHeight 等事件,不能只实现关闭页面。用户字段和支付、连麦等扩展事件需按实际页面另行对齐,本模块不定义通用用户 Token 或支付协议。
App → H5
App 应在 H5 处理函数存在时调用,并传入对象。不要覆盖页面自己定义的 flutterToHtmlEvent。
| 参数名 | 类型 | 必填 | 描述 | 示例值 |
|---|---|---|---|---|
| event | String | 是 | App 主动发送的事件名 | appLifecycle |
| timestamp | String | 是 | 发送时间,ISO 8601 字符串 | 2026-11-02T08:00:00.000Z |
| data | Object / String | 否 | 事件数据 | resumed |
App 调 H5 示例:
javascript
window.flutterToHtmlEvent && window.flutterToHtmlEvent({
event: 'appLifecycle',
timestamp: new Date().toISOString(),
data: 'resumed'
});| event | data | 触发时机 |
|---|---|---|
| appLifecycle | inactive / paused / resumed / detached / hidden | 映射 App 实际生命周期;各系统无对应状态时不必发送 |
| pageLifecycle | didPush / didPop / didPushNext / didPopNext / dispose | 页面进入、离开、被覆盖、重新显示及销毁前 |
| getVideoInfo | 可省略 | 查询 H5 播放器尺寸,成功结果的 data 包含 width、height |
关闭前先通知 pageLifecycle / dispose,再释放 WebView。发送 JavaScript 的异步完成后再关闭;该通知不代表所有 H5 异步业务都已完成。App 回前台发送 appLifecycle / resumed,用于 H5 恢复相应页面业务。
示例适配脚本
纯原生和 uni-app 示例使用 bridgeRuntime.js,随 App 本地资源打包,补齐系统消息通道的 Promise。Flutter 使用插件的 callHandler 直接返回 Promise,不需要该脚本。
该脚本提供请求编号、Promise、可选 callback 和 10 秒传输超时。请求编号和超时由适配层管理,不属于 H5 业务消息字段。
10 秒是示例默认值。对需要用户操作或等待外部应用的事件,应按实际流程调整超时与后续业务通知,避免正常操作被过早判为传输失败。
容器先执行脚本,发送函数的安装示例:
javascript
window.AppBridgeAdapter.install(function (requestId, payload) {
// 容器适配:将 requestId 与原始 JSON 字符串发送到 App。
});App 完成分发后,将结果送回同一个页面的调用示例:
javascript
window.AppBridgeAdapter.receive(requestId, responseText);requestId 仅用于传输配对;responseText 是包含 event、code 等字段的结果 JSON 字符串。Native 拼接执行脚本时,应对两个参数分别进行 JSON 序列化。可选 callback 由适配脚本调用一次,使用该脚本时 Native 不能再额外调用一次 callback;Flutter 示例则由 Dart 接收方法兼容 callback。
各技术栈双向调用示例
以下文档均按两个方向给出配套代码:H5 如何发起及读取结果、Native 如何接收和回传;Native 如何调用、H5 如何接收及返回。
脚本注入应可重复执行,每次完整导航后为新文档重新安装。仅在可信 HTTPS 页面提供原生能力,拦截非预期页面导航;Android 的 JavaScript Interface 还会暴露给子框架,不应在同一容器中加载不可信 iframe。页面销毁后丢弃旧请求,不能向新页面回传旧结果。