乐趣区

想要试试Electron-不如看看这篇爬坑总结

前言

web 端能做的事情很多,但是当涉及到操作系统的时候,可能就有点力不从心了。前段时间在开发一个 web 系统的时候,就遇到了类似的情况。我们需要获取电脑操作系统的一些信息,比如 mac 地址等。我们的 web 系统是完全放在服务器上,通过浏览器来运行的,但是通过 web 端并不能直接实现我们想要的效果。

问题就是留给人们来解决的。经过同事之间的讨论,因为系统本身并不复杂,而且要进行快速的开发。决定用 Electron + 原 web 系统的页面,来解决涉及操作系统信息的问题。

这篇文章总结了我在使用 Electron 时所遇到的一些问题和解决方法。

什么是 Electron?

使用 JavaScript, HTML 和 CSS 构建跨平台的桌面应用——这是 Electron 官网的简介

Electron 是 GitHub 开发的一个开源框架。它允许使用 Node.js(作为后端)和 Chromium(作为前端)完成桌面 GUI 应用程序的开发。Electron 现已被多个开源 Web 应用程序用于前端与后端的开发,著名项目包括 GitHub 的 Atom 和微软的 Visual Studio Code。——知乎

可以简单的理解为 Electron 为 web 项目套上了 Node.js 环境的壳,使得我们可以调用 Node.js 的丰富的 API。这样我们可以用 JavaScript 来写桌面应用,拓展很多我们在 web 端不能做的事情。

怎么构建 Electron 应用?

构建 Electron 应用很简单,可以直接查看官方文档,也可以利用现有的轮子。基本来说可以分为两大类:模板和命令行工具。这两种方式都有各自的优点,具体选用哪种方式要根据自己实际的情况来。就拿我来说,因为我要做的项目原本就有 web 端的页面了,这些模板基本都不适用,为了赶进度,就直接参考官网入门——打造你的第一个 -electron- 应用,再加上原有的代码进行构建项目。

下面为一些常用的构建模板与命令行工具

模板

  • electron-react-boilerplate:electron + react
  • electron-vue: electron + vue

命令行工具

  • 打造你的第一个 -electron- 应用:官网教程
  • electron-forge:一个用来构建现代化 Electron 应用的完善的工具

一个例子

下面是一个最基础的 Electron 项目,后续的代码都是在此基础上进行拓展。

npm install --save-dev electron

一般结构

demo/
├── package.json
├── main.js
└── index.html

package.json

{
  "name": "demo",
  "version": "1.0.0",
  "description": "electornDemo",
  "main": "main.js",
  "scripts": {"start": "electron ."},
  "author": "xmanlin",
  "license": "MIT",
  "devDependencies": {"electron": "^9.0.0"}
}

main.js

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

app.on('ready', function createWindow () {
    // 可以创建多个渲染进程
    let win = new BrowserWindow({
        width: 800,
        height: 600,
    })
    
    win.show()

    // 渲染进程中的 web 页面可以加载本地文件
    win.loadFile('index.html')


    // 记得在页面被关闭后清除该变量,防止内存泄漏
    win.on('closed', function () {win = null})


})

// 页面全部关闭后关闭主进程, 不同平台可能有不同的处理方式
app.on('window-all-closed', () => {app.quit()
})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>demo</title>
</head>
<body>
    <div> 一个 electron 项目 </div>
    <script>
    
    </script>
</body>
</html>

什么是主进程和渲染进程?

在 Electron 中,主进程和渲染进程的概念是十分重要的,具体可以查看官网介绍:主进程和渲染进程。

主进程

  • 运行 package.json 中的 main 脚本的进程是主进程。
  • 一个 electron 应用有且只有一个主进程。
  • 主进程可以进行 GUI 相关的原生 API 操作。

渲染进程

  • Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。
  • 每个 web 页面运行在它自己的渲染进程中。
  • 使用 BrowserWindow 类开启一个渲染进程并将这个实例运行在该进程中,当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。
  • 渲染进程中不能调用原生资源,但是渲染进程中同样包含 Node.js 环境,所以可以引入 Node.js

模块,在 Node.js 支持下,可以在页面中和操作系统进行一些底层交互。

渲染进程之中如何调用 Node.js 的 API?

在 Electron5.0 版本后,渲染进程默认是不能调用 Node.js 的 API 的,经过设置后才可以:

主进程(main.js)

let win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {nodeIntegration: true,  // 设置为 true 就可以在这个渲染进程中调用 Node.js}
})

怎样打开开发者工具?

Electron 虽然是用了 Chromium,但是想要打开开发者工具并不是像浏览器一样,如在 windows 下默认情况直接按 F12。

在 Electron 中有两种方式打开开发者工具:

