Communicate directly between two renderer processes in Electron

冷暖自知 提交于 2019-12-02 01:03:42

问题


I create multiple windows from Electron's main process and need to pass messages between them. The only way I have come across to send messages from rendererA to rendererB is by bouncing it to main process. Is there any way to directly send a message from rendererA to renderB?


回答1:


In a way or another, the main process has to get involved, but communicating between the renderer processes of two windows can be achieved in some kind of straightforward way:

  • In the main process, define the window references as properties of the global object;

  • In each renderer process, access the reference of the window you want to send a message to by using remote.getGlobal (), then use the send () method;

  • Use ipcRenderer.on () the usual way to receive the message in each renderer process.

Here is a quick example of an Electron app which does just that:

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>



回答2:


Basicly, in electron, communications between process has three forms:

  1. main -> renderer: webContents.fromId(id).send() on sender side, ipcRenderer.on on receiver side
  2. renderer -> main: ipcRenderer.send() on sender side, ipcMain.on on receiver side
  3. renderer -> renderer: ipcRenderer.sendTo() on sender side, ipcRenderer.on on receiver side

So in renderer to renderer scenario, sender must know the destination's webContents.id, then call it to/from via ipcRenderer.sendTo()


I've made a electron ipc framework, electron-ipcfy, which unifies ipc calls in all three scenario above.

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');



回答3:


It depends from the logic of your communication system.

For example, if you always have to send data from BrowserWindow2 to BrowserWindow4, you can declare the ipcMain in the BrowserWindow4 and ipcRenderer in the BrowserWindow2.

In case you have to send from all the BrowserWindows to all the others, I advice you to use Main process and dispatch message to the BrowserWindows (using the relatives ID)

In your message receiver:

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

And in your message sender:

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

ipcMain doc

ipcRenderer doc



来源:https://stackoverflow.com/questions/47416799/communicate-directly-between-two-renderer-processes-in-electron

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!