main/preload.js
(在预加载脚本中,通过contextBridge将要使用的node API暴露给全局 window对象。进而在渲染进程中使用这些node API)
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
ipcRenderer: {
...ipcRenderer,
on: function (channel, func) {
ipcRenderer.on(channel, (event, ...args) => {
func(...args);
});
},
},
store: {
get(val) {
return ipcRenderer.sendSync('electron-store-get', val);
},
set(property, val) {
ipcRenderer.send('electron-store-set', property, val);
},
// Other method you want to add like has(), reset(), etc.
},
});
Electron进程间通信
一、渲染进程 —> 主进程(单向)
在渲染进程(页面.js)中调用主进程的API:
1、在主进程中,使用ipcMain.on监听事件
主进程的控制台,在vscode的终端里(或者命令行工具)
main/main.ts
import { app, ipcMain } from 'electron';
ipcMain.on('app.quit', () => {
console.log('quit')
app.quit()
});
2、在preload.js中,通过contextBridge将API在window全局中公开
3、在渲染进程中,使用ipcRenderer.send('eventName',...)调用API
render.js
function unLogin() {
setModalShow(false);
window.electron.ipcRenderer.send('app.quit');
}
二、渲染进程 <—> 主进程(双向)
在渲染进程中调用主进程的模块,并等待返回结果
方法一:使用ipcRenderer.sendSync
render.js
let [macAdress] = useState(
window.electron.ipcRenderer.sendSync('getMacAdress')
);
main/main.ts
import { ipcMain } from 'electron';
import { getMacAdress } from './getMacAdress'
ipcMain.on('getMacAdress', (event) => {
//返回 Mac地址
event.returnValue = getMacAdress();
});
main/getMacAdress.ts
import { networkInterfaces } from 'os';
const zeroRegex = /(?:[0]{1,2}[:-]){5}[0]{1,2}/;
//获得 Mac地址
export function getMacAdress() {
const list = networkInterfaces();
for (const [_key, parts] of Object.entries(list)) {
if (!parts) continue;
for (const part of parts) {
if (zeroRegex.test(part.mac) === false) {
return part.mac;
}
}
}
return '';
}
三、主进程 —> 渲染进程(单向)
main/main.ts
let mainWindow: BrowserWindow | null = null;
const createWindow = async () => {
mainWindow = new BrowserWindow({
...
});
//创建窗口后就直接发送了数据,速度很快,此时页面还没有加载出来(渲染进程中的监听事件还未执行,所以控制台没有打印信息)
//解决:加个定时器延迟发送
setTimeout(() => {
mainWindow?.webContents.send('send-Message', '创建窗口后,主进程主动发数据给渲染进程');
},4000)
};
render.js
window.electron.ipcRenderer.on('send-Message',(_evt,arg) => {
console.log(arg) //'创建窗口后,主进程主动发数据给渲染进程'
})
四、渲染进程 —> 渲染进程
没有直接的方法。
方法一:
将主进程作为渲染器之间的消息代理: 将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。
renderA.tsx
let user = '...params...';
//ipcRenderer.send() 1.在渲染进程发送
window.electron.ipcRenderer.send('userLogin', user);
main/main.ts
import { ipcMain } from 'electron';
let mainWindow: BrowserWindow | null = null;
//webContents.send() 3.在主进程发送
function onLoginRequest(loginData: any) {
mainWindow?.webContents.send('userLogin', loginData);
}
//2.在主进程接收参数
ipcMain.on('userLogin', (_evt, user) => {
onLoginRequest(user);
});
renderB.tsx
import { useHistory } from 'react-router-dom';
//ipcRenderer.on() 4.在另一个渲染进程接收后使用
window.electron.ipcRenderer.on('userLogin', function userLogin(user) {
// 当有新用户进来时 要强制返回到首页并更新用户信息
history.push({pathname: '/',state:{newUser:true,idcard:user.idcard,name:user.name}})
});
方法二:
从主进程将一个 MessagePort 传递到两个渲染器。这将允许在初始设置后渲染器之间直接进行通信。
electron-store的使用
1. main/store.js
const Store = require('electron-store');
const store = new Store();
module.exports = store
2. main/main.ts
import { ipcMain } from 'electron';
import store from './sotre';
ipcMain.on('electron-store-get', async (event, val) => {
event.returnValue = store.get(val);
});
ipcMain.on('electron-store-set', async (_event, key, val) => {
store.set(key, val);
});
3. main/preload.js
4. render.js
let [authCode, setAuthcode] = useState(
(window.electron.store.get(`authCode_${macAdress}`) as string) || ''
);
window.electron.store.set(`authCode_${macAdress}`, authCode);