30天学透Electron之第一天_入门基础

119 阅读10分钟

前言

学一门语言,总无法避开以下几方面:语言本身的语法、打包构建、常用编辑器。

接下来会从这几方面逐一进行讲解,从理论到实践。

快速开始

通过forge的命令create-electron-app, 可以根据样板快速创建一个app应用。前置准备:nodejs、npm、nvm、git

当然没有forge也是可以创建的,根据以下命令即可创建

mkdir my-electron-app && cd my-electron-app
npm init

这个命令主要是创建了一个package.json文件,里面配置了版本、作者、入口js文件等信息。electron应用的入口文件一定要配置成main.js

在安装electron依赖包之间,建议重新配置npm源

npm config set registry registry.npmmirror.com

npm config get registry

npm cache clean --force

在开发环境安装electron,安装成功后,在项目根目录下会出现mode_modules目录和package-lock.json文件

npm install electron --save-dev

也可以指定版本安装, 在我的老版本mac上,只能安装17.0.0这个版本

npm install electron@22.0.0 --save-dev

接下来就可以运行第一个electron应用了

main.js是应用的入口文件,主要管控主进程、app声明周期、执行一些特权操作、管理渲染进程等等,在编写app代码之前先确保main.js配置正确

electron的主进程就是node的运行时,使用electron你可以执行任意的nodejs代码,为了让electron执行main.js,必须在package.json的scripts中增加:"start": "electron .",

main.js中写入console.log('Hello from Electron 👋')

然后执行npm run start, 在终端就可以看到main.js的执行结果了,至此说明electron可以正常使用了,接下来可以继续使用electron编写ui界面了。

Electron视窗

electron窗口可以展示本地的html页面,也可展示远程的html页面,首先在应用根目录下创建一个index.html文件,然后编辑main.js

ecmascript是一种脚本语言标准规范,electron28开始就可以支持ecmascript了

require是common.js的一种模块加载方式,运行时动态加载

import是ecmascript的模块加载方式,编译时静态加载

electron的很多核心模块都是遵循node的事件驱动的,比如app模块

windows视窗中展示的每个页面都是由渲染进程处理的,渲染进程可以和经典的web开发一样访问js api等工具,渲染器工作和普通的web页面非常相似,并且可以访问普通的web api 。

主进程是个nodejs进程, 视窗进程是个chrome进程,两者各自承担不同的职责,无法直接互相访问,但是有办法互相访问。

视窗的生命周期在不同的平台上表现是不一样的,electron没有强制一致,开发者可以监听视窗的事件进行定制。

Electron 只能运行在三种可能的平台上:win32 (Windows)、linux (Linux) 和 darwin (macOS)。

预加载脚本

主进程通过nodejs可以完全操控操作系统,渲染进程只负责渲染页面,无法操作nodejs,这也是为了安全,为了将不同进程桥接到一起,实现进程通信,可以使用预加载脚本。

通过预加载脚本可以增强渲染引擎,electron20之后的预加载脚本默认被沙箱化了,只能访问有限的nodejs函数。

在页面被加载到渲染引擎之前,预加载脚本就会被注入,便于加入一些需要特权访问的功能,也可以通过contextBridge api定义全局变量在不同的进程之间共享。

(1)创建预加载脚本preload.js,定义共享变量

(2)在main.js中定义预加载脚本的路径

(3)在渲染页面中使用预加载脚本

Electron进程

进程通信(IPC)

进程通信是非常重要的,由于electron中主进程和渲染进程承担了不同的职责,想要编写丰富的功能,就需要它们之间互相通信,比如通过ui触发native api,或者通过native api的调用触发ui的变化等等。

通道:通道名是人为定义的一个名称,可以是任意的名称,通道用于ipcMain和ipcRender之间传递消息,这里的通道都是双向的,可以从ipcMain传递到ipcRender,也可以用于从ipcRender传递到ipcMain。

在继续了解进程通信的细节之前,需要知晓“预加载脚本”是怎么工作的

主进程

每个Electron应用都有一个主进程,充当应用的入口点。主进程在nodejs环境中运行,这意味着他能够使用require模块并使用所有的nodejs api。

主进程的主要目的是使用BrowerWindow模块创建和管理应用窗口,BrowerWIndow类的每个实例都会创建一个应用窗口,该窗口在单独的渲染器进程中加载网页。你可以使用窗口的webContents对象从主进程与此web内容进行交互。主进程还通过Electron的app模块控制应用的生命周期。此模块提供了大量事件和方法,你可以使用它们来添加自定义应用行为。

渲染器进程

每个Electron应用都会为每个打开的BrowerWindow(以及每个web嵌入)生成一个单独的渲染器进程。这也就意味着渲染器进程无法直接访问require或者其他nodejs api。

你可能想知道渲染器进程如何与nodejs和electron的原生桌面功能交互,如果这些功能只能通过主进程访问,那么答案就是使用预加载脚本

尽管预加载脚本与其附加的渲染器进程共享window全局变量,但由于contextIsolation默认值,你无法直接将预加载脚本中的任何变量附加到window

