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

JS 与 C++ 双向通信实战:基于 WebHostViewListener 的消息处理机制

前言

在现代浏览器和桌面应用开发中,WebView 嵌入已经成为一种非常常见的 UI 技术方案。无论是基于 Chromium 的 CEF(Chromium Embedded Framework)、Qt WebEngine,还是自研浏览器内核,嵌入 WebView 都能带来极高的灵活性与跨平台 UI 开发能力。

不过,当 HTML/JavaScript 需要与 C++ 后端交互时,如何实现 高效、安全、可维护 的双向通信机制,就成了一个必须认真设计的问题。本文将结合 WebHostViewListener 机制,从源码角度深入剖析 HTML/JS 与 C++ 的消息传递、事件处理、数据序列化等关键流程,并对比常见的 JSBridge、JavaScriptCore 等方案,总结优缺点与优化建议。


一、为什么需要 WebView 与 C++ 双向通信

嵌入 WebView 的目的不仅仅是“显示网页”,而是利用 HTML/CSS/JS 的灵活 UI 构建能力,与 C++ 的高性能、底层资源访问能力结合。

典型的交互场景包括:

  1. HTML/JS 调用 C++ 功能

    • 获取本地文件列表

    • 调用系统 API(如打开文件、读取剪贴板)

    • 访问数据库或加解密模块

    • 发送网络请求并处理复杂协议

  2. C++ 回调 HTML/JS

    • 通知前端状态变化(如下载进度、后台任务完成)

    • 推送实时数据(如 WebSocket 消息)

    • 动态修改前端 UI(更新 DOM 或触发 JS 方法)

如果没有合理的通信机制,前后端之间会出现:

  • 数据结构不统一

  • 消息无法安全传输

  • 调用关系混乱、难以调试

WebHostViewListener 正是为了解决这些痛点而设计的一个消息分发与事件监听器。


二、WebHostViewListener 的定位与职责

在一个基于浏览器内核的应用中,WebHostViewListener 通常作为 桥接层(Bridge Layer) 的核心部分,负责监听 WebView(浏览器渲染进程)与 C++ 宿主(浏览器主进程或宿主应用)之间的消息,并进行分发与处理。

其核心职责包括:

  1. 监听 HTML/JS 发出的消息

    • 通过 WebView 内置的消息通道(如 window.externalchrome.sendwindow.postMessage)接收 JSON 数据

    • 解析消息并根据指令类型路由到对应的 C++ 处理逻辑

  2. 将处理结果返回给前端

    • 将 C++ 的执行结果序列化为 JSON

    • 通过 WebView 的 JavaScript 执行接口(如 ExecuteJavaScriptRunJSFunction)回调给 HTML 页面

  3. 保持通信协议一致性

    • 定义统一的消息格式:消息类型、参数、回调 ID

    • 确保版本升级时协议向后兼容


三、消息格式设计

要实现稳定的双向通信,首先需要一个 统一的消息格式。在 WebHostViewListener 中,常见的设计是基于 JSON 的结构化消息,例如:

{ "cmd": "getUserInfo", "params": { "userId": 12345 }, "callbackId": "cb_001" } 

字段解释:

  • cmd:指令名,告诉 C++ 需要执行什么操作

  • params:参数对象,包含该操作需要的输入数据

  • callbackId:回调 ID,前端用它来区分不同请求的返回

返回给前端的消息同样保持结构化,例如:

{ "callbackId": "cb_001", "status": 0, "data": { "name": "Alice", "age": 25 } } 

这样设计的好处是:

  • 协议简单明了

  • 支持异步回调

  • 易于调试与扩展


四、WebHostViewListener 的工作流程

假设我们有这样一个交互场景:

  1. 前端 HTML 通过 JavaScript 发送一个 getUserInfo 请求

  2. C++ 收到消息后查询数据库

  3. 查询结果再通过 WebView 回调给前端

对应的流程图如下:

HTML/JS ----(消息)----> WebHostViewListener(C++) <---(回调)----- 

1. 前端发送消息

前端调用封装的发送方法,例如:

function sendMessage(cmd, params, callback) { const callbackId = "cb_" + Date.now(); window.WebHostView.postMessage(JSON.stringify({ cmd: cmd, params: params, callbackId: callbackId })); callbacks[callbackId] = callback; } sendMessage("getUserInfo", { userId: 12345 }, function(response) { console.log("User Info:", response.data); }); 

2. WebHostViewListener 接收消息

在 C++ 中,WebHostViewListener 会注册一个 消息回调函数

void WebHostViewListener::OnMessageReceived(const std::string& json_message) { auto msg = ParseJson(json_message); std::string cmd = msg["cmd"]; if (cmd == "getUserInfo") { HandleGetUserInfo(msg["params"], msg["callbackId"]); } } 