第一种是在主进程中进行设置,设置后,启动项目,该渲染进程就默认打开了开发者工具

 win.webContents.openDevTools();

第二种可以在渲染进程窗口的菜单栏进行选择 View -> Toggle Developer Tools。(或者直接按照上面的快捷键进行操作)

electron 控制台打印乱码问题?

我们可能在 Windows 的控制台会出现中文乱码的问题,当我们在 Windows 的控制台下输入 chcp, 可以查看到当前字符编码,常见的 gb2312 的值是 936,utf8 的值是 65001。这种情况下只要对 package.json 进行设置就能解决。

"start": "chcp 65001 && electron ."

主进程和渲染进程之间如何通信?

主进程和渲染进程之间可以通过 ipcRenderer 和 ipcMain 模块通信。

主进程主动向渲染进程发送消息

主进程(main.js)

// 主进程向渲染进程发送消息,'did-finish-load': 当导航完成时发出事件,onload 事件也完成
win.webContents.on('did-finish-load', () => {win.webContents.send('msg', '消息来自主进程')
})

渲染进程(index.html)

<script>
    const {ipcRenderer} = require('electron')
    ipcRenderer.on('msg', (event, message) => {console.log(message) // 消息来自主进程
    })
</script>

渲染进程主动向主进程发送消息

渲染进程(index.html)

const {ipcRenderer} = require('electron')
ipcRenderer.send('indexMsg','消息来自渲染进程')

主进程(main.js)

const {ipcMain} = require('electron')
ipcMain.on('indexMsg',(event,msg) => {console.log(msg) // 消息来自渲染进程
})

渲染进程之间如何通信?

渲染进程之间的通信方式有很多种,下面列出几种:

使用全局共享属性

// 主进程
global.sharedObject = {user: ''}

// 渲染进程一
const {remote} = require('electron')
remote.getGlobal('sharedObject').user = 'xmanlin'

// 渲染进程二
const {remote} = require('electron')
console.log(remote.getGlobal('sharedObject').user) //xmanlin

ipcRenderer.sendTo()

下面是 ipcRenderer.sendTo() 的参数

ipcRenderer.sendTo(webContentsId, channel, [, arg1][, arg2][, ...])
ipcRenderer.sendTo(windowId, 'ping', 'someThing')
//webContentsId : Number
//channel : String
//...args : any[]

具体用法

主进程(main.js)

// 创建一个新的渲染进程
let win2 =  new BrowserWindow({
    width: 800,
    height: 600,
})

// 为渲染进程设置唯一 id
win2.id = 2

渲染进程 1

<script>
    const {ipcRenderer} = require('electron')
    // 向 id 为 2 的渲染进程发送消息
    ipcRenderer.sendTo(2,'msg1','来自渲染进程 1 的消息')
</script>

渲染进程 2

<script>
    const {ipcRenderer} = require('electron')
    ipcRenderer.on('msg1', (event, message) => {console.log(message) // 来自渲染进程 1 的消息
    })
</script>

利用主进程做消息中转站