上下文隔离意味着预加载脚本与渲染器的主要世界隔离,以避免将任何特权api泄漏到web内容代码中,相反,你可以使用contextBridge模块来安全地完成此操作

上下文隔离

contextBridge模块可以用于安全地将api从预加载脚本的隔离上下文公开到网站的运行上下文

进程间通信

通道:就是可以任意命名的,双向的,用于主进程和渲染进程之间通信用的,定义一个通道,主进程和渲染进程都可以共用

预加载脚本:用于暴露一些主进程中的api、模块等,比如暴露nodejs api或者electron模块,这样在渲染进程中也可以直接使用,比如暴露一些变量和通信api等,这样尽管上下文是隔离的,在渲染进程中也可以直接使用nodejs api

通信模式对比

(1)单向通信——渲染进程到主进程

ipcRender.send

ipcMain.on

核心就是在预加载脚本中,通过contextBridge对渲染进程暴露一个通信函数,然后渲染进程就可以向主进程发消息了。

(2)双向通信——渲染进程到主进程,主进程到渲染进程

双向通信的主要应用场景就是从渲染进程发起信息到主进程,然后等待主进程的回复

ipcRender.invoke

ipcMain.handler

核心就是在预加载脚本中,通过contextBridge对渲染进程暴露ipcRender.invoke函数,这样在渲染进程就可以通过这个暴露出的函数操作native组件了

以上是新版本的进程双向通信方式(electron7之后才具备),老版本还有一些其他的选择,不建议使用了

比如用于单向通信的ipcRender.send也可以用于双向通信,electron7之前的版本可以这样用,新版本忽略这种用法

同步调用方法:ipcRender.sendSync,这种老方法也不推荐使用,渲染进程会一直阻塞等待通信的返回,严重影响性能。

(3)单向/双向通信——主进程到渲染进程的通信

主进程需要指定与哪个渲染进程进行通信,然后通过webContents的send方法向渲染进程发消息,这个send方法同ipcRender的send方法类似,用于单向发送消息,渲染进程受到信息后也可以通过ipcRender.send回复主进程

webContents.send

ipcRender.on

(4)渲染进程之间的通信

有2种方式,一种是通过使用主进程做中介,另一种是通过messagePort技术,将messagePort传递到2个渲染进程,之后渲染进程就可以直接通信了。

messagePorts

messagePort主要用于不同上下文之间传递信息。一般都是成对创建的。

messagePorts是一项web特性,用于在不同上下文之间传递信息。

messagePorts都是成对创建的,一对连接的ports称为一个通道。两个port的不同之处取决于如何使用它们,比如在port1发消息,将会在port2收到消息,反之亦然。

在另一个port注册之前,就可以向port发送信息,只不过在另一个port注册之前,发送的消息会在队列中等待另一个port注册完成再被接收

在渲染进程中,MessagePort的表现和web中的表现是一致的,但是主进程不是一个页面,不支持MessagePort、MessageChannel,为了在主进程中也能够通过messagePort交互,electron增加了2个类:MessagePortMain、MessageChannelMain,它们的表现和渲染进程中的MessagePort表现是类似的。

messagePort可以在主进程或者渲染进程中创建使用,然后port只能通过ipcRender.postMessage、webContents.postMessage发送,要注意的是messagePort无法通过常规的send/invoke方法发送,只能通过postMessage发送,然后通过port在不同进程之间直接通信。

核心2个步骤

(1)先通过postMessage方法把port发送到对方进程

(2)然后就可以通过port.postMessage直接把信息发送对方进行通信了

在主进程中,通过messagePort通信,可以实现两个本不可连接的两个页面进行通信,比如被同源限制的2个页面就可以通过messagePort进行通信,messagePort还有一个增强特性,就是支持close事件。

(1)渲染进程之前直接通信

不推荐使用window的全局暴露,还是更推荐使用contextBridge按需暴露给渲染进程使用

(2)electron内置的ipc通信仅仅支持2种模式,send和invoke模式,通过messageChannel可以实现响应流

(3)主进程和渲染进程的mainWorld也可以直接通信,而不需要通过isolate context来传递消息

打包构建部署更新应用

建议使用官方推荐的electron forge

这是一个脚手架工具,包发布管理工具

当初始化一个新的app时,推荐使用官方模版,推荐使用create-electron-app

命令而不是直接使用init。package、make、publish是三个最主要的步骤

(1)安装electron forge,并将forge导入现有项目(让项目变成一个forge可理解的结构),运行完之后,会发现项目中多了个forge.config.js文件

npm install -save-dev @electron-forge/cli

npx electron-forge import

(2)创建可分发的文件。背后做了2件事情,1是把应用代码和electron二进制文件打包,2是创建可分发的文件,执行之后,在应用out目录下可以看到刚刚创建的文件,可以自定义应用图标。

npm run make

(3)代码签名是很重要的一个环节,用于标识应用的安全性,各个平台下载启动时都会校验这个应用的代码签名,同时对于应用的自动更新也是强依赖于代码签名的。

(4)发布(publish),就是将本地生产的可分发包发布到公共地址,供他人下载使用。

常用编辑器

推荐使用官方推荐的fiddle

===欢迎关注===

搜索框传播样式-标准色版.png