Chrome 浏览器前端与客户端双向通信实战

Chrome 前端(即页面 JS / Web UI)与客户端(C++ 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改造浏览器底层的开发者。


🔧 典型交互场景分类

场景 描述 技术路径
1️⃣ WebUI 页面与 C++ 后端交互 如设置页、扩展页等 WebUI <-> WebUIMessageHandler
2️⃣ 页面 JS 与 Extension 后端 如插件调用 chrome.runtime.sendMessage JS <-> Mojo / native extension API
3️⃣ 页面 JS 与 Native 功能交互 如调用浏览器硬件能力 JS <-> Mojo / C++ Impl

📍 框架组件总览图


1️⃣ WebUI 页面交互机制详解

▶ 构成组件

  • 前端:WebUI HTML + JS 页面,嵌入在 chrome:// 或 browser://

  • 后端:继承自 content::WebUIController + WebUIMessageHandler

▶ 流程详解

  1. 前端 JS 发起调用:

    cpp 复制代码
    chrome.send("MyFunctionName", [arg1, arg2]);
  2. 后端 C++ 注册 handler:

    cpp 复制代码
    void MyHandler::RegisterMessages() override {
      web_ui()->RegisterMessageCallback(
          "MyFunctionName",
          base::BindRepeating(&MyHandler::OnMyFunction, base::Unretained(this)));
    }
    
    void MyHandler::OnMyFunction(const base::Value::List& args) {
      // 处理参数,回调 JS
      FireWebUIListener("on-data-ready", data);
    }
  3. 后端回调前端:

    cpp 复制代码
    cr.addWebUIListener("on-data-ready", (data) => { ... });

▶ 应用场景

  • 设置页 (chrome://settings)

  • 下载页、扩展页、历史页等


2️⃣ Extension 与 Native 通信机制

▶ 构成组件

  • JS:使用 chrome.runtime.sendMessage 或 chrome.extension.getBackgroundPage()

  • 后端:继承 ExtensionFunction 并注册到 ExtensionFunctionRegistry

▶ 流程示意

cpp 复制代码
chrome.runtime.sendMessage({cmd: "doSomething"}, function(response) {
  console.log("Response:", response);
});

// C++ Extension Function 实现
class DoSomethingFunction : public ExtensionFunction {
 public:
  ResponseAction Run() override {
    // 处理逻辑...
    return RespondNow(OneArgument(base::Value("OK")));
  }
};

// 注册宏
EXTENSION_FUNCTION_NAME("extensionInternal.doSomething")

✅ Chrome 扩展调用的是基于 IPC 和 Mojo 的通道,最终由浏览器进程分发请求到对应 ExtensionFunction。


3️⃣ Mojo 通信机制(JS <-> Mojo <-> C++)

适用于较底层的交互,如性能数据、打印、系统 API 等。

▶ 构成组件

  • 前端:JS Binding(*.mojom-webui.js)

  • 后端:C++ Mojo Impl(绑定接口实现)

  • 通道:RenderFrameHost->GetRemoteInterfaces() or WebUIDataSourceWithMojo

▶ 示例流程

cpp 复制代码
// JS 侧
mojo.bindInterface('my_namespace.MyInterface');
myInterface.doSomething().then((result) => { ... });

// mojom 定义
interface MyInterface {
  DoSomething() => (string result);
}

// C++ 实现并绑定
class MyInterfaceImpl : public mojom::MyInterface {
 public:
  void DoSomething(DoSomethingCallback callback) override {
    std::move(callback).Run("Done!");
  }
};

web_ui()->BindInterface(std::make_unique<MyInterfaceImpl>());

🔄 JS 与 C++ 通信方式对比总结

通信方式 特点 适用场景
chrome.send() 简单、基于 WebUI Message 内部页面(如 chrome://*)
chrome.runtime.sendMessage() 基于扩展 IPC,功能强大 插件调用浏览器能力
Mojo 模块化、高性能、支持多进程 深层系统通信(如 Debug、音频)
相关推荐
weixin_307779131 小时前
C++代码实现MATLAB中的dlarray函数功能
开发语言·c++·算法·matlab
Frank_refuel5 小时前
C++11之一场名为“搬家”的 C++ 之旅
开发语言·c++
hetao17338376 小时前
2026-10-03~04 hetao1733837 的刷题记录
c++·算法
福兮说7 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
longlongzihan7 小时前
从LeetCode 70. 爬楼梯看动态规划:如何精准推导状态转移方程?
c++·算法·leetcode·动态规划
郑州光合科技余经理8 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
小呆呆6668 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
Dovis(誓平步青云)8 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan9 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_10 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线