// 主进程
ipcMain.on('msg1', (event, message) => {yourWindow.webContents.send('msg2', message);
}

// 渲染进程 1
ipcRenderer.send('msg1', '来自渲染进程 1 的消息')

// 渲染进程 2
ipcRenderer.on('msg2', (event, message) => {console.log(message)  // 来自渲染进程 1 的消息
  }
)

如何对项目进行打包?

打包也是必不可少的一步,这里介绍两种比较成熟的打包工具:electron-packager 和 electron-builder。这两个工具主要是对其进行配置。

electron-packager

我们可以利用 electron-packager 把我们现有的 electron 应用打包为 exe 可执行文件。

先进行安装

npm install electron-packager --save-dev

安装好之后要配置 electron-packager 的基本命令,下面为官方文档中的基本格式:

electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch> [optional flags...]

简要的介绍一下各个参数所代表的意思:

  • sourcedir:项目所在路径
  • appname:应用名称(打包后文件的名称)
  • platform:确定了你要构建哪个平台的应用(Windows、Mac 还是 Linux)

    • platform=win32 代表 Windows
    • platform=darwin 代表 Mac
    • platform=linux 代表 Linux
  • arch:决定了使用 x86 还是 x64 还是两个架构都用
  • optional options:可选选项

下面为一个例子,供参考

package.json

"scripts": {
    "build32": "electron-packager ./ appDemo --platform=win32 --arch=ia32  --out=./app --app-version=1.0.0 --overwrite --icon=./favicon.ico",
    "build64": "electron-packager ./ appDemo --platform=win32 --arch=x64  --out=./app --app-version=1.0.0 --overwrite --icon=./favicon.ico"
  }

上面都是打包 Windows 下的软件,build32 打包的为 32 位,build64 打包的为 64 位。除基本参数外,上面其他参数所代表的意义如下:

  • –out 表示打包后生成的文件的目录
  • –app-version 表示打包生成文件的版本号
  • –overwrite 表示删除原有的打包文件,生成新的打包文件
  • –icon 表示打包文件的图标

electron-builder

electron-builder 不仅可以打包为 exe 可执行文件,还可以打包为可安装程序,功能与 electron-packager 相比也要丰富一些。

官网更为推崇 yarn 来进行安装

yarn add electron-builder --dev

当然 npm 也是可以的

npm install electron-builder --save-dev

然后我们可以进行配置了

"scripts": {
  "pack": "electron-builder --dir",
  "dist": "electron-builder"
},
 "build": {
   "productName": "appDemo", // app 中文名称
   "appId": "appDemoId",// app 标识
   "directories": { // 打包后输出的文件夹
     "buildResources": "resources",
     "output": "dist/"
   }
   "files": [ // 打包后依然保留的源文件
     "dist/electron",
     "node_modules/",
     "package.json"
   ],
   "mac": { // mac 打包配置
     "target": "dmg",
     "icon": "icon.ico"
   },
   "win": { // windows 打包配置
     "target": "nsis",
     "icon": "icon.ico"
   },
   "dmg": { // dmg 文件打包配置
     "artifactName": "appDemo.dmg",
     "contents": [
       {
         "type": "link",
         "path": "/Applications",
         "x": 410,
         "y": 150
       },
       {
         "type": "file",
         "x": 130,
         "y": 150
       }
     ]
   },
   "nsis": { // nsis 文件打包配置
     "oneClick": false,
     "allowToChangeInstallationDirectory": true, // 允许修改安装目录
     "allowElevation": true, // 允许请求提升。如果为 false,则用户必须使用提升的权限重新启动安装程序。"installerIcon": "./build/icons/aaa.ico",// 安装图标
     "uninstallerIcon": "./build/icons/bbb.ico",// 卸载图标
     "installerHeaderIcon": "./build/icons/aaa.ico", // 安装时头部图标
     "createDesktopShortcut": true, // 创建桌面图标
     "createStartMenuShortcut": true,// 创建开始菜单图标
     "shortcutName": "xxxx", // 图标名称
     "include": "build/script/installer.nsh", // 包含的自定义 nsis 脚本这个对于构建需求严格得安装过程相当有用。},
 }

在使用 electron-builder 打包时,也可以指定参数

 --mac, -m, -o, --macos   macOS 打包
 --linux, -l              Linux 打包
 --win, -w, --windows     Windows 打包
 --mwl                    同时为 macOS,Windows 和 Linux 打包
 --x64                    x64 (64 位安装包)
 --ia32                   ia32(32 位安装包) 

全部参数可参考 Command Line Interface (CLI)

关于 NSIS,也可以了解一下这种打包方式:electron 打包流程 electron-packager + NSIS

如何设置窗口默认最大化和全屏?

默认最大化

// 主进程(main.js)let win = new BrowserWindow({show: false})
win.maximize()
win.show()

默认全屏

// 主进程(main.js)let win = new BrowserWindow({fullscreen: true})

如何自定义菜单栏?

可以直接参考这篇文章 - 使用 Electron 自定义菜单,写的比较详细,也可以直接参考官方文档来。当然我们也可以把自带的菜单栏隐藏掉,然后自己调用写 Electron 的 API 写一个菜单栏。例如 VSCode 就是这么做的,打开 VSCode,然后在帮助里面找到切换开发者工具,你可能会发现新世界~。

如何获取操作系统 mac 地址?

这个主要是调用 Node.js 的 API,就可以获取系统的 mac 地址。

var os=require("os");
// 获取 mac 地址
var mac = ''
var networkInterfaces=os.networkInterfaces();
for(var i in networkInterfaces){for(var j in networkInterfaces[i]){if(networkInterfaces[i][j]["family"]==="IPv4" && networkInterfaces[i][j]["mac"]!=="00:00:00:00:00:00" && networkInterfaces[i][j]["address"]!=="127.0.0.1"){mac = networkInterfaces[i][j]["mac"]
        }
    }
}

参考

https://www.electronjs.org/docs

https://blog.csdn.net/weixin_…

https://www.jianshu.com/p/62c…

https://blog.csdn.net/qq_3480…

https://segmentfault.com/a/11…

https://juejin.im/post/5cfd2e…

最后

这篇文章是我到目前为止在学习并应用 Electron 时所遇到的问题以及所找到的解决办法,希望对大家有所帮助。若有不足或错误的地方,欢迎指出~

退出移动版