上层 JS 与底层 C++ 通信
🗒️

上层 JS 与底层 C++ 通信

Created by
ZhaohaoZhaohao
Tags
Chromium
Published
Published 2024-08-09 00:00
Last edited time
Last updated 2024-08-09 08:13
参考文档
前情提要:“WebUI” is a term used to loosely describe parts of Chrome's UI implemented with web technologies (i.e. HTML, CSS, JavaScript).

💡 方法1. Mojo - 推荐

JS发送消息给C++

  1. <C++> 定义Mojo接口:在.mojom文件中定义一个通用的通信接口。
    1. Copy c++
      // example.mojom module example.mojom; interface Service { // 从JS到C++的消息。 DoSomething(string data); }
  1. <C++> 生成绑定代码:使用Mojo构建工具自动生成C++和TypeScript的绑定代码。
  1. <C++> 实现接口:在C++端实现Mojo接口定义的方法。
    1. Copy c++
      // example_service_impl.h class ExampleServiceImpl : public example::mojom::Service { void DoSomething(const std::string& data) override { // 处理从JS发送的数据。 std::cout << "Received data from JS: " << data << std::endl; } };
  1. <JS> 使用Mojo接口:在JS端,通过生成的TypeScript绑定代码使用Mojo接口。
    1. Copy typescript
      // example.ts // 创建Mojo接口的远程对象。 const serviceRemote = new example.mojom.ServiceRemote(); const serviceReceiver = new example.mojom.ServiceReceiver( serviceRemote.$.bindNewPipeAndPassReceiver() ); // 使用Mojo接口发送消息。 serviceRemote.doSomething("Hello from JS!");

JS接收C++发来的消息

  1. <C++> 触发接口调用:在C++端,当需要向JS发送消息时,调用Mojo接口的相应方法。
    1. Copy c++
      // example_service_impl.cc void NotifyJS(const std::string& message) { // 通过Mojo接口发送消息给JS。 service_->DoSomething(message); }
  1. <JS> 监听接口事件:JS端通过Mojo接口的异步事件监听器接收消息。
    1. Copy typescript
      // example.ts // 设置异步回调。 serviceRemote.doSomethingCallback = (response) => { // 响应从C++接收到的数据。 console.log(`Response from C++: ${response}`); };
  1. <JS> 使用TypeScript Promises:对于需要响应的操作,使用Promise来简化异步通信。
    1. Copy typescript
      // example.ts function sendRequest(data: string): Promise<string> { return new Promise((resolve, reject) => { // 设置一次性的回调。 const onceCallback = (response) => { serviceRemote.doSomethingCallback = null; resolve(response); }; // 发送请求并设置回调。 serviceRemote.doSomething(data, onceCallback); }); } sendRequest("Request from JS").then((response) => { alert(response); });
  1. <C++> 响应Promise:C++端在完成异步操作后,使用Mojo的回调机制来响应JS的Promise。
    1. Copy c++
      // example_service_impl.cc void DoSomething(const std::string& data, const DoSomethingCallback& callback) override { // 模拟异步操作。 std::thread([=]() { // 假设这里是一些异步操作。 std::this_thread::sleep_for(std::chrono::seconds(1)); // 响应JS的请求。 callback("Response from C++"); }).detach(); }
 

💡 方法2. WebUIMessageHandler + chrome.send()

JS发送消息给C++

  1. <JS> 使用chrome.send()函数: 在JS代码中,当需要向C++发送消息时,可以使用chrome.send()函数。这个函数接受两个参数:消息的名称和一个参数列表。
    1. Copy javascript
      // 在JS中,调用chrome.send()发送消息到C++。 chrome.send('messageName', [arg1, arg2, ...]);
  1. <C++> 创建WebUIMessageHandler: 在C++端,WebUIMessageHandler类用于处理从JS发送过来的消息。我们需要创建一个WebUIMessageHandler的子类,并重写RegisterMessages()方法来注册可以处理的消息和对应的回调函数。
    1. Copy c++
      class MyWebUIMessageHandler : public WebUIMessageHandler { public: void RegisterMessages() override { web_ui()->RegisterMessageCallback("messageName", base::BindRepeating(&MyWebUIMessageHandler::HandleMessageName, base::Unretained(this))); } private: void HandleMessageName(const base::Value::List& args) { // 处理接收到的参数。 } };
  1. <C++> 在WebUIController中注册消息处理器: 创建WebUIMessageHandler的实例,并在WebUIController的实现中注册该处理器。
    1. Copy c++
      class MyWebUIController : public WebUIController { public: explicit MyWebUIController(content::WebUI* web_ui) : WebUIController(web_ui), message_handler_(new MyWebUIMessageHandler()) { message_handler_->RegisterMessages(); } private: std::unique_ptr<MyWebUIMessageHandler> message_handler_; };

JS接收C++发来的消息

  • 方法1
      1. <C++> 调用CallJavascriptFunction(): 当C++需要在JS中执行一个函数时,可以使用CallJavascriptFunction()。这个方法允许C++端调用JS中定义的全局函数。
        1. Copy c++
          // 在C++中,通过CallJavascriptFunction()调用JS中的函数。 CallJavascriptFunction("functionNameInJS", base::Value("argument"));
      1. <JS> 定义相应的函数: 在JS代码中,需要定义C++可能会调用的函数。
        1. Copy javascript
          // 在JS中定义一个函数,C++可能会调用这个函数。 function functionNameInJS(argument) { // 根据参数执行相应的操作。 }
  • 方法2
      1. <C++> 使用FireWebUIListener(): C++端还可以使用FireWebUIListener()来触发在JS端注册的事件监听器。
        1. Copy c++
          // 在C++中触发一个事件监听器。 void MyWebUIMessageHandler::TriggerEvent() { FireWebUIListener("eventName", base::Value("eventData")); }
      1. <JS> 监听事件: JS可以使用addWebUiListener()来监听由C++触发的事件。
        1. Copy javascript
          // 在JS中监听一个事件。 addWebUiListener('eventName', function(eventData) { // 响应事件和数据。 });
 

Comments