在学习 Electron 时,首先需要理解其基本的进程模型,因为 Electron 应用由两个主要的进程组成:主进程(Main Process)和渲染进程(Renderer Process)。每个进程承担不同的职责,而且它们之间的通信方式也决定了应用的架构和安全性。
Electron 是一个跨平台的桌面应用框架,使用 Web 技术(HTML、CSS、JavaScript)来构建用户界面,但它的架构与传统的 Web 应用有所不同。Electron 的应用由两个主要进程组成:
主进程(Main Process):
主进程负责整个应用的生命周期管理,比如创建窗口、处理用户交互、管理文件等。它是 Electron 应用的核心。在主进程中,你可以访问 Node.js 的 API、操作系统资源、创建系统通知等。
渲染进程(Renderer Process):
渲染进程负责呈现和管理用户界面,它通常是运行网页内容的进程(也就是 HTML、CSS、JavaScript)。渲染进程与主进程不同,它不能直接访问 Node.js API,出于安全性考虑,渲染进程的功能被限制。
这两个进程各自独立运行,它们之间通过 IPC(进程间通信) 进行通信。主进程负责创建和管理应用窗口,而渲染进程则负责渲染 UI 和执行应用逻辑。
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#4C9AFF", "edgeLabelBackground":"#ffffff"}}}%%
graph TD
A[Electron 进程模型] --> B[主进程]
A --> C[渲染进程]
B --> D[创建和管理窗口]
B --> E[访问 Node.js 和 Electron API]
C --> F[渲染网页内容]
C --> G[无法直接访问 Node.js 和 Electron API]
B --> H[预加载脚本]
H --> I[在渲染进程加载前执行]
H --> J[通过 contextBridge 暴露安全 API]
H --> K[实现主进程与渲染进程的通信]
H --> L[增强渲染进程功能]
H --> M[确保应用安全性]
由于渲染进程运行的是网页内容,并且可能会加载不可信的第三方内容,因此 Electron 出于安全性考虑,默认情况下不允许渲染进程直接访问 Node.js API 或 Electron 的核心功能。这就意味着,在渲染进程中,开发者不能像在主进程中那样直接使用文件系统、操作系统功能等。
为了让渲染进程能够执行特定的 Node.js 操作,Electron 提供了一种安全的方式——预加载脚本。
预加载脚本(Preload Script)是运行在渲染进程与主进程之间的一种特殊脚本。它的作用是让主进程将某些安全的 Node.js 或 Electron API 暴露给渲染进程,而不直接暴露所有的核心 API,从而保障应用的安全性。
默认情况下,渲染进程无法访问 Node.js 或 Electron API,直接使用 require 或 import 语句会抛出错误。通过预加载脚本,你可以将一些受控且安全的 API 暴露给渲染进程,让渲染进程能够安全地与主进程进行交互,同时避免暴露系统级功能和潜在的安全风险。
预加载脚本通常是一个 JavaScript 文件,里面使用 contextBridge 将某些 API 暴露给渲染进程。contextBridge 确保渲染进程只能访问你允许的功能,而不是整个 Node.js 环境。
Javascript// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
// 通过 ipcRenderer 与主进程通信
sendMessage: (message) => ipcRenderer.send('message', message),
onMessage: (callback) => ipcRenderer.on('message', (event, data) => callback(data)),
});
在上面的代码中,我们使用 contextBridge.exposeInMainWorld 来将 sendMessage 和 onMessage 函数暴露到渲染进程的 window.electron 对象上。这样,渲染进程就可以通过 window.electron.sendMessage 和 window.electron.onMessage 来与主进程进行通信。
在主进程中创建 BrowserWindow 时,指定 preload 选项来加载你的预加载脚本:
Javascript// main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'), // 指定预加载脚本
nodeIntegration: false, // 禁用 nodeIntegration,增加安全性
contextIsolation: true, // 启用上下文隔离,确保渲染进程安全
}
});
win.loadURL('https://your-app-url.com');
}
app.whenReady().then(createWindow);
这样,Electron 会在渲染进程加载前执行 preload.js,并允许渲染进程访问你通过 contextBridge 暴露的 API。
在渲染进程中,你可以通过 window.electron 对象访问预加载脚本暴露的功能:
Javacript// renderer.js window.electron.sendMessage('Hello from renderer'); window.electron.onMessage((data) => { console.log('Received message:', data); });
通过这种方式,渲染进程与主进程之间的通信既保持了安全性,又能够实现功能扩展。
本文作者:chenchuan
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!