0%

极客时间 Electron 课程学习笔记

Electron 基础

image-20210321163931126

主进程

  • Electron 运行 package.json 的 main 脚本的进程被称为主进程
  • 每个应用只有一个主进程
  • 管理原生 GUI,典型的窗口(BrowserWindow,Tray,Dock,Menu)
  • 创建渲染进程
  • 控制应用生命周期

渲染进程

  • 展示 Web 页面的进程被称为渲染进程
  • 通过 Node.js Electron 提供的 API 可以跟系统底层打交道
  • 一个 Electron 应用可以有多个渲染进程

IPC 模块通信

  • Electron 提供了 IPC 通信模块,主进程的 ipcMain 和 渲染进程的 ipcRenderer
  • ipcMain,ipcRenderer 都是 EventEmitter 对象

渲染进程到主进程

  • ipcRenderer.send 和 ipcMain.on
  • ipcRenderer.invoke 和 ipcMain.handle,它们和上面的区别是 handle 可以返回一个结果给渲染进程。

从主进程到渲染进程

  • ipcRenderer.on
  • webContents.send

页面间(渲染进程与渲染进程间)通信

  • 通知事件
    • ipcRenderer.sendTo
  • 数据共享
    • Web 技术(localStorage,sessionStorage,indexedDB)
    • 使用 remote(不推荐)

Electron 优缺点

  • 性能较差,包体积大
  • 跨平台,使用前端技术构建,没有浏览器的兼容问题,支持 ES6/7 和浏览器最新 Feature ,比如纯天然的 lazyLoad
  • 使用Node.js 或 Electron net 模块发送请求不存在 web 的跨域问题

Electron 工程

Electron 打包

electron-builder 安装&使用

1
2
3
4
5
6
7
8
9
10
11
12
npm install --global --production windows-build-tools (用管理员启动 cmd 安装,Windows 必备)
npm i electron-builder --save-dev
npm i cross-env --save-dev

cross-env npm_config_electron_mirror="https://npm.taobao.org/mirrors/electron/"  electron-builder build --mac
cross-env npm_config_electron_mirror="https://npm.taobao.org/mirrors/electron/"  electron-builder build --win --ia32

npm remove electron-rebuild

//package.json加入"postinstall": "electron-builder install-app-deps",重新编译原生模块

npm install electron-builder-squirrel-windows --save-dev

打包配置

  • 在 package.json 加入 build 属性
  • 存放在electron-builder.yml

配置项

image-20210323104325396

详情见文档

Electron 更新

官方自动更新模块

基于 Squirrel 框架完成的自动更新

Electron-updater

Electron 官方 Updater 的改版,由 electron-builder 提出

优点

  • 接入简单
  • Windows 支持签名验证
  • 支持进度条
  • 基于 electron-builder,非常容易使用

缺点

  • Windows 更新体验没有内置的好
  • Windows 存在权限问题

对比详见官方文档

Electron 集成原生能力

环境配置

1
2
yarn global add --production windows-build-tools 
yarn global add node-gyp

Electron 集成 dll

node-ffi-napi(node 版本 > 10,Electron 版本 > 6)

1
yarn add ffi-napi

使用 user32.dll 实现唤起微信桌面端窗口

1
2
3
4
5
6
7
8
9
10
const FFI = require('ffi-napi')
const user32 = new FFI.Libary('user32',{
'FindWindowA':['int32',['string','string']],
'showWindow':['int32',['int32','int32']]
})
function showWeChat(){
let res = user32.FindoWindowA("WeChatMainWindForPC",null)
let show = user32.showWindow(res,5)
}
module.exports = {showWeChat}

Electron 崩溃监控

  • 渲染进程崩溃后可以提示用户重新加载
  • 可以通过 preload 统一初始化崩溃监控

主进程异常监控

1
2
3
4
process.on('uncaughtException',function(err){
// 上报异常
// 异常日志
})

使用 crashReporter 实现崩溃日志发送

1
2
3
4
5
6
7
8
9
10
const {crashReporter} = require('electron');

crashReporter.start({
productName: "test",
companyName: "test",
submitURL: "https://www.test.com",
autoSubmit: true,
uploadToServer: true,
ignoreSystemCrashHandler: true
});

Electron 支持快捷键

全局快捷键

借助 Electron globalShortcut 方法实现

1
2
3
4
5
6
7
8
const {globalShortcut} = require("electron");

module.exports = (app => {
// 注册全局快捷键
globalShortcut.register("CommandOrControl+Option+Y", () => {
app.mainWindow.show()
})
});

本地快捷键

应用快捷键只有在应用程序被聚焦时触发,详见官方文档

Electron 国际化

Electron 开机自启

通过 setLoginItemSettings 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const {ipcMain, app: electronApp} = require('electron');
// 属性返回启动 Node.js 进程的可执行文件的绝对路径名。

const exePath = process.execPath;
module.exports = (() => {
// 给渲染页面获取当前的状态
ipcMain.handle('get-auto-start-status', () => electronApp.getLoginItemSettings())

// 设置开启自启
ipcMain.on('auto-start-open', () => {
electronApp.setLoginItemSettings({
openAtLogin: true,
path: exePath,
args: []
})
});
//设置开机不自启
ipcMain.on('auto-start-closed', () => {
electronApp.setLoginItemSettings({
openAtLogin: false,
path: exePath,
args: []
})
})

});

Electron 优化白屏问题

image-20210322172450113

窗口显示 win.on(‘show’) 和 页面渲染完成 win.on(‘ready-to-show’) 之间存在时间差,导致产生白屏。

解决方式

  • 在ready-to-show 时再去执行 win.show() 显示页面
  • 设置窗口底色

也可以通过 BrowserView、BrowserWindow、childWindow 实现一个 loading 占位图,等待页面加载完成后再替换掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const {BrowserView, BrowserWindow} = require('electron');

const browserWindow = new BrowserWindow({
width: 500,
height: 600,
// 其他参数
});

const loadingBrowserView = new BrowserView();

browserWindow.setBrowserView(loadingBrowserView);

loadingBrowserView.setBounds({
x: 0,
y: 0,
width: 400,
height: 600
});

loadingBrowserView.webContents.loadURL('loading.html');

browserWindow.webContents.on('will-navigate', () => {
browserWindow.setBrowserView(loadingBrowserView);
});


browserWindow.webContents.on('dom-ready', async (event) => {
browserWindow.removeBrowserView(loadingBrowserView);
});

Electron 的一些优化技巧

  • 尽量不要使用 remote 模块(同步IPC,容易影响UI渲染)
  • 使用 requestIdleCallback (在浏览器空闲时间才会去执行)

Electron 的问题

  • 打包体积过大,可以使用 yarn autoclean 来减少 node_modules 的体积

  • 源码安全问题

    打包生成的 asar 文件通过以下方式就可以解包得到源码

    1
    2
    yarn global add asar
    asar e app.asar unpack

    通过这种方式,我直接得到了 OPGG 客户端的源码。如果是商业应用需要进行代码混淆。

    image-20210322165723980

学习资源