Electron学习

 官网

介绍

Electron 可以让我们使用纯 JavaScript 调用丰富的原生 API 来创建桌面应用;可以把它看作是专注于桌面应用而不是 web 服务器的 io.js 的一个变体。

当然这不意味着 Electron 是绑定了 GUI 库的 JavaScript;相反,Electron 使用 web 页面作为它的 GUI,所以可以把它看作成一个被 JavaScript 控制的,精简版的 Chromium 浏览器——从这个角度来理解,我们就明白了,所有和系统的交互功能,Electron 这个平台已经搞定了,我们所需要的就是创建一个自己喜欢的界面,一个或多个核心的功能,以及调用它提供给我们的 API 就好。

因为 Electron 本身其实也是 Node.js 的一个第三方项目,所以在开发的时候,我们首先需要已经安装了 Node.js,以及包管理器 NPM,外加一个顺手的编辑器:我个人用 VS Code 很顺手,当然如果喜欢用别的编辑器也没问题,比如前文提到的 Notepad++,或者著名的 Sublime Text、Atom(话说这个也是 Electron 做的)、Komodo Edit……等等等等,都可以。

接下来,用 NPM 在本地安装一个 Electron 的副本即可,可以选择全局安装或者针对项目单独安装:

npm i -g electron

一个基础的 Electron 项目结果如下:

my-electron-app/
├── package.json
├── main.js
└── index.html

因为 Node.js 对项目结构以及命名还是有点要求的,所以我个人推荐用一些 Electron Cli 工具来进行项目启动和初始化,这样会相对省一些事,比如 electron-forge

Electron Forge

是创建、发布和安装现代Electron 应用程序的完整工具。

安装

建议是安装成全局,这样方便使用
npm install -g electron-forge

使用

新建一个文件夹,定位到文件夹。

1、在你的应用程序中安装 Electron 作为开发依赖

npm install electron --save-dev

【--save-dev 的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖。】

--save-dev 与--save的区别

npm install 在安装 npm 包时,有两种命令参数可以把它们的信息写入 package.json 文件,一个是npm install--save另一个是 npm install –save-dev,他们表面上的区别是--save 会把依赖包名称添加到 package.json 文件 dependencies 键下,--save-dev 则添加到 package.json 文件 devDependencies 键下

  • --save-dev,会在devDependencies里面添加依赖
  • -D,会在devDependencies里面添加依赖
  • --save,会在dependencies里面添加依赖
  • -S,会在dependencies里面添加依赖

2、通过 init 命令指定当前文件夹为新项目:

electron-forge init

【这里要留意,如果 NPM 的映像是指向淘宝的话,整个过程会快很多。查看镜像:npm config get registry

完成后,初始配置就结束了:

3、这个初始代码已经可以运行了,只要运行如下命令:electron-forge start 

可以看到,初始的界面是包括了菜单栏、主界面以及控制台的,而控制台的出现就分明体现了它本质上是个浏览器的特点,这也使得我们在本地及时的进行调整、修复和新功能测试变得非常简单。

更多参考:快速了解Electron:新一代基于Web的跨平台桌面技术

快速入门

参考

通过使用Electron创建一个极简的 Hello World 应用,该应用与electron/electron-quick-start类似

该应用将会打开一个浏览器窗口,来展示包含当前正在运行的 Chromium, Node.js, and Electronweb等版本信息的web界面

前提条件:node.js

注意:因为 Electron 将 Node.js 嵌入到其二进制文件中,你应用运行时的 Node.js 版本与你系统中运行的 Node.js 版本无关。 

创建应用程序

Electron 应用程序遵循与其他 Node.js 项目相同的结构。

1、首先创建一个文件夹并初始化 npm 包。

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

init初始化命令会提示您在项目初始化配置中设置一些值:

 参考:使用npm init初始化项目

2、然后,将 electron 包安装到应用的开发依赖中。[注save前是两个-]

$ npm install --save-dev electron

3、最后,您希望能够执行 Electron 如下所示,在您的 package.json配置文件中的scripts字段下增加一条start命令:"start": "electron ."

