Electron进程间通信(例:获取本机Mac地址)&& electron-store的使用

858 阅读2分钟

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);