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

时间:2017-11-21 15:31:42

标签: electron ipc

我从Electron的主要进程创建了多个窗口,需要在它们之间传递消息。我从rendererA向rendererB发送消息的唯一方法是将它弹回到主进程。有没有办法直接从rendererA发送消息到renderB?

3 个答案:

答案 0 :(得分:8)

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

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

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

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

这是一个quick example of an Electron app就是这样:

<强> main.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>

答案 1 :(得分:2)

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

  1. main->渲染器:webContents.fromId(id).send()在发送方,ipcRenderer.on在接收方
  2. renderer-> main:ipcRenderer.send()在发送方,ipcMain.on在接收方
  3. renderer->渲染器: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');

答案 2 :(得分:1)

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

例如,如果您始终必须将数据从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