Electron学习

个人看法是利用主要利用前端技术快速开发跨平台应用程序.趁现在发展还不错(至少比WinForm,WPF,Qt开发更年轻),至于移动端,除了原生之外还有Flutter和React Native等技术.

知识点

流程模型

Electron是多进程的,因为单进程意味着一个网站的崩溃或无响应会影响到整个浏览器.

Electron 应用程序的结构非常相似。 作为应用开发者,你将控制两种类型的进程:主进程渲染器进程。 这类似于上文所述的 Chrome 的浏览器和渲染器进程。

主进程

每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力

窗口管理

主进程的主要目的是使用 BrowserWindow 模块创建和管理应用程序窗口。

BrowserWindow 类的每个实例创建一个应用程序窗口,且在单独的渲染器进程中加载一个网页。 从主进程用 window 的 webContent 对象与网页内容进行交互。

由于 BrowserWindow 模块是一个 EventEmitter, 所以您也可以为各种用户事件 ( 例如,最小化 或 最大化您的窗口 ) 添加处理程序。

当一个 BrowserWindow 实例被销毁时,与其相应的渲染器进程也会被终止

下面介绍一下EventEmitter类

Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。

Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。

1
2
3
4
5
6
7
8
9
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件触发');
});
setTimeout(function() {
event.emit('some_event');
}, 1000);

应用程序生命周期

主进程还能通过 Electron 的 app 模块来控制您应用程序的生命周期。 该模块提供了一整套的事件和方法,可以让您用来添加自定义的应用程序行为 (例如:以编程方式退出您的应用程序、修改应用程序坞,或显示一个关于面板)

原生 API

为了使 Electron 的功能不仅仅限于对网页内容的封装,主进程也添加了自定义的 API 来与用户的作业系统进行交互。 Electron 有着多种控制原生桌面功能的模块,例如菜单、对话框以及托盘图标。

预加载脚本

预加载脚本实践中通常用来为无法访问Node.js和Electron的渲染进程提供API,会在渲染进程之前执行程序.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// See the Electron documentation for details on how to use preload scripts:
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
const { contextBridge, ipcRenderer } = require("electron/renderer")
contextBridge.exposeInMainWorld("myApi",{
send: (channel,data) => {
let validChannels = ["toMain"]
if(validChannels.includes(channel)){
ipcRenderer.send(channel,data)
}
},
receive: (channel,func) => {
let validChannels = ["fromMain"]
if(validChannels.includes(channel)){
ipcRenderer.on(channel,(event,...args) => func(...args))
}
},
setTitle:(title)=>{
ipcRenderer.send("set-title",title)
},
openFile:()=>ipcRenderer.invoke("dialog:openFile"),
})

Electron中的MessagePorts

MessagePorts是一个允许在不同上下文之间传递消息的web功能。这就像window.postMessage,但在不同的channel上。

在渲染进程中,MessagePort类的行为与它在web上的行为完全相同。不过,主进程不是网页——它没有Blink集成——因此它没有MessagePort或MessageChannel类。为了在主进程中处理和交互MessagePorts,Electron添加了两个新类:MessagePortMainMessageChannelMain。这些类的行为与渲染器中的类似类类似。

MessagePort对象可以在渲染器或主进程中创建,并使用ipcRenderer.postMessage和WebContents.postMessage方法来回传递。请注意,通常的IPC方法(如send和invoke)不能用于传输MessagePorts,只有postMessage方法可以传输MessagePort

通过主进程传递MessagePorts,您可以连接两个可能无法通信的页面(例如,由于同源限制)。

Electron为MessagePort添加了一个web上没有的功能,以使MessagePort更有用。这就是关闭事件,当通道的另一端关闭时会发出该事件。端口也可以通过垃圾收集来隐式关闭。在渲染器中,您可以通过分配给port.onclose或调用port.addEventListener(’close’,…)来侦听关闭事件。在主进程中,您也可以通过调用port.on(’close’,……)来监听关闭事件

Process Sandboxing

Chromium中的一个关键安全特性是进程可以在沙盒中执行。沙盒通过限制对大多数系统资源的访问来限制恶意代码可能造成的危害——沙盒进程只能自由使用CPU周期和内存。为了执行需要额外特权的操作,沙盒进程使用专用通信通道将任务委派给更有特权的进程。

Electron中的沙盒进程的行为方式与Chromium的大致相同,但Electron还有一些额外的概念需要考虑,因为它与Node.js接口。

Renderer processes

当Electron中的渲染器进程被沙盒化时,它们的行为与常规Chrome渲染器的行为相同。沙盒渲染器不会初始化Node.js环境。因此,当启用沙箱时,渲染器进程只能通过进程间通信(IPC)将这些任务委派给主进程来执行特权任务(如与文件系统交互、对系统进行更改或生成子进程)。

Preload scripts

为了允许渲染器进程与主进程通信,附加到沙盒渲染器的预加载脚本仍将有Node.js API的多填充子集可用。暴露了类似于Node的require模块的require函数,但只能导入Electron和Node内置模块的子集:

  • electron (following renderer process modules: contextBridge, crashReporter, ipcRenderer, nativeImage, webFrame)
  • events
  • timers
  • url

node: imports are supported as well:

此外,预加载脚本还将某些Node.js基元聚合填充为全局:

由于require函数是一个功能有限的polyfill,因此您将无法使用CommonJS模块将预加载脚本分离为多个文件。如果您需要拆分预加载代码,请使用打包器,如webpack或Parcel。请注意,因为提供给预加载脚本的环境比沙盒渲染器的环境具有更高的特权,所以除非启用了contextIsolation,否则仍有可能将特权API泄露给渲染器进程中运行的不受信任的代码。

-------------本文结束感谢您的阅读-------------
感谢阅读.

欢迎关注我的其它发布渠道