[electron]自动注册IPC的解决方案

发布于:2025-04-14 ⋅ 阅读:(28) ⋅ 点赞:(0)

前言

主进程和渲染进程通过IPC进行通信,每次需要定义名称并注册,很多代码都是重复书写,并且如果主进程和渲染进程开发人员是同一个的话,很多东西都可以简化。
渲染进程通过ipcRenderer.invoke与主进程通信,主进程通过ipcMain.handle接受渲染进程传递的参数并返回调用结果,二者用一个key进行对应,希望此过程可以简化,省略key的书写,进行自动注册。

主进程

使用electron-vite脚手架创建electron项目,在主进程文件夹中创建ipc文件夹,ipc文件夹中包含一个index文件和一个handlers文件夹,在handlers文件夹中放入所有的处理函数,并用index导出。

| -- main
	| -- ipc
	  | -- handlers
	    | -- xxx1.js
	    | -- xxx2.js
	    | -- index.js
	  | -- index.js
	| -- index.js
| -- preload
	| -- index.js

例如,在xxx1.js中有一个处理函数

// xxx1.js
import process from "node:process"

export const getEnv = ()=>{
  return JSON.stringify(processa.env)
}

在handlers的index文件中导出

import { getEnv } from './xxx1'

export {
    getEnv 
}

在ipc的index中对所有的handler进行自动注册,并注册一个getIpcHandlerForPreload方便在preload中进行调用

import { ipcMain } from 'electron'
import * as handlers from './handlers'

export const registerHandlerForIpcMain = () => {
    for (const key in handlers) {
        const handler = handlers[key];
        ipcMain.handle(key, (_event, ...params) => handler(...params));
    }
    ipcMain.handle("getIpcHandlerForPreload", () => Object.keys(handlers));
};

在主进程的入口index处调用这个函数

import {registerHandlerForMainAndPreload } from "./ipc/index.js";
...
app.whenReady().then(() => {
  registerHandlerForMainAndPreload();
  ...
});

preload

在preload中对渲染进程要使用的invoke进行处理,把接口暴露给渲染进程

import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
import { platform } from 'os';

// Custom APIs for renderer
const api = {
  currentPlatform: platform()
}

// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
// just add to the DOM global.
if (process.contextIsolated) {
  try {
    contextBridge.exposeInMainWorld('electron', electronAPI);
    contextBridge.exposeInMainWorld('api', api);

    (async () => {
      const ipcMainHandlers = await ipcRenderer.invoke('getIpcHandlerForPreload');
      const electronAPIContent = {};
      for (const handlerName of ipcMainHandlers) {
        electronAPIContent[handlerName] = function() { return ipcRenderer.invoke(handlerName, ...arguments); };
      }
      contextBridge.exposeInMainWorld('ipcInvoke', electronAPIContent);
    })();
  } catch (error) {
    console.error(error)
  }
} else {
  // @ts-ignore (define in dts)
  window.electron = electronAPI
  // @ts-ignore (define in dts)
  window.api = api
}

渲染进程

最后,在渲染进程中就可以直接通过preload暴露的接口使用函数了,参数也可以直接传递,不需要第一个参数是event。

// 渲染进程中xxx.js
window.ipcInvoke.getEnv()

问题

本来想在ipc的index中使用动态引入handlers文件夹中的东西,但是打包后路径会报错,找不到handlers文件夹,应该是vite配置问题,目前还没解决,有什么好办法呢?


网站公告

今日签到

点亮在社区的每一天
去签到