进程间通信
在Electron应用中,进程间通信(IPC)是Web渲染进程与主进程通信的关键机制,主要通过ipcMain和ipcRenderer模块实现。这两个模块分别在主进程和渲染进程中使用,允许这两个进程之间建立通信通道,以便进行数据和消息的交换。
主进程接收与响应消息
在主进程中/electron/main/index.ts
,我们通过监听渲染进程发来的消息,并响应它们来实现通信:
ts
function createWindow() {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.mjs'),
},
});
if (NODE_ENV === 'development') {
mainWindow.loadURL('http://localhost:5173/');
// 打开开发工具
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadFile(path.join(__dirname, '../../dist/index.html'));
}
// 监听渲染进程发送的消息
ipcMain.on('message-to-main', (_event, args) => {
console.log(args); // 打印从渲染进程接收到的消息
// 回应渲染进程
mainWindow.webContents.send('message-from-main', 'Hello from Main Process', 123123);
});
}
启用渲染进程中的Node API
通过设置webPreferences中的nodeIntegration,我们可以控制渲染进程中Node.js API的可用性。
配置nodeIntegration
ts
function createWindow() {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.mjs'),
nodeIntegration: true,
contextIsolation: false,
},
});
if (NODE_ENV === 'development') {
mainWindow.loadURL('http://localhost:5173/');
// 打开开发工具
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadFile(path.join(__dirname, '../../dist/index.html'));
}
// 监听渲染进程发送的消息
ipcMain.on('message-to-main', (_event, args) => {
console.log(args); // 打印从渲染进程接收到的消息
// 回应渲染进程
mainWindow.webContents.send('message-from-main', 'Hello from Main Process', 123123);
});
}
在Web环境中调用IPC通信
Web环境中可以通过两种方式与主进程进行IPC通信
- @vueuse/electron
- ipcRenderer:通过electron引入ipcRenderer进行IPC通信
使用@vueuse/electron进行通信
vue
<script setup lang="ts">
import { useIpcRenderer } from '@vueuse/electron';
const ipcRenderer = useIpcRenderer();
ipcRenderer.send('message-to-main', 'Hello from Renderer Process');
ipcRenderer.on('message-from-main', (_event, message: string) => {
console.log('[Electron message]: ', message);
});
</script>
直接使用 ipcRenderer
在 build/vite/plugin/electron
添加如下代码
ts
export function configElectronPlugin(isDevelopment: boolean, isProduction: boolean): PluginOption {
if (!isDevelopment) {
return electron({
main: {
entry: 'electron/main/index.ts',
vite: {
build: {
sourcemap: !isProduction,
minify: isProduction,
outDir: 'dist_electron/config',
rollupOptions: {
output: {
entryFileNames: 'main.js',
},
},
},
},
},
preload: {
input: 'electron/preload/index.ts',
vite: {
build: {
sourcemap: !isProduction,
minify: isProduction,
outDir: 'dist_electron/config',
rollupOptions: {
output: {
entryFileNames: 'preload.mjs',
},
},
},
},
},
renderer: {},
});
} else {
return [];
}
}
vue
<script setup lang="ts">
import { ipcRenderer } from 'electron';
ipcRenderer.send('message-to-main', 'Hello from Renderer Process');
ipcRenderer.on('message-from-main', (_event, message: string) => {
console.log('[Electron message]: ', message);
});
</script>
使用contextBridge暴露Node API给Web环境
contextBridge用于在预加载脚本中安全地向渲染进程暴露API,同时保持上下文隔离。
在预加载脚本中暴露API
electron/preload/index.ts
:tsimport { ipcRenderer, contextBridge } from 'electron'; import type { ExposeInMainWorldApi } from '#/electron'; const exposeInMainWorldApi: ExposeInMainWorldApi = { sendMessageToMain: (message) => ipcRenderer.send('message-to-main', message), onMessageFromMain: (callback) => ipcRenderer.on('message-from-main', callback), }; contextBridge.exposeInMainWorld('electronAPI', exposeInMainWorldApi);
添加 typescript 类型
/types/electron.d.ts
tsimport { IpcRenderer,IpcRendererEvent } from 'electron' export interface ExposeInMainWorldApi { sendMessageToMain: (value: string) => void onMessageFromMain: (callback: IpcRendererListener<[string]>) => IpcRenderer } declare type IpcRendererListener<T extends any[] = any[]> = (event: IpcRendererEvent, ...args: T) => void
在渲染进程中使用暴露的API
ts// 向主进程发送消息 window.electronAPI.sendMessageToMain('Hello from Renderer Process'); // 接收注册发送的消息 window.electronAPI.onMessageFromMain((_event, message) => { console.log('[Electron message]: ', message); });