ArkTS Web 组件里,如何通过 javaScriptProxy 让 JS 同步调用原生方法

ArkTS Web 组件里,如何通过 javaScriptProxy 让 JS 同步调用原生方法

网罗开发(小红书、快手、视频号同名)

大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
📣 公众号“Swift社区”,每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友“fzhanfei”,与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!

文章目录

前言

在鸿蒙应用里,只要你用过 Web 组件加载 H5 页面,基本都会绕不开一个问题:

H5 想直接调用 ArkTS 里的方法,该怎么做?

比如这些很典型的需求:

  • H5 点了一个按钮,希望直接触发原生能力
  • JS 想同步拿到设备信息、登录态、配置数据
  • Web 页面和 ArkTS 页面需要“像在同一个世界”里通信

很多人第一反应是:
“是不是只能用异步回调?”
但实际上,鸿蒙 Web 组件已经给了一个非常直观的同步调用方式——javaScriptProxy

这篇文章我们就从一个完整例子出发,把这套机制讲清楚。

Web 和 ArkTS 通信的核心思路

在鸿蒙 Web 组件中,javaScriptProxy 做的事情,本质上只有一件:

把 ArkTS 里的一个对象,按约定规则“注入”到 JS 运行环境中

注入完成后:

  • JS 端可以像调用普通对象一样
  • 同步调用 ArkTS 中的方法
  • 不需要额外桥接代码、不需要消息回调

但前提是三点必须满足:

  • ArkTS 端定义好“可暴露对象”
  • 明确哪些方法允许 JS 调用
  • Web 组件配置正确

下面我们一步一步拆。

一个最简单、但真实的使用场景

先设一个很常见的业务背景:

Web 页面是活动页
原生侧负责能力与数据
H5 需要直接拿到当前登录用户的 ID

这个场景特别适合用同步调用。

ArkTS 端:定义一个可注入的对象

第一步,是在 ArkTS 侧定义一个普通类,用来承载要暴露给 JS 的方法。

classJsBridge{getUserId():string{return'user_10086'}showToast(msg:string):void{console.info('来自 JS 的消息:'+ msg)}}

这里有几个非常重要的点:

  • 方法必须是同步方法
  • 不要返回 Promise
  • 返回值要是 JS 能理解的基础类型

建议一开始就把它当成:

“给 JS 用的工具类”,
而不是业务 Service。

Web 组件中配置 javaScriptProxy

接下来是关键步骤,把这个对象“挂”到 Web 组件上。

@Entry@Component struct WebPage { controller: WebviewController =newWebviewController() jsBridge: JsBridge =newJsBridge()build(){Web({ src:'https://example.com', controller:this.controller, javaScriptProxy:{ object:this.jsBridge, name:'nativeBridge', methodList:['getUserId','showToast'], controller:this.controller }})}}

这段代码里,每一项都很关键。

我们一条条拆。

javaScriptProxy 配置项逐条解析

object:真正被注入的对象

object:this.jsBridge 
  • 就是刚才定义的 JsBridge
  • JS 实际调用的就是这个实例上的方法

name:JS 侧访问的名字

name:'nativeBridge'
  • 这是 JS 侧能看到的对象名
  • JS 会通过 window.nativeBridge 来访问

这个名字,就是你给 JS 世界开的一个入口

methodList:允许被调用的方法白名单

methodList:['getUserId','showToast']

这是很多人容易忽略的一点。

  • 不在这个列表里的方法
  • JS 是无法调用的
  • 即使方法真实存在于对象中

这一步非常重要,它本质上是一个安全边界

controller:WebView 控制器

controller:this.controller 
  • 用于绑定当前 Web 实例
  • 没它,代理不会生效

JS 端:像调用普通对象一样调用 ArkTS

当 Web 页面加载完成后,JS 侧可以直接这样写:

const userId = window.nativeBridge.getUserId() console.log('当前用户ID:', userId) window.nativeBridge.showToast('你好,ArkTS')

注意这里的几个特点:

  • 是同步调用
  • 有返回值
  • 没有回调、没有 Promise

从 JS 的角度看,它完全不知道这是“原生方法”。

同步调用适合用在什么地方

很多人会问:

既然能同步,什么都用它行不行?

不太建议。

更合理的使用场景是:

  • 获取配置类数据
  • 获取登录态、环境信息
  • 触发简单原生行为

不太适合的场景包括:

  • 网络请求
  • 耗时计算
  • 涉及 IO 的操作

原因很简单:
同步调用一旦变慢,卡的是 Web 页面。

常见问题与踩坑经验

方法没暴露,JS 调用直接报错

九成是忘了加到 methodList

这是最常见、也是最隐蔽的问题。

返回复杂对象,JS 拿不到

建议只返回:

  • string
  • number
  • boolean
  • 简单对象结构

复杂结构容易出现序列化问题。

想做异步怎么办

javaScriptProxy 不适合做异步。

