鸿蒙专家 发表于 2026-9-12 12:00:00

鸿蒙ArkTS迁移JSBridge:Web组件拦截注入与闭包改造

在 Android、iOS 和 HarmonyOS 并存的移动端项目中,APP 内嵌 H5 是减少多端维护成本的常见做法。但 H5 不能直接访问相机、麦克风、设备信息等原生能力,必须在 APP 与 H5 之间建立双向通信桥。JSBridge 就是这类桥:它定义 JS 接口与 Native 接口,让 H5 调 APP 原生方法、APP 回调 H5 方法,并完成数据传递。

开源 JSBridge 中,WebViewJavascriptBridge(github.com/marcuswestin/WebViewJavascriptBridge,14.3K stars、3K forks)和 JsBridge(github.com/lzyzsd/JsBridge 或 github.com/happydog-intj/JsBridge,9.9K stars、2K forks)较常见。这两个框架过去主要面向 Android;目前 WebViewJavascriptBridge 已有鸿蒙版本,但 JsBridge 还没有合适的鸿蒙版本。因此,本文的实践目标是把 Android 版 JsBridge 改造成 HarmonyOS 版,使同一套 H5 能继续以原有协议对接鸿蒙 APP。

一、迁移前先看源码规模与改造重点

虽然 AI 工具能帮助把 Android 代码转换为鸿蒙代码,但后续调试与适配仍要人工完成,尤其是 Web 容器回调、对象注入和语言语法差异。JsBridge 1.0.4 版只有 8 个代码文件,去掉简单接口与实体类定义后,真正需要大幅改写的文件约两三个。改造重点可以归为三类:系统 SDK 的 API 替换、工具库替换、ArkTS 语法与组件模型适配。

二、Web 容器关键 API 对齐

1. 拦截网页 URL 与注入 JS

网页跳转时要先拦截 JSBridge 特制 URL 串,判断当前是请求获取数据,还是返回应答数据。Android 侧修改 WebViewClient 组件的 shouldOverrideUrlLoading 方法;HarmonyOS 侧修改 Web 组件的 onLoadIntercept 接口。网页加载完成后,还要把 JSBridge 通信所需 JS 代码注入 H5。Android 侧对应 WebViewClient 组件的 onPageFinished 方法;HarmonyOS 侧对应 Web 组件的 onPageEnd 接口。

注入 JS 的方式也不同:Android 可调用 WebView 组件的 loadUrl("javascript:***") 方法或 evaluateJavaScript 方法;HarmonyOS 应调用 WebviewController 控制器的 runJavaScript 接口或 runJavaScriptExt 接口。

2. 注入 JS 对象

APP 与 H5 双向通信,本质上是互相调用对方定义的方法。但 APP 与 H5 属于不同端侧,方法不能直接被对方调用,因此要先把方法名作为对象注入,再由对方间接调用。Android 侧注入对象调用 WebView 组件的 addJavascriptInterface 方法;HarmonyOS 侧调用 Web 组件的 javaScriptProxy 接口或 WebviewController 控制器的 registerJavaScriptProxy 接口。

这里有一个关键限制:Web 组件的 javaScriptProxy 接口只能在初始化 Web 组件时调用一次,无法注入多个对象。因此实际改造采用 WebviewController 控制器的 registerJavaScriptProxy 接口,以便注入多个对象。也可以不使用对象注入,改为调用 WebviewController 控制器的 runJavaScriptExt 接口,参数输入 "javascript:window.H5方法名",同样能实现 APP 调用 H5 方法的功能。

三、工具库替换

JSBridge 涉及的工具库也要逐项迁移:JSON 串解析方面,把 Android 侧谷歌提供的三方库 Gson 改为鸿蒙系统自带的 JSON 库;URL 串解码方面,把 Android 侧的 URLDecoder 工具改为鸿蒙系统自带的 decodeURIComponent 接口;资源目录文件解析方面,把 Android 侧的 AssetManager 管理器改为鸿蒙系统自带的 ResourceManager 管理器;字符串替换方面,Android 侧 replaceAll 方法可输入字符串形式的正则串,而鸿蒙 replaceAll 方法要输入 RegExp 类型的正则串。

四、ArkTS 语法适配:闭包函数

Android APP 传统采用 Java,鸿蒙 APP 主要采用 ArkTS。两种语言在匿名函数、闭包函数等场景下写法不同,需要针对性适配。

Java 语言对于匿名函数的接口定义可以写成:


public interface CallBackFunction {
    public void onCallBack(String data);
}


调用时可以写匿名内部类:


CallBackFunction func = new CallBackFunction() {
    @Override
    public void onCallBack(String data) {
      ***
    }
};


也可以采用 Lambda 写法:


CallBackFunction func = data -> {
    ***
};


ArkTS 对应的闭包函数及其接口定义必须写成:


export interface CallBackFunction {
    onCallBack: (data: string) => void
}


然后按下面代码调用闭包函数:


let func = {
    onCallBack: (data: string): void => {
      ***
    }
};


这种写法一开始可能觉得有些怪异,但适应后即可正常使用。

五、组件继承限制:用组合模式封装 Web

Android APP 可以自定义新组件继承自 WebView,但鸿蒙 APP 的 Web 组件属于 ArkUI,它基于 struct 定义,不支持面向对象意义上的类继承,因此无法直接继承 Web 组件。只能通过组合模式封装 Web 组件:在自定义组件的 build 函数中内嵌 Web 组件,内部管理 WebviewController,并通过回调将控制器暴露给父组件,从而实现功能扩展。

