一、Electron 介绍:
- Electron 是什么?
-
Electron 是由 Github 开发的开源框架(它是由github开发,现在由OpenJS基金会维护的一个开源框架)
-
它允许开发者使用 Web(html、css、js等)技术构建跨平台桌面应用;
-
Electron的核心组成是Chromium、Node.js以及内置的Native API。其中Chromium为Electron提供强大的UI能力,可以在不考虑兼容性的情况下,利用强大的web生态来开发界面;Nodejs让Electron有了底层的操作能力,比如像文件读写,集成c++等,还可以使用大量的npm包来帮助大家完成项目需求;内置的Native API解决了跨平台的问题,首先它提供了同一的原生界面,比如像窗口、托盘等,其次是系统能力,比如像我们的Notification等,最后是应用的基础能力,比如像软件更新,崩溃监控等。
-
- 什么时候用Electron?
-
特定领域:开发者工具、效率工具、实用工具、播放器、社交应用等;
-
前端工程师储备;
-
同时开发web + 桌面端
-
- 学习Electron的好处?
-
造工具,提高开发效率;
-
技术广度
-
- Electron最小组成:
graph TD
Electron --> main.js
Electron --> index.html
Electron --> package.json
main.js为主进程、index.html为渲染进程、package.json为包描述;下面我直接从官网搬一段过来:
// main.js
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
// index.html
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</body>
</html>
// package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"author": "Jane Doe",
"license": "MIT"
}
二、Electron架构原理及环境搭建
-
Electron架构
-
Chromium
Electron它是基于Chromium做的,所以想要了解Electron的话要先了解Chromium架构。Chromium本质是Chrome的开源版,也是一个浏览器,浏览器也是一个桌面应用,它需要去创建窗口、右键菜单、管理浏览器Tab页还有扩展程序等等,而处理这些事情的进程我们称为主进程,也就是下图中的Browser;而对应的每个页面的进程我们称之为渲染进程(Render)。
可以看到我们的浏览器会有一个主进程,多个渲染进程,进程之间是需要通信交互才能运转的,跨进程间的通信通过IPC来进行;我们主进程的RenderProcessHost和渲染进程的RenderProcess就是专门处理IPC事件的。
渲染进程,我们最熟悉的页面就是在RenderView中基于Webkit排版展示出来的,ResourceDispatcher是用来处理我们的资源请求的,当我们的页面需要去请求资源的时候会通过ResourceDispatcher创建一个请求ID然后转发到我们的IPC在我们的主进程中处理,然后返回。
本质上这张图带来的信息主要有三点:1、Chromium是多进程架构,包括Browser和多个Render;2、进程间是需要IPC通信的;3、我们Web关注到的只是很小的一部分。
-
Electron
由于Electron使用了Chromium来展示Web页面,所以Chromium的多进程架构也会被只用到Electron中,在Electron中也分为主进程和渲染进程。
跟Chromium不一样的有两点,第一我们在各个进程里暴露了一些Native API,第二我们引入了Node.js。于是我们在Electron中可以使用Chromium和Node,比如我们可以通过Node去管理窗口,然后在页面中我们可以使用Node库。这其实很不容易的,因为在主线程中同一个时间下,只能运行一个事件循环。
Node.js它的事件循环是基于libuv的,而Chromium是基于messagebump的,这就是Electron原理的重点(如何整合事件循环)。
具体的思路有两种:
- 将Chromium的messagebump用libuv实现一次,比如像NW就是这么做的,Electron其实也曾经尝试过,在渲染进程里面实现会比较简单,但是在主进程里面因为各个系统的GUI实现都不一样。
- Node.js集成到Chromium,Chromium集成到Node.js(用libuv实现messagebump),这也是现在的做法。
-
-
桌面端技术选型
- 为什么要开发桌面端?
- 更快捷的入口
- 离线可用
- 调用系统能力(通知、硬件…),连接打印机等
- 安全需求
- ......
- 各大桌面端技术优缺点:
- Native(C++/C#/Objective-C):
- 高性能
- 原生体验
- 包体积小
- 门槛高
- 迭代速度慢
- QT:
- 基于C++
- 跨平台(Mac、Windows、iOS、Android、Linux、嵌入式)
- 高性能
- 媲美原生的体验
- 门槛高
- 迭代速度一般
- Flutter:
- 跨端(iOS、Android、Mac、Windows、Linux、Web)
- PC 端在发展中(Mac > Linux、Windows)
- 基建少
- NW.j:
- 跨平台(Mac、Windows、Linux),v0.14.7 支持 XP(XP 市场份额约为15%)
- 迭代快,Web 技术构建
- 源码加密、支持 Chrome 扩展
- 不错的社区
- 包体积大
- 性能一般
- Electron:
- 跨平台(Mac、Windows、Linux、不支持 XP)
- Web 技术构建
- 活跃的社区
- 大型应用案例
- 包体积大
- 性能一般 具体对比如下图:
- Native(C++/C#/Objective-C):
- 为什么要开发桌面端?
-
环境搭建
-
编辑器,自己喜欢就好
-
node,建议版本不要太高,可以通过nvm来管理node版本,具体安装参考: juejin.cn/post/695364…
-
Electron安装:
- npm install electron --save-dev
- npm install --arch=ia32 --platform=win32 electron
我们可以指定arch=ia32来安装32位的electron,在window平台打包都应该要基于32位来打,这样打出来的包在32位和64位都可以用。
-
二、与web开发的不同
-
主进程与渲染进程:
- 主进程:
- Electron 运行 package.json 的 main 脚本的进程被称为主进程
- 每个应用只有一个主进程
- 管理原生 GUI,典型的窗口(BrowserWindow、Tray、Dock、Menu)
- 创建渲染进程
- 控制应用生命周期(app)
- 渲染进程:
-
展示 Web 页面的进程称为渲染进程
-
通过 Node.js、Electron 提供的 API 可以跟系统底层打交道
-
一个 Electron 应用可以有多个渲染进程
-
- 主进程:
-
进程间的通信
- 进程间通信的目的
- 通知事件(比如我们在页面中想去创建一个原生菜单,但只有主进程才能够去创建原生菜单,所以只能通过IPC进程通信,去让主进程创建我们的菜单)
- 数据传输(比如我想在某个页面里获得现在的内存情况,这样的话我就需要将这些数据通过IPC来进行传输)
- 共享数据(比如我们的用户信息在各个进程之间都会用到,就需要通过IPC通信来完成数据的共享)
- IPC模块通信
- Electron 提供了 IPC 通信模块,主进程的 ipcMain 和 渲染进程的 ipcRenderer
- ipcMain、ipcRenderer 都是 EventEmitter 对象
- 如何通信
- 从渲染进程到主进程:
-
Callback 写法:ipcRenderer.send、ipcMain.on
// 渲染进程 ipcRenderer.send('my-click', '我点击了hello'); // 主进程 ipcMain.on('my-click', (e, val) => { console.log(val); }) -
Promise 写法(Electron 7.0 之后,处理请求 + 响应模式):ipcRenderer.invoke、ipcMain.handle(我们在渲染进程中发送事件,并且可以得到主进程中的处理结果,类似于发送请求)
// 渲染进程 const { ipcRenderer } = require('electron'); const hNode = document.getElementById('btn'); hNode.onclick = async function() { let res = await ipcRenderer.invoke('my-click', '我是渲染进程的数据'); console.log(res) // 我是渲染进程的数据:我又从主进程过来了 } // 主进程 ipcMain.handle('my-click', async (e, val) => { let res = await new Promise((resolve, reject) => { resolve(val + ':' + '我又从主进程过来了') }) return res; })
-
- 从主进程到渲染进程
-
主进程通知渲染进程:ipcRenderer.on、webContents.send(这里可能有的小伙伴会感到疑惑,为什么不像渲染进程到主进程一样通过send、on呢?这是因为,主进程只有一个而渲染进程有多个,我们到底send给谁呢?因此我们需要找到具体的窗体内容,也就是webContents)
// 主进程 // 等渲染进程加载完毕 win.webContents.send('my-main', '我是主进程过来的'); // 渲染进程 ipcRenderer.on('my-main', (e, val) => { console.log(val); // 我是主进程过来的 })
-
- 页面间(渲染进程与渲染进程间)通信
- 通知事件:通过主进程转发(Electron 5之前,渲染进程发送给主进程,再由主进程转发给另一个渲染进程)、ipcRenderer.sendTo (Electron 5之后)
- 数据共享:Web 技术(localStorage、sessionStorage、indexedDB)、使用 remote(将我们数据挂载到全局,容易影响性能,electron10以后remote弃用,需要自行npm下载)
- 注意事项:
- 少用remote模块,甚至是不用它,很多人会因为它写起来特别简单,会常用它,但是每次remote会触发底层的同步IPC事件,特别影响性能,甚至如果remote处理的不好,会导致进程卡死;
- 不用sync模式,一旦写的不好,会导致整个应用卡;
- 在请求+响应的通信模式下,需要自定义超时限制,当我们的应用响应超时的时候,需要直接response一个异常的超时事件让业务处理,然后去做对应的交互。
- 从渲染进程到主进程:
- 进程间通信的目的
-
Native能力及原生GUI
-
使用 Electron API 创建原生 GUI
- BrowserWindow 应用窗口
- Tray 托盘
- app 设置dock.badge
- Menu 菜单
- dialog 原生弹框
- TouchBar 苹果触控蓝
- ...
-
使用 Electron API 获得底层能力
- clipboard 剪切板
- screen
- globalShortcut 全局快捷键
- desktopCapture 捕获桌面
- shell 打开本地文件、URL
- powerMonitor
- ...
-
使用 Node.js 获得底层能力
- Electron 同时在主进程和渲染进程中对 Node.js 暴露了所有的接口
- fs 进行文件读写
- crypto 进行加解密
- 通过 npm 安装即可引入社区上所有的 Node.js 库
- Electron 同时在主进程和渲染进程中对 Node.js 暴露了所有的接口
-
使用 Node.js 调用原生模块
- node.js add-on
- node-ffi(调用c++等动态库,比如像打印这种模块下)
-
调用 OS 能力
- WinRT(windows runtime)
- Applescript(苹果系统)
- Shell(系统命令)
-
Electron 的能力
-
-
释放前端想象力
- 无兼容问题
- 不用担心在 Safari、IE 上的表现差异了
- 大胆使用 Chrome 浏览器已经支持的 API
- babel 中设置 targets 为 Electron 对应的 Chrome 版本
- 最新浏览器 Feature
- 纯天然 LazyLoad(mathiasbynens.be/demo/img-lo…
- ES 6/7/8/9/10高级语法
- Async await / Promise
- String/Array/Object 等高级用法
- BigInt
- 无跨域问题
- 使用 Node.js 发送请求
- 使用 Electron net 发送请求
- More
- 操作本地文件
- 更好用的本地 DB
- 多线程、多进程并行
- 无兼容问题
文章内容非原创,只为学习记录,如有侵权,联系删除。