如果需要异步通信,应该:

  • 用 URL scheme
  • 或者 Web 与 ArkTS 消息机制

把这套机制放进真实项目里

在实际项目中,我更推荐这样用:

  • 一个专门的 JsBridge
  • 只放“跨端需要的能力”
  • 控制方法数量
  • 严格维护 methodList

把它当成:

ArkTS 与 H5 的“边界协议”

而不是随手塞逻辑的地方。

总结

javaScriptProxy 本身并不复杂,
复杂的,往往是我们没想清楚:

  • 哪些能力该给 JS
  • 哪些不该给
  • 同步和异步的边界在哪里

一旦你把它当成“对象注入 + 方法白名单”,
这套机制会非常顺手、也非常稳定。

Read more

《回溯 C++98:string 核心机制拆解 —— 从拷贝策略到高效 swap》

《回溯 C++98:string 核心机制拆解 —— 从拷贝策略到高效 swap》

🔥草莓熊Lotso:个人主页 ❄️个人专栏:《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受。 🎬博主简介: 目录 前言: 一. 字符串的拷贝机制:从浅拷贝到写时拷贝 1.1 浅拷贝:隐藏的 “双重释放” 陷阱 1.2 深拷贝:独立内存的安全保障 1.2.1 传统版写法的string类 1.2.2 现代版写法的string类 1.3 写时拷贝(了解就可以):读写分离的优化策略 二、C++98/03 中的三种 swap 实现 2.1 成员函数 swap:

By Ne0inhk
Effective Modern C++ 条款37:使std::thread在所有路径最后都不可结合

Effective Modern C++ 条款37:使std::thread在所有路径最后都不可结合

Effective Modern C++ 条款37:使std::thread在所有路径最后都不可结合 * 引言:线程生命周期的关键问题 * 线程的两种状态:可结合与不可结合 * 可结合(Joinable)状态的特征 * 不可结合(Unjoinable)状态的四种情况 * 为什么可结合性如此重要? * 两种被拒绝的替代方案 * RAII拯救方案:ThreadRAII类 * ThreadRAII实现详解 * 关键设计决策 * 实际应用案例 * 高级讨论:何时选择join或detach * 性能考量与最佳实践 * 结论:让线程管理无忧 BiliBili上对应的视频为:https://www.bilibili.com/video/BV1iZZgBiE9j 引言:线程生命周期的关键问题 在多线程程序设计中,std::thread的管理是一个看似简单实则暗藏玄机的话题。想象一下,你精心设计的并发程序在大多数情况下运行良好,却在某些边缘情况下突然崩溃——这正是许多开发者在使用原生线程时遇到的噩梦场景。本文将深入探讨std::thread对象

By Ne0inhk
【C++】模板的两大特性

【C++】模板的两大特性

文章目录 * 前言 * 1. 关于 typename 的使用场景 * 2. 模板的分离编译问题 * 2.1 简述程序编译链接的过程 * 2.1.1 预处理 * 2.1.2 编译 * 2.1.3汇编 * 2.1.4 链接 * 2.2 模板分离编译为什么会链接报错 * 2.2.1 什么是分离编译 * 2.2.2 模板分离编译存在的问题 * 3. 解决办法 前言 本文探讨了C++模板编程中的两个关键问题。第一部分介绍了typename在模板中的特殊使用场景,指出当模板参数访问内嵌类型时必须使用typename关键字来消除编译器歧义。第二部分分析了模板分离编译导致链接错误的原因,通过对比普通函数和模板函数的编译链接过程,解释了模板定义必须放在头文件中才能被实例化的原理。文章结合代码示例和编译链接过程图解,帮助读者理解模板编译机制和常见错误的解决方法。 1.

By Ne0inhk
RPC魔法揭秘:从原理到BRPC实战,用C++玩转分布式通信

RPC魔法揭秘:从原理到BRPC实战,用C++玩转分布式通信

文章目录 * 本篇摘要 * 一.什么是rpc * 简单理解 * 核心特点 * RPC 工作原理 * 常见 RPC 框架 * 典型使用场景 * 二.BRPC介绍 * 是什么? * 比gRPC强在哪? * 三.基于brpc实现简单的服务调用 * brpc安装教程 * 简单实现客户端向brpc服务端口请求服务完成应答过程(以echo回显为例) * 测试效果 * 代码汇总 * 四.封装每个服务的channels及所有服务管理者 * 五.基于etcd实现服务上下线监控来完成brpc服务调用 * 测试效果 * 代码汇总 * 六.本篇小结 本篇摘要 本文从RPC核心概念出发,阐释其“透明远程调用”的本质与工作原理,对比主流框架后聚焦百度开源的C++高性能RPC框架BRPC,详解其安装、Echo服务示例代码(含客户端/服务端实现),并延伸介绍基于ETCD的服务注册发现与信道管理封装,完整呈现分布式通信方案落地过程。 一.什么是rpc 简单理解 RPC(远程过程调用)就是让程序调用

By Ne0inhk