跳至主要內容

进程间通信

望间代码Electron大约 3 分钟

进程间通信

Electron 的进程间通信(IPC)是框架内主进程(Main Process)与渲染进程(Renderer Process)之间传递数据和消息的核心机制。

主进程与渲染进程之间进行通信,需要使用到两个核心对象,分别是 ipcMainopen in new windowipcRendereropen in new window

渲染进程 -> 主进程(单向)

渲染进程发送消息到主进程,主进程接收到消息后,打印消息内容
ipcRenderer.on -> ipcMain.on

Main Process

const { ipcMain } = require("electron");

// 主进程监听
ipcMain.on("rendererToMain", async (event, arg) => {
  console.log(arg);
});

Renderer Process

const { ipcRenderer } = require("electron");

// 渲染进程发消息到主进程
ipcRenderer.send("rendererToMain", "hello");

渲染进程 <-> 主进程(双向)

渲染进程发送消息到主进程,主进程接收到消息后,返回结果

ipcRenderer.invoke + ipcMain.handle

Main Process

const { ipcMain } = require("electron");

// 主进程监听并放回结果
ipcMain.handle("rendererToMainReply", async (event, arg) => {
  console.log(arg);
  return "reply";
});

Renderer Process

const { ipcRenderer } = require("electron");

// 渲染进程发送消息并等待放回结果
const result = await ipcRenderer.invoke("rendererToMainReply", "hello");

ipcRenderer.send + ipcMain.on

Main Process

const { ipcMain } = require("electron");

// 主进程监听
ipcMain.on("rendererToMain", (event, arg) => {
  console.log(arg);
  // 作用如何 'send', 但是放回结果到发送方
  event.reply("mainToRenderer", "reply");
});

Renderer Process

const { ipcRenderer } = require("electron");

// 渲染进程发送消息并等待放回结果
ipcRenderer.send("rendererToMain", "hello");

ipcRenderer.on("mainToRenderer", (event, arg) => {
  console.log(arg);
});

ipcRenderer.sendSync + ipcMain.on

渲染进程发送消息到主进程,并同步等待响应结果
同步意味着它会阻塞渲染进程,直到主进程返回结果

Main Process

const { ipcMain } = require("electron");

// 主进程监听
ipcMain.on("rendererToMainReply", (event, arg) => {
  console.log(arg);
  event.returnValue = "reply";
});

Renderer Process

const { ipcRenderer } = require("electron");

const result = ipcRenderer.sendSync("rendererToMainReply", "hello");

主进程 -> 渲染进程

webContents.send

主进程使用 BrowserWindow.webContents.send 向渲染进程发送消息

Main Process

const { BrowserWindow } = require("electron");

const mainWindow = new BrowserWindow();
mainWindow.webContents.send("mainToRenderer", "hello");

Renderer Process

const { ipcRenderer } = require("electron");

ipcRenderer.on("mainToRenderer", (event, arg) => {
  console.log(arg);
});

event.sender.send

ipcMain.on 监听到消息后,使用 event.sender.send 向渲染进程发送消息

Main Process

const { ipcMain } = require("electron");

ipcMain.on("rendererToMain", (event, arg) => {
  event.sender.send("mainToRenderer", "hello");
});

Renderer Process

const { ipcRenderer } = require("electron");

ipcRenderer.send("rendererToMain", "hello");

ipcRenderer.on("mainToRenderer", (event, arg) => {
  console.log(arg);
});

渲染进程 -> 渲染进程

将主进程作为中转,渲染进程向主进程发送消息,主进程将消息转发给其他渲染进程

Main Process

const { ipcMain, BrowserWindow } = require("electron");

const mainWindow = new BrowserWindow();

ipcMain.on("rendererToRenderer", (event, arg) => {
  mainWindow.webContents.send("rendererToRenderer", arg);
});

Renderer Process A

const { ipcRenderer } = require("electron");

ipcRenderer.send("rendererToRenderer", "hello");

Renderer Process B

const { ipcRenderer } = require("electron");

ipcRenderer.on("rendererToRenderer", (event, arg) => {
  console.log(arg);
});

使用 contextBridge 安全通信

preload.js

const { contextBridge, ipcRenderer } = require("electron");

// 定义允许渲染进程访问的API
contextBridge.exposeInMainWorld("electronAPI", {
  // 发送消息到主进程
  send: (channel, data) => {
    // 白名单验证channel名称
    const validChannels = ["toMain"];
    if (validChannels.includes(channel)) {
      ipcRenderer.send(channel, data);
    }
  },
  // 从主进程接收消息
  receive: (channel, callback) => {
    // 白名单验证channel名称
    const validChannels = ["fromMain"];
    if (validChannels.includes(channel)) {
      // Deliberately strip event as it includes `sender`
      ipcRenderer.on(channel, (event, ...args) => callback(...args));
    }
  },
});

Main Process

const { app, BrowserWindow } = require("electron");
const path = require("path");

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      // 使用预加载脚本
      preload: path.join(__dirname, "preload.js"),
      // 为安全起见,建议开启contextIsolation
      contextIsolation: true,
      nodeIntegration: false, // 禁用node集成,使用contextBridge更安全
    },
  });

  // 监听来自渲染进程的消息
  ipcMain.on("toMain", (event, arg) => {
    // 回复渲染进程
    event.sender.send("mainToRenderer", "Hello from Main!");
  });
}

app.whenReady().then(createWindow);

Renderer Process

const { ipcRenderer } = require("electron");

window.electronAPI.send("toMain", "Hello from Renderer!");

// 设置接收主进程消息的回调
window.electronAPI.receive("fromMain", (data) => {
  console.log(`Received from Main: ${data}`);
});
上次编辑于:
贡献者: ViewRoom