最终你的package.json如下:

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "\"hello world\"",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "electron ."
  },
  "author": "huy",
  "license": "ISC",
  "devDependencies": {
    "electron": "^13.1.3"
  }
}

4、start命令能让您在开发模式下打开您的应用,即 : npm start

注意:此时运行程序会报错,因为还没有入口文件。

运行主进程

任何 Electron 应用程序的入口都是 main 文件。 这个文件控制了主进程,它运行在一个完整的Node.js环境中,负责控制您应用的生命周期,显示原生界面,执行特殊操作并管理渲染器进程(稍后详细介绍)。

要初始化这个main文件,需要在您项目的根目录下创建一个名为main.js的空文件。

注意:此时运行程序不会报错,但是没有反应,因为还没有页面。

创建页面

在可以为我们的应用创建窗口前,我们需要先创建加载进该窗口的内容。 在 Electron 中,每个窗口中无论是本地的HTML文件还是远程URL都可以被加载显示。

在您的项目根目录下创建一个名为index.html的文件:

<!DOCTYPE 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>

在窗口中打开您的页面

现在您有了一个页面,将它加载进应用窗口中。 要做到这一点,你需要 两个Electron模块:

  • app 模块,它控制应用程序的事件生命周期。
  • BrowserWindow 模块,它创建和管理应用程序 窗口。

因为主进程运行着Node.js,您可以在文件头部将他们导入作为 公共JS模块:

// Modules to control application life and create native browser window
const {app , BrowserWindow } =require('electron')

//添加一个createWindow()方法来将index.html加载进一个新的BrowserWindow实例。
function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600
  })

  win.loadFile('index.html')
}

//调用createWindow()函数来打开您的窗口。
//只有在 app 模块的 ready 事件被激发后才能创建浏览器窗口。 通过使用 app.whenReady() API来监听此事件。 在whenReady()成功后调用createWindow()。
app.whenReady().then(()=>{
    createWindow()
})

此时,执行 npm start

通过预加载脚本从渲染器访问Node.js

现在要做的是输出Electron的版本号和它的依赖项到你的web页面上。

在主进程通过Node的全局 process 对象访问这个信息是微不足道的。 然而,你不能直接在主进程中编辑DOM,因为它无法访问渲染器 文档 上下文。 它们存在于完全不同的进程!

这是将 预加载 脚本连接到渲染器时派上用场的地方。 预加载脚本在渲染器进程加载之前加载,并有权访问两个 渲染器全局 (例如 window 和 document) 和 Node.js 环境。

创建一个名为 preload.js 的新脚本如下:

window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector)
    if (element) element.innerText = text
  }

  for (const dependency of ['chrome', 'node', 'electron']) {
    replaceText(`${dependency}-version`, process.versions[dependency])
  }
})

要将此脚本附加到渲染器流程,请在你现有的 BrowserWindow 构造器中将路径中的预加载脚本传入 webPreferences.preload 选项

 const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

这里使用了两个Node.js概念:

  • __dirname 字符串指向当前正在执行脚本的路径 (本例中,你的项目的根文件夹)。
  • path.join API 将多个路径段联结在一起,创建一个跨平台的组合路径字符串。

我们使用一个相对当前正在执行JavaScript文件的路径,这样您的相对路径将在开发模式和打包模式中都将有效。

此时,执行 npm start,结果如下:

总结

1、我们引导了一个Node.js应用程序,并添加了Electron作为依赖项。
2、我们创建了一个main.js脚本来运行我们的主进程,它控制我们的应用程序并在Node.js环境中运行。在这个脚本中,我们使用Electron的app和BrowserWindow模块来创建一个浏览器窗口,该窗口在一个单独的进程(渲染器)中显示web内容。
3、为了访问渲染器中的某些Node.js功能,我们在BrowserWindow构造函数中附加了一个预加载脚本。

打包

推荐使用cli(electron-forge)

建议是安装成全局,这样方便使用
npm install -g electron-forge