3. C++ 处理逻辑

void WebHostViewListener::HandleGetUserInfo(const Json::Value& params, const std::string& callbackId) { UserInfo info = database_.GetUser(params["userId"].asInt()); Json::Value result; result["name"] = info.name; result["age"] = info.age; SendCallback(callbackId, 0, result); } 

4. 回调前端

void WebHostViewListener::SendCallback(const std::string& callbackId, int status, const Json::Value& data) { Json::Value msg; msg["callbackId"] = callbackId; msg["status"] = status; msg["data"] = data; std::string json_str = msg.toStyledString(); webview_->ExecuteJavaScript("window.onNativeMessage(" + json_str + ");"); } 

五、与常见 JSBridge 的区别

你提到的 CSDN 文章中介绍的方式,更多是基于 JavaScript 调用绑定函数 的模式,例如:

  • 在 WebView 中注入一个 window.external.callCppMethod() 的接口

  • 或使用 CEF 提供的 ExecuteFunction 注册回调

这种方式的特点:

  • 实现简单,适合调用频率低的功能

  • 消息结构不一定规范,容易出现维护问题

  • 缺少统一的异步回调机制

而 WebHostViewListener 的优势在于:

  • 协议化:统一 JSON 消息格式

  • 可扩展:只需新增 cmd 处理函数即可

  • 异步友好:支持多并发调用,回调不会乱序


六、性能与安全性考虑

在大规模应用中,通信机制需要关注以下几个点:

  1. 消息序列化与反序列化开销

    • 频繁 JSON 解析会有性能损耗

    • 可考虑二进制格式(如 Protobuf)优化

  2. 安全性

    • 严格校验 cmd 是否在允许列表

    • 检查 params 数据类型,防止注入攻击

  3. 线程模型

    • UI 线程接收消息,耗时操作放到后台线程

    • 回调 UI 必须切回主线程


七、实际案例:浏览器插件配置面板

以我在浏览器项目中的一个场景为例:

  • 前端是 HTML/JS 的插件配置界面

  • 需要读取/写入本地配置文件

  • 修改配置后立即生效

采用 WebHostViewListener:

  • 前端发送 "saveConfig" 消息

  • C++ 写入 JSON 配置文件

  • 成功后回调 "status": 0

  • 前端立即刷新界面

这种模式非常清晰,扩展新功能时,只需要新增一个 cmd 分支,不会影响已有功能。


八、总结

WebHostViewListener 提供了一种结构化、可维护、扩展性强的 WebView 与 C++ 双向通信机制,它相较于简单的 JS 调用绑定函数模式,在复杂项目中更具优势。

它的核心思想:

  • 协议化(统一 JSON 格式)

  • 模块化(cmd 分发)

  • 异步化(callbackId 回调)

在浏览器、桌面客户端、混合应用等场景下,都可以直接借鉴这种设计思路。

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

相关文章:

  • Java后端面试题(含Dubbo、MQ、分布式、并发、算法)
  • 分布式与微服务宝典
  • 智能算法流程图在临床工作中的编程视角系统分析
  • 【docker①】在VS Code中使用Docker容器
  • 安全点(Safepoint)完成后唤醒暂停线程的过程
  • 解决uni-app微信小程序编译报错:unexpected character `1`
  • 机器学习实战·第三章 分类(2)
  • EI学术会议 | 虚拟现实、图像和信号处理
  • 股指期货长线还是短线好?
  • AWS Redis Serverless连接完全指南:从安装到实战
  • Notepad++插件开发实战:从入门到精通
  • oss(阿里云)前端直传
  • 使用 Milvus Operator 在 Kubernetes 中部署 Milvus记录
  • LeetCode 刷题【40. 组合总和 II】
  • 3d游戏引擎中ContentTools中的文件模型导入代码1
  • python---list.sort() 和 sorted(list)的区别
  • JVM安全点轮询汇编函数解析
  • 计算机网络---IPv6
  • 第6节 torch.nn.Module
  • 熬夜面膜赛道跑出的新物种
  • Spring Boot初级概念及自动配置原理
  • 【递归、搜索与回溯算法】综合练习
  • 系统分析师-数据库系统-并发控制数据库安全
  • 使用 UDP 套接字实现客户端 - 服务器通信:完整指南
  • HiSmartPerf使用WIFI方式连接Android机显示当前设备0.0.0.0无法ping通!设备和电脑连接同一网络,将设备保持亮屏重新尝试
  • 【android bluetooth 协议分析 05】【蓝牙连接详解3】【app侧该如何知道蓝牙设备的acl状态】
  • 【KO】Android 面试高频词
  • 从内核数据结构的角度理解socket
  • Android Activity 的对话框(Dialog)样式
  • RxJava 在 Android 中的深入解析:使用、原理与最佳实践