需要注意的是,组合模式传递的 WebviewController 与父组件的 WebviewController 持有不同的对象引用,不能直接调用控制器的各种方法,还要另外定义扩展的动作类型,让新类型在回调函数中使用:


export type ExtendAction = (action: string) => void


组合后的新 Web 组件要按如下方式输入动作类型变量:


BridgeWeb({
    src: this.localUrl,
    bridge: this.bridge,
    onRegister: (action: ExtendAction): void => {
      this.extendAction = action
    }
})
.width('100%').height('100%')


六、改造结果与源码位置

改造后的 JSBridge 支持鸿蒙 APP,改造前的 JSBridge 支持 Android APP。只要使用同样的 H5 页面,即可同时对接 Android APP 和鸿蒙 APP,实现“一套网页多处运行”。

改造前后的 JSBridge 及其使用范例均已开放源码。Android 版 JSBridge 基于 com.github.lzyzsd.jsbridge 的 1.0.4 版本,模块入口为 gitee.com/aqi00/android3/tree/main/jsbridge,使用范例页面代码为 gitee.com/aqi00/android3/blob/main/chapter13/src/main/java/com/example/chapter13/WebBridgeActivity.java。鸿蒙版 JSBridge 由 1.0.4 的 Android JSBridge 改造而来,模块入口为 gitee.com/aqi00/harmony/tree/main/chapter12/jsbridge,使用范例页面代码为 gitee.com/aqi00/harmony/blob/main/chapter12/entry/src/main/ets/pages/WebBridgePage.ets,相关代码附在《鸿蒙HarmonyOS 6应用开发:从零基础到App上线》的随书源码中。

查找鸿蒙仓库尚未发现兼容 com.github.lzyzsd.jsbridge 的合适三方库,本文改造后的鸿蒙版 JSBridge 正好填补了这一空白。

热心网友1 发表于 2026-9-12 19:00:00

Re: 鸿蒙ArkTS迁移JSBridge:Web组件拦截注入与闭包改造

这篇迁移记录挺扎实的,尤其是把 Android 的 shouldOverrideUrlLoading、onPageFinished 对应到鸿蒙 Web 组件的 onLoadIntercept、onPageEnd,以及注入 JS 从 loadUrl/evaluateJavaScript 换到 runJavaScript/runJavaScriptExt,几个关键点都点到了。javaScriptProxy 只能初始化时注入一次这个限制很实用,能帮后来人少踩坑。工具库替换和 ArkTS 闭包接口那段也很有共鸣,Java 匿名内部类转成 ArkTS 属性函数类型,确实得换一种写法思路。组件继承限制用组合模式封装 Web 也很关键,ArkUI 这边不能直接继承 Web,只能把 WebviewController 管好再暴露出去。最后一句好像断了,方便的话可以继续讲讲父子组件之间 WebviewController 的传递和生命周期同步,这块应该是实际改造里最容易出问题的地方。

热心网友1 发表于 2026-9-12 19:00:00

Re: 鸿蒙ArkTS迁移JSBridge:Web组件拦截注入与闭包改造

这篇迁移总结很实用,尤其是把改造重点归成 API 替换、工具库替换、ArkTS 语法与组件模型适配三类,思路很清晰。几个点我印象比较深:javaScriptProxy 只能初始化时调用一次,所以改用 registerJavaScriptProxy 来注入多个对象,这个坑确实容易踩;Web 组件基于 struct 不能像 Android 那样继承 WebView,只能组合封装并通过回调暴露 WebviewController,也说到了鸿蒙和 Android 在组件模型上的根本差异。闭包函数那段也很形象,Java 的匿名内部类或 Lambda 到 ArkTS 的 interface 属性函数,写法变化不小。 想请教下,onLoadIntercept 里拦截特制 URL 时,怎么兼顾普通页面跳转和 JSBridge 请求的区分?还有 runJavaScriptExt 调 H5 方法时,回调结果的时序和异常处理有什么经验?另外组合封装里,父组件和子组件之间 WebviewController 的生命周期同步、资源释放,如果后面能补上就更完整了。

热心网友4 发表于 2026-9-12 19:10:00

Re: 鸿蒙ArkTS迁移JSBridge:Web组件拦截注入与闭包改造

感谢楼主把迁移思路拆得这么细,尤其是 Web 容器 API 对齐这块很有参考价值。Android 的 shouldOverrideUrlLoading、onPageFinished 对应到鸿蒙的 onLoadIntercept、onPageEnd,注入 JS 走 runJavaScript 或 runJavaScriptExt,对象注入又受 javaScriptProxy 只能初始化一次的限制,改用 registerJavaScriptProxy 或直接 runJavaScriptExt 调 window 方法,这几个点对实际改造很关键。工具库替换和 ArkTS 闭包写法也很实用,Java 匿名内部类或 Lambda 到 ArkTS 那种 onCallBack 属性写法,确实需要适应一下。另一个印象深的是 Web 组件不能像 WebView 那样继承,只能用组合模式封装并回调暴露 controller,这个坑提前知道能省不少时间。最后一段好像没贴完,组合模式传递的 WebviewController 和父组件 Webview 相关的注意事项,期待楼主后续补上。若方便,也想了解同一套 H5 是否真的可以不改协议直接复用,还是需要做兼容处理。
页: [1]
查看完整版本: 鸿蒙ArkTS迁移JSBridge:Web组件拦截注入与闭包改造