Electron 学习笔记

导图

基本介绍

Electron三个组成部分

  1. Chormium - UI
  • Web生态兼容性
  1. Node.js - 底层操作
  • 文件读写;
  • 使用C++;
  1. Native API - 跨平台
  • 统一原生界面如窗口,托盘;
  • 系统能力:Notification;
  • 基础能力:软件更新/崩溃;

浏览器发展史

Nexus世界上第一个浏览器

Mosaic - Mozilla - NetScape(所有浏览器的UA(user-agent)都会带上Mozilla)

IE (1995 Microsoft)

JavaScript (1995 NetScape) Brendan Eich - 10天完成!

开源Mozilla - 火狐

Chrome (2008,极简 多进程 v8)

Chrominum 开源 node.js 开源 v8开源

node-webkit (NW 2011) Github前五 - 赵成 (后加入Github Atom 项目组)

Atom-shell -> Electron (2013->2015)

判别是否Electron应用:

项目目录下 Contents/Framework 下是否有Electron

Electron应用最小组成

index.html 页面

package.json 包体描述

main.js 管理整个应用

架构和原理

Chromium架构

IPC跨进程通信 (主进程RenderProcessHost,Renderer进程RenderProcess)

ResourceDispatcher页面请求资源转发到IPC Browser处理再返回

Electron架构

Node.js和Chromiums整合

难点:事件循环(Node.js基于libuv,Chromium基于message bump)

  • Chromium集成到Node.js ,用libuv实现messagebump(NW) 【NSRunLoop glib 边界情况】
  • Node.js集成到Chromium【libuv轮询backend_fd】

延申资料

桌面端技术选型

入口快捷

离线可用

调用系统能力(通知,硬件)

安全需求(金融)

Native(C++/C#/Objective-c)

高性能,原生,体积小;门槛高

QT(C++)

跨平台,高性能,媲美原生;门槛高,迭代速度一般

Flutter

发展中,基建少

Nw.js (微信开发者工具)

支持XP,源码加密,支持扩展;包体积大,性能一般

Electron

包体积大,性能一般

Carlo,WPF,Chromium Embedded Framework,PWA

开发环境准备

安装 vscode,nodejs(NVM)【跳过】

安装 Electron:

npm install electron --save-dev

npm install --arch=ia32 --platform=win32 electron (32位打包,在32,64都能用)

验证安装成功

npx electron -v

./node_modules/.bin/electron -v

开发一个番茄钟

休息5分钟弹出休息结束

应用启动 → 倒计时工作25分钟 → 弹出是否休息→休息则5分钟倒计时后结束→不休息则重新开始25分钟

引入模块

const { app, BrowserWindow } = require('electron')

可以先阅读&操作一遍官方的快速开始文档

第三方库

timer.js

安装

npm install timer.js

引入

var myTimer = new Timer({
	onTick:() => {}
    onEnd: () => {}
})

使用

与Web开发异同

一、主进程与渲染进程

主进程(唯一)

  • package.json中main脚本的进程
  • 管理原生GUI(BrowserWindow、Tray、Dock、Menu)
  • 创建渲染进程,控制应用生命周期(app)

渲染进程(多个)

  • 展示Web页面的进程
  • 通过Node.js、Electron提供的API跟系统底层打交道

主进程 渲染进程 交叉
app管理应用生命周期(退出),设置属性(Dock) ipcRenderer(跟ipcMain进行IPC通信) clipboard剪切板
BrowserWindow管理窗口 remote调用主进程模块(建议不用) crashReporter监听进程
ipcMain(跟ipcRenderer进行IPC通信) desktopCapture系统截图/视频流
Menu/Tray/MenuItem/dialog/Notification原生GUI
webContents加载具体页面
autoUpdater更新模块
globalShortcut设置全局快捷键

二、进程间通信

  • 通知事件(创建原生菜单只有主进程能做)
  • 数据传输(在某页面获得内存情况)
  • 共享数据(用户信息在各个进程中共用)

IPC模块通信

Electron提供的IPC通信模块:主进程ipcMain、渲染进程ipcRenderer(两者都是EventEmitter对象)

从渲染进程到主进程

  • Callback写法

    • ipcRenderer.send(channel, …args)
    • ipcMain.on(channel, handler)
  • Promise写法(Electron7.0之后,处理请求+响应模式)

    • ipcRenderer.invoke(channel, …args)
    • ipcMain.handle(channel, handler)

从主进程到渲染进程

  • 主进程通知渲染进程
    • ipcRenderer.on(channel, handler)
    • webContents.send(channel) [BroswerWindow]

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

  • 通知事件
    • 通过主进程转发(Electron 5之前)
    • ipcRenderer.sendTo(Electron 5之后)
  • 数据共享
    • web技术(localStorage、sessionStorage、indexedDB)
    • 使用remote

// main.js
// new win1 & win2 instanceof BrowserWindow and loadFile
global.sharedObject = {
	win2WebContentsId = win2.webContents.id // 传输webContents.id
}

// renderer1.js
const { ipcRenderer, remote } = require('electron')
let sharedObject = remote.getGlobal('sharedObject')
let win2WebContentsId = sharedObject.win2WebContentsId
ipcRenderer.sendTo(win2WebContentsId, 'do-some-work', 1)

// renderer2.js
const { ipcRenderer } = require('electron')
ipcRenderer.on('do-some-work', (e, a) => {
    alert('renderer2 handle some work' + a)
})

坑🕳

  • 少用remote模块(好写,但触发底层IPC通信事件,性能开销大,易卡死)
  • 不要用sync模式(ipcRenderer的方法,易卡死)
  • 在请求+响应的通信模式下,需要自定义超时限制

三、Native及原生GUI

使用Electron API创建原生GUI

  • BrowserWindow 应用窗口
  • Tray 托盘
  • app设置dock.badge(未读数)
  • Menu菜单
  • dialog原生弹框
  • TouchBar苹果触控板

使用Electron API获得底层能力

  • clipboard
  • globalShortcut 全局快捷键
  • desktopCapture 捕获桌面
  • shell打开文件、URL

使用Node.js获得底层能力

  • Electron 同时在主进程和渲染进程中对Node.js暴露了所有的接口
    • fs进行文件读写
    • crypto进行加解密
  • 通过npm安装社区上所有的Node.js库

🌰

使用node.js的fs模块打印文件内容

mainWindow.webContents.openDevTools() // 主进程打开开发工具
require('fs').readFileSync('./index.html', 'utf-8') // 开发工具的console中执行

使用Node.js调用原生模块

node.js add-on

node-ffi (Foreign Function Interface)

调用OS能力

  • winRT(调用蓝牙等)
  • Applescript(苹果系统)
  • Shell(node.js child_process)

Electron能力

四、释放前端想象力

  • 不用兼容Safari、IE

    • babel中设置targets为Electron对应的Chrome版本
  • 大胆使用Chrome最新支持的API 【文档地址

    • 原生LazyLoad
    • ES 6/7/8/9/10高级语法
      • async await / Promise
      • String/Array/Object高级用法
      • BigInt(处理大数不用再引用long.js啦)
  • 无跨域问题(使用Node.js发送请求、使用Electron net发送请求)

  • 操作本地文件

  • 更好用的本地DB(LowDB, LevelDB, SQLite)

  • 多线程、多进程并行(Node.js: worker + child_process)