在 Electron 中的两个渲染器进程之间直接通信

Posted

技术标签:

【中文标题】在 Electron 中的两个渲染器进程之间直接通信【英文标题】:Communicate directly between two renderer processes in Electron 【发布时间】:2018-05-05 03:14:43 【问题描述】:

我从 Electron 的主进程创建了多个窗口,并且需要在它们之间传递消息。我遇到的将消息从 rendererA 发送到 rendererB 的唯一方法是将其反弹到主进程。有什么办法可以直接从renderA发送消息给renderB?

【问题讨论】:

我不知道 Electron 的 IPC 功能。 【参考方案1】:

在某种程度上,主进程必须参与其中,但两个窗口的渲染器进程之间的通信可以通过某种直接的方式实现:

在主进程中,将窗口引用定义为全局对象的属性;

在每个渲染器进程中,通过remote.getGlobal()访问你要发送消息的窗口的引用,然后使用send()方法;

在每个渲染器进程中使用ipcRenderer.on()通常的方式接收消息。

这是一个quick example of an Electron app,它就是这样做的:

ma​​in.js

const  app, BrowserWindow  = require ('electron');
global.window1 = null;
global.window2 = null;
function onAppReady ()

    window1 = new BrowserWindow ( width: 600, height: 500 );
    window1.loadURL (`file://$__dirname/index1.html`);
    window1.webContents.openDevTools ();
    window1.on ('closed', () =>  window1 = null; );
    //
    window2 = new BrowserWindow ( width: 500, height: 600 );
    window2.loadURL (`file://$__dirname/index2.html`);
    window2.webContents.openDevTools ();
    window2.on ('closed', () =>  window2 = null; );

app.on ('ready', onAppReady);
app.on ('window-all-closed', () =>  app.quit (); );

index1.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Window 1</title>
  </head>
  <body>
    <h1>Window 1</h1>
    <button type="button" class="send-message">Send Message to Window 2</button>
    <script>
        const  remote, ipcRenderer  = require ('electron');
        //
        let button = document.querySelector ('.send-message');
        button.addEventListener ('click', () =>
        
            let window2 = remote.getGlobal ('window2');
            if (window2) window2.webContents.send ('message', "Message from Window 1");
        );
        //
        ipcRenderer.on ('message', (event, message) =>  console.log (message); );
    </script>
  </body>
</html>

index2.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Window 2</title>
  </head>
  <body>
    <h1>Window 2</h1>
    <button type="button" class="send-message">Send Message to Window 1</button>
    <script>
        const  remote, ipcRenderer  = require ('electron');
        //
        let button = document.querySelector ('.send-message');
        button.addEventListener ('click', () =>
        
            let window1 = remote.getGlobal ('window1');
            if (window1) window1.webContents.send ('message', "Message from Window 2");
        );
        //
        ipcRenderer.on ('message', (event, message) =>  console.log (message); );
    </script>
  </body>
</html>

【讨论】:

我刚刚在我的电子应用程序中测试了您的“直接消息流”代码,其中包含一个主窗口和一个隐藏的工作渲染器进程窗口,工作人员向主窗口发送大量消息。它工作得很好,但比以前慢了(~5 倍)。在我将所有消息发送到主进程之前,主进程将它们分派到主渲染器窗口。我想这与let window2 = remote.getGlobal ('window2'); 有关【参考方案2】:

基本上,在电子中,进程之间的通信有三种形式:

    main -> 渲染器:webContents.fromId(id).send() 在发送方,ipcRenderer.on 在接收方 renderer -> main: ipcRenderer.send() 在发送方,ipcMain.on 在接收方 渲染器 -> 渲染器:ipcRenderer.sendTo() 在发送方,ipcRenderer.on 在接收方

所以在渲染器到渲染器的场景中,发送者必须知道目的地的 webContents.id,然后通过ipcRenderer.sendTo() 调用它到/从它


我已经做了一个电子ipc框架electron-ipcfy,它统一了上面所有三个场景中的ipc调用。

import  ipcfy  from "electron-ipcfy";

interface TestService 
    greet(name: string);


const testService = ipcfy<TestService>('test');

if (process.type == 'browser') 
    // Attach implementation
    testService.__attachImpl(
        new class implements TestService 
            greet(name: string) 
                console.log(`Hello, $name!`);
            
        );


// Then you can call it in any process
testService.greet('world');

【讨论】:

sendTo 仍会经过主进程吗?【参考方案3】:

这取决于你的通信系统的逻辑。

例如,如果您总是要从 BrowserWindow2 向 BrowserWindow4 发送数据,您可以在 BrowserWindow4 中声明 ipcMain,在 BrowserWindow2 中声明 ipcRenderer

如果您必须从所有 BrowserWindows 向所有其他浏览器发送消息,我建议您使用主进程并将消息发送到 BrowserWindows(使用亲属 ID

在您的消息接收者中:

ipcMain.on('asynchronous-message', (event, arg) => 
   //manage data

在您的消息发件人中:

ipcRenderer.send('asynchronous-message', message)

ipcMain doc

ipcRenderer doc

【讨论】:

在 BrowserWindow4 中声明 ipcMain 是什么意思?能具体点吗? 我添加了一些信息,请问您是否需要澄清:)

以上是关于在 Electron 中的两个渲染器进程之间直接通信的主要内容,如果未能解决你的问题,请参考以下文章

Electron - 解决渲染器进程中的电子模块问题

使用electron进行原生应用的打包---主进程与渲染进程之间的通信

electron渲染进程与主进程通信

Electron 主进程和渲染进程

Electron - 限制从主进程到渲染进程的消息流

Electron 主进程和渲染进程