Electron相关

生命周期

  • will-finish-launching:应用完成基本启动
  • ready:应用完成初始化时
  • window-all-closed:所有窗口关闭时
  • before-quit:应用准备退出时,可以通过event.preventDefault()取消退出
  • will-quit:当所有窗口都已关闭并且应用将退出
  • quit:应用退出

    Windows上,如果应用由于系统关闭/重新启动或用户注销而关闭,则不会发出此事件。

主进程和渲染进程通信

preload.ts中暴露IPC方法

// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
import { contextBridge, ipcRenderer } from "electron";
import { IPreloadApi } from "../type";
import { EIpcEventType, EIpcMianEventType } from "../interface";

// 定义 API 实现
const api: IPreloadApi = {
  navigate: (url: string) => {
    ipcRenderer.send(EIpcEventType.NAVIGATE_RESPONSE, `已经导航至 ${url}`);
  },
  send: (channel: EIpcEventType, ...arg: any) => {
    ipcRenderer.send(channel, ...(arg || []));
  },
  invoke: (channel: EIpcEventType, ...arg: any) => {
    return ipcRenderer.invoke(channel, ...(arg || []));
  },
  receive: (channel: EIpcMianEventType, func: (...args: any[]) => void) => {
    ipcRenderer.on(
      channel,
      (event: Electron.IpcRendererEvent, ...args: any[]) => func(...args)
    );
  },
};

// 使用 contextBridge 将 API 暴露给渲染进程
contextBridge.exposeInMainWorld("api", api);
  1. 主进程发送消息给渲染进程
// 主进程发送消息
mainWindow.webContents.send(EIpcMianEventType.PRINT, {
    msg: `大小已改变 ${width} - ${height}`,
});


// 渲染进程接受消息
window.api.receive(EIpcMianEventType.PRINT, (e, arg) => {
    console.log("接收到主进程消息:", data);
});
  1. 渲染进程给主进程发送消息
// 单向通信
// 渲染进程使用ipcRenderer.send发送消息
window.api.send(EIpcEventType.RESIZE_WINDOW, 400, 200);

// 主进程使用ipcMain.on接收消息
ipcMain.on(EIpcEventType.RESIZE_WINDOW, (event, width, height) => {
    mainWindow.setSize(width, height);
});

// 接收返回参数
// 渲染进程使用ipcRenderer.invoke发送消息
const result = await window.api.invoke(EIpcEventType.RESIZE_WINDOW, 400, 200);
console.log(result);

// 主进程使用ipcMain.handle接收消息
ipcMain.handle(EIpcEventType.RESIZE_WINDOW, async (event, width, height) => {
    mainWindow.setSize(width, height);
    return {msg:"窗口大小已改变"}
})
  1. 渲染进程之间通信
// 主进程代码
const { BrowserWindow, app, ipcMain, MessageChannelMain } = require('electron')

app.whenReady().then(async () => {
  // Worker 进程是一个隐藏的 BrowserWindow
  // 它具有访问完整的Blink上下文(包括例如 canvas、音频、fetch()等)的权限
  const worker = new BrowserWindow({
    show: false,
    webPreferences: { nodeIntegration: true }
  })
  await worker.loadFile('worker.html')

  // main window 将发送内容给 worker process 同时通过 MessagePort 接收返回值
  const mainWindow = new BrowserWindow({
    webPreferences: { nodeIntegration: true }
  })
  mainWindow.loadFile('app.html')

  // 在这里我们不能使用 ipcMain.handle() , 因为回复需要传输
  // MessagePort.
  // 监听从顶级 frame 发来的消息
  mainWindow.webContents.mainFrame.ipc.on('request-worker-channel', (event) => {
    // 建立新通道  ...
    const { port1, port2 } = new MessageChannelMain()
    // ... 将其中一个端口发送给 Worker ...
    worker.webContents.postMessage('new-client', null, [port1])
    // ... 将另一个端口发送给主窗口
    event.senderFrame.postMessage('provide-worker-channel', null, [port2])
    // 现在主窗口和工作进程可以直接相互通信,无需经过主进程!
  })
})


// preload.ts
const { ipcRenderer } = require('electron')

ipcRenderer.on('port', e => {
  // 接收到端口,使其全局可用。
  window.electronMessagePort = e.ports[0]

  window.electronMessagePort.onmessage = messageEvent => {
    // 处理消息
  }
})


// 通信
window.electronMessagePort.postMessage('ping')

其他的API

  • ipcRenderer.once: 类似于ipcRenderer.on,但只监听一次事件

  • ipcRenderer.sendSync: 类似于ipcRenderer.send,但它时同步的,会阻塞渲染进程,直到接收到回复

  • ipcRenderer.postMessage: 类似于ipcRenderer.on,向主进程发送消息,可选择转移零个或多个MessagePort对象的所有权。

  • ipcRenderer.sendToHost:类似于ipcRenderer.send,但事件将被发送到主页中的<webview>元素而不是主进程。

  • ipcRenderer.sendTo: 类似于ipcRenderer.send,但事件将被发送到指定的其他渲染进程,v28起已弃用。

快捷键

import { BrowserWindow, globalShortcut } from "electron";
import { IStore } from "@/interface";
import { setApplicationMenu } from "./tools";

/** @function 注册快捷键 */
export const globalRegister = (mainWindow: BrowserWindow, store: IStore) => {
  globalShortcut.register("CmdOrCtrl+M", () => {
    setApplicationMenu(mainWindow, store);
  });
};