0%

Electron主进程与渲染进程的通信

最近写了一个Vue+Electron实现的Markdown编辑器:Direct5dom/vue-markdown

得益于Vue的低门槛,Web部分的开发很容易就完成了,但是到Electron部分时遭遇了难题。

我想使用Electron原生的导航栏来实现打开文件、保存文件等功能,而导航栏的相关配置位于主进程,在主进程无法调用渲染进程的方法、函数,因此需要完成主进程与渲染进程的通信。

用到的相关模块

  • ipcMain - 事件发射器。在主进程中使用时,它可以处理从渲染进程发送的异步和同步消息。从渲染进程发出的消息将被发射到这个模块。
  • ipcRenderer - 事件发射器。它提供了一些方法,它可以从渲染进程向主进程发送同步和异步的消息。也可以接收来自主进程的回复。
  • webContents - 事件发射器。它负责渲染和控制一个网页,是BrowserWindow对象的一个属性。它提供了一个.send可以从主进程发送消息到渲染进程。

用法举例

渲染进程主动向主进程发送消息

最简单的异步通信

我们在HTML中设置好按钮:

1
<button id="btn">发送通知</button>

在渲染进程 (renderer.js) 中设置发送器.send

1
2
3
4
5
6
const { ipcRenderer } = require("electron");
const oBtn = document.getElementById("btn");

oBtn.onclick = function() {
ipcRenderer.send("sendMessage","this is render");
}

在主进程 (main.js) 中设置监听器.on

1
2
3
4
5
const { ipcMain } = require("electron");

ipcMain.on("sendMessage",(event,data) => {
console.log(data);
})

执行结果:

1
2
# 主进程控制台
this is render

主进程在收到消息后回复渲染进程

在渲染进程 (renderer.js) 中设置发送器.send和监听器.on

1
2
3
4
5
6
7
8
9
10
11
const { ipcRenderer } = require("electron");
const oBtn = document.getElementById("btn");


oBtn.onclick = function() {
ipcRenderer.send("sendMessage","this is renderer");
}

ipcRenderer.on("sendMain",(event,data) => {
console.log(data);
})

在主进程 (main.js) 中设置监听器.on,并设置.sendevent

1
2
3
4
5
6
const { ipcMain } = require("electron");

ipcMain.on("sendMessage",(event,data) => {
console.log(data);
event.sender.send("sendMain","this is a main")
})

执行结果:

1
2
3
4
# 主进程控制台
this is render
# 渲染进程控制台
this is a main

同步通信

在渲染进程 (renderer.js) 中设置同步发送器.sendSync

1
2
3
4
5
6
7
const { ipcRenderer } = require("electron");
const oBtn = document.getElementById("btn");

oBtn.onclick = function() {
let res = ipcRenderer.sendSync("sendMessage","this is renderer");
console.log(res)
}

在主进程 (main.js) 中设置监听器.on,并设置.returnValueevent

1
2
3
4
5
6
const { ipcMain } = require("electron");

ipcMain.on("sendMessage",(event,data) => {
console.log(data);
event.returnValue = "this is main"
})

执行结果:

1
2
3
4
# 主进程控制台
this is render
# 渲染进程控制台
this is a main

主进程主动向渲染进程发送消息

上面的方法都是从渲染进程主动发送消息到主进程的方法。你可能会下意识的类比ipcRenderer.send使用ipcMain.send,然而ipcMain并没有提供这个方法,详见:ipcMain | Electron (electronjs.org)

而要完成这个需求,我们需要用到另一个事件发射器——webContents。他是BrowserWindow的一个属性。

一个简单的案例:

主进程 (main.js) 创建BrowserWindow,并设置webContents.send

1
2
3
4
5
const mainWindow = new BrowserWindow({
// ...
});

mainWindow.webContents.send("sendMain","this is main");

在渲染进程 (renderer.js) 中设置监听器.on

1
2
3
ipcRenderer.on("openFilePath", (event, data) => {
console.log(data);
});

执行结果:

1
2
# 渲染进程控制台
this is a main

参考资料

electron中渲染进程与主进程间的通信 - 知乎 (zhihu.com)