# 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 页面?

相关推荐
轻口味1 小时前
HarmonyOS 7 新特性5:平行视界——轻视界文集的两栏阅读与窗口状态边界矩阵真机实测
华为·矩阵·harmonyos·鸿蒙·平行视界
动物园猫2 小时前
Compose Multiplatform 三方库 compose-icons(Octicons)的 OpenHarmony 鸿蒙化适配实战
华为·ar·harmonyos
旺仔Sec3 小时前
2026年江西省职业院校技能大赛鸿蒙应用开发赛项竞赛任务书(高职组)样题
华为·harmonyos
曲鸟3 小时前
体验完鸿蒙AI后的几点感受
人工智能·华为·harmonyos
HwJack203 小时前
【HarmonyOS开发小实践】Node-API 的SO 命名规则、多线程限制与调试
华为·harmonyos
LucianaiB3 小时前
用 HarmonyOS 做一张会写诗的月夜明信片:追月的完整开发复盘
华为·ai·harmonyos·skill
蒸鱼Yuzheng4 小时前
HarmonyOS HAP 与调试工件治理:包结构、版本身份与自动化证据链
自动化·性能测试·数据治理·harmonyos·hap
轻口味5 小时前
HarmonyOS 7 新特性3:TiledGSNode——轻带看让 71MB 庭院按视口按需加载:真机实测与零请求降级
华为·harmonyos·鸿蒙·tiledgsnode
李游Leo5 小时前
《HarmonyOS 7 ArkGraphics 3D 空间设计开发实战》01:从空场景到第一个可运行的3D房间【鸿蒙心迹】
3d·华为·harmonyos