Electron - IPC 解决主进程和渲染进程之间的通信

Electron 的主进程是一个 Node.js 环境,因此 主进程可以使用 Node.js 的内置模块以及相关 Node.js 环境的 npm 安装包,主进程拥有对操作系统的完全访问权限。 但是渲染器进程默认运行在网页端而不是运行 Node.js, 为了将 Electron 的不同进程类型桥接在一起,我们需要使用一个称为 preload 的特殊脚本
注意的是:从 Electron 20 开始,preload 脚本默认被沙箱化,并且不再能够访问完整的 Node.js 环境。这意味着您只能访问一组有限的 API, 代码参考: github.com/kejuqu/elec...

BrowserWindow's preload 脚本运行在既有能访问 HTML DOM 又有部分 Node.js 和 Electron 子集功能, 详细的区别:

可用的 API 详细
Electron modules 渲染器进程模块
Node.js modules events, timers, url
Polyfilled globals Buffer, process, clearImmediate, setImmediate

Preload 脚本在渲染器页面加载前被注入,如果要为渲染器添加需要特权访问的功能可以通过contextBridge API 来定义 全局对象

暴露 node.js 模块的信息到页面(renderer 进程)

contextBridge.exposeInMainWorld 在主进程和渲染进程之间建立一个安全的 "通道",将主进程指定的 API/变量/函数暴露到渲染进程的 全局对象(window) 对象上,供前端直接调用。 将 process.versions 的 node, chrome, electron 暴露到 renderer 进程

js 复制代码
// 新建 src/preloads/versions.js
import { contextBridge } from "electron";

// contextBridge.exposeInMainWorld(key,value)

// 通过 contextBridge.exposeInMainWorld 向 window 对象暴露一个名为 versions 的对象
contextBridge.exposeInMainWorld("versions", {
  node: () => process.versions.node,
  chrome: () => process.versions.chrome,
  electron: () => process.versions.electron,
  // we can also expose variables, not just functions,
  value: "any",
  ping: () => "pong",
});

为了将 preload 脚本和 renderer 进程,需要在要暴露的 page 创建时,及在创建 BrowserWindow的构造函数指定 webPreferences.preload 的路径

js 复制代码
// main.js
const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    // 添加在这里
    webPreferences: {
      preload: path.resolve(__dirname, "src", "preloads", "versions.js"),
    },
  });

  win.loadFile("index.html");
};

// 然后在 index.html 中新增
<body>
    <h1>Hello from Electron renderer!</h1>
    <p>👋</p>
    <!-- display windows.versions info -->
    <p id="versions"></p>
    <!-- Import the renderer code here -->
    <script src="./src/renderers/versions.js"></script>
</body>


// src/renderers/versions.js
const versionNode = document.getElementById("versions-content");

// 在 renderer 里可以使用 dom 和其他 web 相关技术
console.log("window.versions: ", window.versions);

versionNode.innerText = `Node.js version: ${window.versions.node()}, Electron version: ${window.versions.electron()}, Chrome version: ${window.versions.chrome()}, ping: ${
  window.versions.ping
}`;

进程间的通信

为了解决主进程不能访问 DOM, web page(渲染进程)不能访问 Node.js API 的问题,Electron 的 ipcMainipcRenderer 模块实现了, 利用 ipcRenderer.invoke(channel: string, ...args: any[]): Promise<any> 可以从 web page 向 主进程发送消息,然后在主进程通过 ipcMain.handle(channel: string, listener: (event: IpcMainInvokeEvent, ...args: any[]) => (Promise<any>) | (any)): void;(handle 或者 ipcMain 下边的对应方法)来处理 ipcRenderer 发送过来的channel

js 复制代码
// src/preloads/versions.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('versions', {
  node: () => process.versions.node,
  chrome: () => process.versions.chrome,
  electron: () => process.versions.electron,
  ping: () => ipcRenderer.invoke('ping')
  // we can also expose variables, not just functions
})

// main.js
app.whenReady().then(() => {
  createWindow();

  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
  
  // 主要添加这个 处理
  ipcMain.handle("ping", async () => {
    return "pong";
  });
});

注意

不要通过 contextBridge.exposeInMainWorld 将 ipcRenderer 这个模块都给暴露到 global 上,因为这样可能会造成 web page 可以发送任意的 IPC 消息给主进程,造成恶意攻击的危害

相关推荐
我命由我123457 分钟前
VSCode - Prettier 配置格式化的单行长度
开发语言·前端·ide·vscode·前端框架·编辑器·学习方法
HashTang8 分钟前
【AI 编程实战】第 4 篇:一次完美 vs 五轮对话 - UnoCSS 配置的正确姿势
前端·uni-app·ai编程
JIngJaneIL16 分钟前
基于java + vue校园快递物流管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js
asdfg125896333 分钟前
JS中的闭包应用
开发语言·前端·javascript
kirk_wang34 分钟前
Flutter 导航锁踩坑实录:从断言失败到类型转换异常
前端·javascript·flutter
静小谢1 小时前
前后台一起部署,vite配置笔记base\build
前端·javascript·笔记
用户47949283569152 小时前
改了CSS刷新没反应-你可能不懂HTTP缓存
前端·javascript·面试
还好还好不是吗2 小时前
老项目改造 vue-cli 2.6 升级 rsbuild 提升开发效率300% upupup!!!
前端·性能优化
sumAll2 小时前
别再手动对齐矩形了!这个开源神器让 AI 帮你画架构图 (Next-AI-Draw-IO 体验)
前端·人工智能·next.js