这里有两种形式的打包,分别在不同场景下使用

  • electron-forge package 只是打包成一个目录到out目录下,注意这种打包一般用于调试,并不是用于分发
  • electron-forge make 这个才会打出真正的分发包,放在out\make目录下

两个命令都可以使用--arch 和--platform参数来指定系统结构和平台,但是需要注意的是只能打包你当前机器的平台包,比如你用OSX是无法打出windows平台安装包的;这两个参数不填写的话,默认和当前系统一致
另外,make是用squirrel打出来的包,安装后是放在%localappdata%下的

参考:Electron应用的开发和打包
官方

其他学习

主脚本文件main.js/index.js

1、调用模块

引用 Electron 模块:

import { app, BrowserWindow } from 'electron';

或者用更符合 ES 6 的方式来引入:

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

2、应用退出

if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
  app.quit();
}

当应用更新、卸除的时候,应用会自动退出就好。

3、主窗口

  • 指定主窗口的内容从哪里加载,这里指定了 src 目录下的 index.html:
mainWindow.loadURL(`file://${__dirname}/index.html`);

这里使用了 Node.js 的路径通配符 ${__dirname},通常就是当前文件所在路径的名称,

  • 是否允许开发工具可见:【程序运行没有效果时,可以开启看看是什么问题】
mainWindow.webContents.openDevTools();

在前期的开发工作当中,开发者工具是我们很重要的辅助工具,一般都是需要打开的;只有在需要对外发布的时候,我们才需要去除这一行使得开发工具“隐身”。

4、应用加载

就是 Electron 已经完成了加载窗口前的准备,应用在各个不同状态时,需要启动其他 API 的时候一个应用处理的机制,本质上就是侦听器:app.on();

Electron的进程

Electron 是由两种进程组成的,即主进程和渲染进程:

  • 在 Electron 里,运行 package.json 里 main 脚本的进程被称为主进程(Main Process),在主进程运行的脚本可以以创建 web 页面的形式展示 GUI:
  1. 主进程通过创建浏览器窗口实例来创建网页:每一个浏览窗口实例在其渲染过程中运行网页,当一个 BrowserWindow 实例被摧毁时,对应的渲染过程也被终止
  2. 主进程管理所有网页及其对应的渲染过程
  • 由于 Electron 使用 Chromium 来展示页面,所以 Chromium 的多进程结构也被充分利用:每个 Electron 的页面都在运行着自己的进程,这样的进程我们称之为渲染进程(Renderer Process)
  1. 渲染进程只能管理单个的网页,在一个渲染过程中崩溃不会影响其他渲染过程
  2. 渲染进程通过 IPC 与主进程通信,在网页上执行 GUI 操作;由于安全考虑和可能的资源泄漏,直接从渲染器过程中调用与本地 GUI 有关的 API 会受到限制
  3. 在html中引入渲染进程代码:<script src="./renderer.js"></script>

两者之间的通信可以通过进程间通信模块进行:ipcMain 和 ipcRenderer ;还有一个从渲染进程调用主进程模块的通讯模块:remote

进程API

针对不同的进程,Electron 提供了不同的 API 以供使用,所以可以分为以下3类 API:

  • 主进程 API
  • 渲染进程API
  • 通用API

进程间通信

1、从渲染进程到主进程

Callback 写法:
• ipcRenderer.send
• ipcMain.on
Promise 写法 (Electron 7.0 之后,处理请求 + 响应模式)
• ipcRenderer.invoke
• ipcMain.handle

2、从主进程到 渲染进程

• ipcRenderer.on
• webContents.send

报错

1、electron渲染进程报require is not defined

主进程main.js里的new BrowserWindow中增加:
webPreferences:{
      nodeIntegration:true,
      contextIsolation:false
    }

参考:踩坑electron渲染进程renderer,解决require is not defined的问题

2、electron windows通知不生效

 参考:electron,win10,消息通知

posted @ 2021-06-17 19:58  peterYong  阅读(386)  评论(0编辑  收藏  举报