当前位置: 首页 > news >正文

[特殊字符] Vue3 + WebView 双端通信桥:用 TypeScript 构建高可维护的 JSBridge 与 JSSDK

在移动端 WebView 场景中(例如 iOS 的 WKWebView、Android 的 WebView),
前端页面(Web)原生容器(Native) 之间需要频繁通信:

  • Web 请求位置信息、蓝牙状态;

  • Native 主动推送系统事件、设备权限变更;

  • 双方需要统一协议、可靠回调和强类型约束。

本文带你构建一个完整的 TypeScript + Promise 化 + 双端兼容 的 JSBridge,
让你的 H5 页面拥有原生 App 级的通信能力。


🧩 一、核心设计思路

我们拆分为两层:

层级说明
JSBridge与原生交互的底层通信封装(注册、触发、回调)
JSSDK对上层业务提供类型化、Promise 化的接口封装

架构图如下:

[Web业务层] ⇄ [JSSDK接口层] ⇄ [JSBridge通信层] ⇄ [Native]

⚙️ 二、JSBridge 优化实现

// bridge.ts
interface BridgeMessage<T = any> {eventName: stringparams?: T
}type BridgeHandler<T = any> = (params: T) => voidinterface BridgeResponse<T = any> {success: booleandata?: Tmessage?: string
}// ===== 定义事件映射 =====
export interface BridgeEventMap {getLocation: { type: 'wgs84' | 'gcj02' }openBluetoothAdapter: voidstartBeaconDiscovery: { uuids: string[] }getBeacons: voidstopBeaconDiscovery: voidcloseBluetoothAdapter: voiddevicePermissionChanged: { location: boolean; bluetooth: boolean }logout: { redirectUrl: string }getMotionDate: { yaw: string }getSafeTop: voidgetUserInfo: void
}export type BridgeEventName = keyof BridgeEventMapclass JSBridge {private bridge: any | null = nullprivate eventHandlers = new Map<string, Set<BridgeHandler>>()public readonly ready: Promise<void>constructor() {this.ready = new Promise((resolve) => {this.setup((bridge) => {this.bridge = bridge// 注册全局事件接收器bridge.registerHandler?.('globalHandler', (msg: BridgeMessage) => {const handlers = this.eventHandlers.get(msg.eventName)if (handlers) handlers.forEach(fn => fn(msg.params))})resolve()})})}/** 初始化 iOS / Android 桥接环境 */private setup(callback: (bridge: any) => void): void {// iOSif (window.WKWebViewJavascriptBridge) return callback(window.WKWebViewJavascriptBridge)if (window.WKWVJBCallbacks) return window.WKWVJBCallbacks.push(callback)window.WKWVJBCallbacks = [callback]window.webkit?.messageHandlers?.iOS_Native_InjectJavascript?.postMessage(null)// Androidif (window.WebViewJavascriptBridge) return callback(window.WebViewJavascriptBridge)if (window.WVJBCallbacks) return window.WVJBCallbacks.push(callback)window.WVJBCallbacks = [callback]document.addEventListener('WebViewJavascriptBridgeReady', () => {callback(window.WebViewJavascriptBridge)})}/** ✅ Web 调用原生方法(Promise 异步) */async invoke<K extends BridgeEventName, R = BridgeResponse<BridgeEventMap[K]>>(eventName: K,params?: BridgeEventMap[K],): Promise<R> {await this.readyif (!this.bridge) throw new Error('Bridge 未初始化')return new Promise((resolve, reject) => {const msg: BridgeMessage = { eventName, params }try {this.bridge.callHandler('globalHandler', msg, (response: BridgeResponse) => {if (response?.success) resolve(response.data as R)else reject(new Error(response?.message || `Bridge 调用失败: ${eventName}`))})} catch (err) {reject(err)}})}/** ✅ 原生调用 Web 事件(支持多订阅) */on<K extends BridgeEventName>(eventName: K, handler: BridgeHandler<BridgeEventMap[K]>) {if (!this.eventHandlers.has(eventName))this.eventHandlers.set(eventName, new Set())this.eventHandlers.get(eventName)!.add(handler)}/** ✅ 一次性监听 */once<K extends BridgeEventName>(eventName: K, handler: BridgeHandler<BridgeEventMap[K]>) {const wrapper = (params: BridgeEventMap[K]) => {handler(params)this.off(eventName, wrapper)}this.on(eventName, wrapper)}/** ✅ 取消监听 */off<K extends BridgeEventName>(eventName: K, handler: BridgeHandler<BridgeEventMap[K]>) {this.eventHandlers.get(eventName)?.delete(handler)}
}const bridge = new JSBridge()
export default bridge

📦 三、JSSDK 封装层

我们为每个原生能力封装 Promise 化的接口:

// jssdk.ts
import bridge, { type BridgeEventMap } from '@/utils/bridge'class JSSDK {private ready: Promise<void>constructor() {this.ready = bridge.ready}/** 获取定位信息 */async getLocation(params: BridgeEventMap['getLocation']) {await this.readyreturn bridge.invoke('getLocation', params)}/** 获取用户信息 */async getUserInfo() {await this.readyreturn bridge.invoke('getUserInfo')}/** 监听设备权限变更 */onPermissionChanged(handler: (state: BridgeEventMap['devicePermissionChanged']) => void) {bridge.on('devicePermissionChanged', handler)}
}export const jsSDK = new JSSDK()

🚀 四、实际使用

在你的 Vue 组件中:

<script setup lang="ts">
import { jsSDK } from '@/utils/jssdk'onMounted(async () => {const location = await jsSDK.getLocation({ type: 'wgs84' })console.log('当前位置:', location)jsSDK.onPermissionChanged(({ location, bluetooth }) => {console.log('设备权限变化:', { location, bluetooth })})
})
</script>

🧠 五、优化亮点总结

优化点说明
强类型映射通过 BridgeEventMap 保证调用与回调参数类型一致
Promise 化接口异步调用结构更清晰,易用性更强
iOS/Android 自动检测自动区分 WebView 环境初始化
多订阅 + 一次性事件同时支持 on / once 监听
安全防护调用前 await bridge.ready,防止未初始化调用
单例模式保证全局唯一的通信实例,避免重复注册

🧭 六、适用场景

  • iOS / Android WebView 双端混合开发;

  • 小程序 WebView 嵌入网页;

  • Cordova / Capacitor / Flutter Web 容器通信;

  • H5 与原生系统能力(定位、蓝牙、设备信息等)交互。


🪄 结语

这套桥接方案结合了 TypeScript 类型安全 + Promise 异步接口 + Vue3 生命周期管理
能够在保持灵活性的同时,确保跨端通信的稳定与可维护性。

让 H5 页面与原生交互,变得如同调用普通 API 一样简单优雅 👇

await jsSDK.getLocation({ type: 'gcj02' })

📚 如果你正开发一款需要与原生端交互的 Web 应用,
不妨尝试封装自己的 JSBridge —— 一劳永逸地解决前端与原生通信的复杂性!

http://www.dtcms.com/a/580986.html

相关文章:

  • 自然科学笔记-微积分
  • iOS 上架要求全解析,App Store 审核标准、开发者准备事项与开心上架(Appuploader)跨平台免 Mac 实战指南
  • iOS app语言切换
  • Search-o1:增强大型推理模型的主动搜索能力
  • 个人笔记|IP分片不用TTL
  • 百汇游戏网站开发商南通网站推广公司
  • 【Linux】权限(2):文件权限的深入理解粘滞位
  • 做网站公司如何选百度广告联盟推广链接
  • BIM+GIS协同:RVT文件转3DTiles的技术路径与场景落地
  • 中颖AFE芯片:SH367303、SH367306 和 SH367309
  • 数据结构—排序算法篇三
  • 从“医疗大模型”向“医疗智能体”架构与路径分析(白皮书草案-上)
  • LeetCode算法日记 - Day 95: 回文子串
  • DockerCompose与多容器编排
  • AngularJS与SQL的集成使用指南
  • 【ZeroRange WebRTC】TWCC 在 WebRTC 中的角色与工作原理(深入指南)
  • 数据结构常见的八大排序算法
  • 个人怎么做网站app推广引流方法
  • 初识光伏逆变器
  • 一文了解LLM应用架构:从Prompt到Multi-Agent
  • MongoDB 内存管理避坑指南:解决高占用、页错误等核心问题,让数据库性能翻倍
  • 关于DNS中毒攻击的解决方案分享
  • 【C++】数据挖掘算法在软件测试中的应用
  • WebSocket 完全指南:从原理到实战,搭建实时通信桥梁
  • STM32项目分享:智能水产养殖系统
  • 网站开发线框个体营业执照网上年报
  • iPhone苹果手机拍的照片默认是heic如何换成jpg格式
  • 基于微信小程序的旅游攻略分享互动平台设计与实现-项目分享
  • Neo4j Windows桌面版安装及更改默认数据存储位置
  • 智能安防新篇章:EasyGBS助力重塑物业视频管理服务