进程间通信
大约 3 分钟
进程间通信
Electron 的进程间通信(IPC)是框架内主进程(Main Process)与渲染进程(Renderer Process)之间传递数据和消息的核心机制。
主进程与渲染进程之间进行通信,需要使用到两个核心对象,分别是 ipcMain 和 ipcRenderer。
渲染进程 -> 主进程(单向)
渲染进程发送消息到主进程,主进程接收到消息后,打印消息内容
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}`);
});