本文介绍了使用electron开发时候和消息传递相关的知识,包括主进程和渲染进程之间的通信,以及Web页面和主进程之间的通信。
1. ipcMain.on监听的是什么消息
ipcMain.on用于在Electron主进程(ipcMain)中监听从渲染进程(ipcRenderer)发送的消息。它是一个事件监听器,可以注册特定的事件名称,并在收到对应事件时触发回调函数;例如:
js
const { ipcMain } = require('electron');
// 监听来自渲染进程的消息
ipcMain.on('message', (event, arg) => {
console.log(arg); // 打印接收到的消息
});
2. 如何在ipcRenderer(渲染进程)中向ipcMain发送消息
在渲染进程
js
const { ipcRenderer } = require('electron');
// 发送消息给主进程
ipcRenderer.send('message', 'Hello from renderer process!');
// 监听来自主进程的回复消息
ipcRenderer.on('reply', (event, arg) => {
console.log(arg); // 打印收到的回复消息
});
3. 如何在ipcMain中向ipcRenderer发送消息
3.1 在ipcMain中通过win.webContents对象向此win对象对应的ipcRender发送消息,例如
js
const { ipcMain, BrowserWindow } = require('electron');
// 创建窗口对象
let win = new BrowserWindow();
// 监听来自渲染进程的消息
ipcMain.on('messageToMain', (event, arg) => {
console.log(arg); // 打印接收到的消息
// 向特定窗口的渲染进程发送消息
win.webContents.send('messageFromMain', 'Hello from main process!');
});
3.2 ipcMain收到消息之后回复发送消息的ipcRenderer
利用消息传递过程中,回调函数第一个参数,即事件对象event上的reply对象属性进行消息传递(准确来说是消息传递),例如:
js
// 监听来自渲染进程的消息
ipcMain.on('message', (event, arg) => {
console.log(arg); // 打印接收到的消息
// 发送回复消息给渲染进程
event.reply('reply', 'Hello from main process!');
});
4. ipcRender上与消息通知相关的方法
下面是七个使用ipcRenderer进行消息通知的示例,包括ipcMain和ipcRenderer两侧的代码:
4.1. ipcRenderer.send(channel, ...args)
: 主进程(ipcMain)代码:
javascript
const { ipcMain } = require('electron');
ipcMain.on('messageToMain', (event, arg) => {
console.log(arg); // 打印接收到的消息
});
// 渲染进程发送消息到主进程
ipcRenderer.send('messageToMain', 'Hello from renderer process!');
渲染进程(ipcRenderer)代码:
javascript
const { ipcRenderer } = require('electron');
// 向主进程发送异步消息
ipcRenderer.send('messageToMain', 'Hello from renderer process!');
4.2. ipcRenderer.sendSync(channel, ...args)
: 区别在于ipcRenderer.sendSync是有返回值的,而ipcRenderer.send没有;这个区别很好的体现出了同步通信和异步通信的区别。
主进程(ipcMain)代码:
javascript
const { ipcMain } = require('electron');
ipcMain.on('messageToMainSync', (event, arg) => {
console.log(arg); // 打印接收到的消息
// 向渲染进程返回同步消息
event.returnValue = 'Hello back from main process!';
});
// 渲染进程发送同步消息到主进程
const result = ipcRenderer.sendSync('messageToMainSync', 'Hello from renderer process!');
console.log(result); // 打印接收到的返回结果
渲染进程(ipcRenderer)代码:
javascript
const { ipcRenderer } = require('electron');
// 向主进程发送同步消息
const result = ipcRenderer.sendSync('messageToMainSync', 'Hello from renderer process!');
console.log(result); // 打印接收到的返回结果
4.3. ipcRenderer.invoke(channel, ...args)
:
- 需要注意的是ipcRenderer.invoke和icpMain.handle搭配使用,和上面的ipcRenderer.send搭配ipcMain.on是不同的。
- icpMain.handle的返回值是一个Promise对象,此对象包裹的数据正是ipcRenderer.invoke.then的接受数据。
主进程(ipcMain)代码:
javascript
const { ipcMain } = require('electron');
ipcMain.handle('messageInvoke', async (event, arg) => {
console.log(arg); // 打印接收到的消息
// 模拟处理过程,返回Promise结果
return new Promise((resolve) => {
setTimeout(() => {
resolve('Hello back from main process!');
}, 1000);
});
});
// 渲染进程发送异步消息到主进程,并等待返回结果
ipcRenderer.invoke('messageInvoke', 'Hello from renderer process!')
.then((result) => {
console.log(result); // 打印接收到的返回结果
});
渲染进程(ipcRenderer)代码:
javascript
const { ipcRenderer } = require('electron');
// 向主进程发送异步消息,并等待返回结果
ipcRenderer.invoke('messageInvoke', 'Hello from renderer process!')
.then((result) => {
console.log(result); // 打印接收到的返回结果
});
4.4. ipcRenderer.on(channel, listener)
: 正如前文所说:ipcRenderer.on和ipcRenderer.send或者win.webContents.send搭配使用。 主进程(ipcMain)代码:
javascript
const { ipcMain } = require('electron');
ipcMain.on('messageToMain', (event, arg) => {
console.log(arg); // 打印接收到的消息
// 向渲染进程发送回复消息
event.reply('messageFromMain', 'Hello back from main process!');
});
渲染进程(ipcRenderer)代码:
javascript
const { ipcRenderer } = require('electron');
// 监听来自主进程的消息
ipcRenderer.on('messageFromMain', (event, arg) => {
console.log(arg); // 打印接收到的消息
});
// 向主进程发送消息
ipcRenderer.send('messageToMain', 'Hello from renderer process!');
4.5. ipcRenderer.once(channel, listener)
: 主进程和渲染进程示例与示例4。4中的代码相同。唯一不同之处是使用ipcRenderer.once
替代ipcRenderer.on
,以确保监听器仅触发一次。
4.6. ipcRenderer.removeListener(channel, listener)
: 主进程和渲染进程示例与示例4中的代码相同。在需要移除特定监听器时,使用ipcRenderer.removeListener
方法。
4.7. ipcRenderer.removeAllListeners([channel])
: 移除所有或指定channel的监听器。
5. Web页面和主进程之间的通信
Web页面和主进程之间的通信的本质是ipcRenderer和ipcMain之间进行通信,本质上就是4中的7种方法;不同之处在于:
- 在Electron中,为了确保Web页面与主进程之间的通信安全,需要使用contextBridge模块来限制对Electron API的访问。contextBridge提供了exposeInMainWorld方法,用于在渲染进程中暴露特定的API给主进程,以便进行双向通信。
- 通过exposeInMainWorld,可以将自定义的API对象或函数注入到渲染进程的全局作用域中,使其可以直接在页面中访问,并与主进程进行通信。
javascript
const { contextBridge, ipcRenderer } = require('electron');
//
contextBridge.exposeInMainWorld('electronAPI', {
// web页面获取渲染进程中的相关信息
isPrimaryScreen: () => true,
// web页面操作主进程方法
exitApp: () => void ipcRenderer.send('closeMainWindow'),
// web页面向主进程传递数据
updateFocusWindow: index => void ipcRenderer.send('update-focus-window', index),
// web页面将消息的回调函数注册到ipcRender中
handleClearLocalStorage: callback => void ipcRenderer.on('clear-localStorage', callback),
// web页面向主进程获取进程数据
getLocalIP: () => ipcRenderer.invoke('get-local-ip'),
});
使用:
js
console.log(window?.electronAPI.getLocalIP().then(data => data));