# ArkWeb 手记 03|把 JSBridge 做成协议

HarmonyOS 7 · ArkWeb 混合应用开发手记 03

上一篇已经把 H5 和 ArkTS

的双向调用跑通了。真正进业务以后,问题很快就从"能不能调用"变成"调用多了以后怎么不乱"。分享、登录、支付、定位、设备信息一起进来,如果每个方法都有自己的参数和回调,Bridge

很快会变成一团线。

这一篇不继续加能力,先把通信协议定下来。核心只有四个词:method、requestId、params、统一响应。

1. 为什么需要 requestId

H5

连续发两个异步请求时,返回顺序不一定和发出顺序一样。最稳的做法,是每次请求都带一个唯一

ID:

ts 复制代码
interface BridgeRequest {
  requestId: string
  method: string
  params: string
}

interface BridgeResponse {
  requestId: string
  code: number
  message: string
  data: string
}

requestId 就像快递单号。结果回来以后,不需要猜它属于哪个请求。

【配图 01:BridgeRequest / BridgeResponse 协议代码,红圈标 requestId】

2. H5 侧只保留一个入口

不要继续增加 getToken()、openShare()、getLocation()

这种全局入口。可以把调用收成:

js 复制代码
function callNative(method, params = {}) {
  const requestId = `${Date.now()}_${Math.random()}`
  return new Promise((resolve, reject) => {
    pending.set(requestId, { resolve, reject })
    NativeBridge.invoke(JSON.stringify({
      requestId,
      method,
      params
    }))
  })
}

业务侧就很舒服:

js 复制代码
const result = await callNative('getAppInfo')

3. ArkTS 做统一分发

原生只暴露一个 invoke:

ts 复制代码
invoke(raw: string): void {
  try {
    const request: BridgeRequest = JSON.parse(raw)
    this.dispatch(request)
  } catch (e) {
    console.error('[Bridge] invalid request')
  }
}

再按 method 分发:

ts 复制代码
private dispatch(req: BridgeRequest): void {
  switch (req.method) {
    case 'getAppInfo':
      this.getAppInfo(req)
      break
    case 'openShare':
      this.openShare(req)
      break
    default:
      this.reply(req.requestId, 404, 'method not found', '')
  }
}

这里宁可多写一个 switch,也不要动态执行任意方法名。Bridge

是能力边界,不是万能反射器。

4. 返回结构必须统一

成功和失败都走同一个结构:

ts 复制代码
private reply(id: string, code: number,
  message: string, data: string): void {
  const result: BridgeResponse = {
    requestId: id,
    code,
    message,
    data
  }
  this.sendToH5(result)
}

H5 收到后只处理一次:

js 复制代码
window.onNativeMessage = function (result) {
  const task = pending.get(result.requestId)
  if (!task) return

  pending.delete(result.requestId)

  if (result.code === 0) {
    task.resolve(result.data)
  } else {
    task.reject(new Error(result.message))
  }
}

5. Promise 不是重点,超时才是

最容易漏的是:原生如果永远不回,Promise 就永远 pending。

js 复制代码
const timer = setTimeout(() => {
  pending.delete(requestId)
  reject(new Error(`Bridge timeout: ${method}`))
}, 10000)

收到结果时记得 clearTimeout(timer)。10 秒不是标准值,要按业务调整。

6. 错误码不要随手写

至少分清:成功、参数错误、方法不存在、业务失败、超时。

ts 复制代码
enum BridgeCode {
  SUCCESS = 0,
  INVALID_PARAMS = 400,
  METHOD_NOT_FOUND = 404,
  BUSINESS_ERROR = 500
}

别今天返回 -1,明天返回 false,后天又返回字符串

"error"。这种协议最难维护。

7. 给协议加版本

ts 复制代码
interface BridgeRequest {
  version: string
  requestId: string
  method: string
  params: string
}

H5 和 App

不一定同时发版。版本字段不是为了显得专业,而是给以后兼容留出口。

8. 日志也按 requestId 串起来

text 复制代码
[Bridge][REQ][req_1001] getAppInfo
[Bridge][RES][req_1001] code=0

线上排查时,只搜一个 ID 就能看到完整链路。

9. 不要把敏感能力直接暴露

支付、账号、文件、定位都应该有白名单和参数校验。Bridge 收到 method

不等于一定执行。

ts 复制代码
private allowedMethods: Set<string> =
  new Set(['getAppInfo', 'openShare'])

来源、页面、登录态和业务权限需要按项目继续校验。

10. 这一篇真正得到什么

到这里,JSBridge 从"几个能调用的方法"变成了一条协议:请求有

ID,响应有固定结构,异步有超时,能力有白名单,日志可以串联。

下一篇我们处理另一个很真实的问题:H5

连续跳了三层以后,用户按返回,到底应该退网页还是退 ArkUI 页面?

相关推荐
用户294694054481613 小时前
DSH Desktop - Electron on HarmonyOS Edition
harmonyos·deepseek
IsITGirl15 小时前
HarmonyOS 鸿蒙 WuKong 稳定性测试报错 Failed to connect to AAMS(已解决)
华为·harmonyos
万物智能信息科技17 小时前
鸿蒙RS232驱动开发—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
驱动开发·华为·开源·harmonyos·鸿蒙
less_1213818 小时前
鸿蒙 WPS Open SDK 接入指南:凭据申请、HAR 集成与 registerApp 校验
华为·harmonyos·wps
威哥爱编程1 天前
HarmonyOS 7 Agent 开发实战 07:多 Agent 任务分解与反思
agent·harmonyos
威哥爱编程1 天前
HarmonyOS 7 Agent 开发实战 06:Agent 记忆与上下文管理
agent·harmonyos
HarmonyOS_SDK2 天前
【HarmonyOS SDK Skills】扫码能力一键构建,系统级高精度扫码秒实现
harmonyos
结局无敌2 天前
React Native for OpenHarmony 实战:三方库 react-native-modal-dialog 的鸿蒙化适配指南
深度学习·算法·react native·react.js·harmonyos
结局无敌2 天前
React Native for OpenHarmony 实战:三方库 react-native-paper 的鸿蒙化适配指南
javascript·人工智能·深度学习·react native·react.js·ecmascript·harmonyos
七月稻草人2 天前
鸿蒙手机远程控制电脑选哪个?2026 鸿蒙远控软件横评
智能手机·电脑·harmonyos