Electron桌面应用开发入门

Electron通过WEB技术开发桌面应用,Electron 基于 Chromium 和 Node.js, 我们可以使用 HTML, CSS 和 JavaScript 构建桌面应用。Electron 兼容 Mac, Windows 和 Linux。VSCode就是基于Electron开发。有完善的官方开发文档。使WEB开发人员可以开发桌面应用成为可能,降低桌面应用开发成本,提升开发效率

安装

下载程序包

安装VSCode

安装SVN

  • Ctrl+Shift+X 打开EXTENSIONS 输入 SVN
  • 安装第一个SVN插件
  • 打开带有SVN的工程目录,VSCode会出现S大图标显示SVN的操作记录
  • Source Control(Ctrl+Shift+G)进行文件SVN控制,VSCode左边第三个图标

安装JS 代码跳转工具

  • Ctrl+Shift+X 打开EXTENSIONS 输入 Go To Method
  • 安装第一个插件,打开js代码右键菜单出现对应跳转功能

VSCode 打开项目工程

打开控制终端安装依赖

  • Ctrl+~ 打开终端控制台在主目录执行下面命令
  • 输入 npm install -g cnpm --registry=https://registry.npm.taobao.org
  • 输入 cnpm install
  • 输入 npm start 启动项目

VScode Electron Debug配置

  • 点击菜单DebugAdd Configuration...
  • 增加官方配置configurations部分配置,官方Debug文档
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    {
    "version": "0.2.0",
    "configurations": [
    {
    "name": "Debug Main Process",
    "type": "node",
    "request": "launch",
    "cwd": "${workspaceRoot}",
    "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
    "windows": {
    "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
    },
    "args": [
    "."
    ],
    "outputCapture": "std"
    }
    ]
    }
  • 对于win10操作系统vscode环境使用下面配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    {
    "version": "0.2.0",
    "configurations": [

    {
    "name": "Debug Main Process",
    "type": "node",
    "request": "launch",
    "cwd": "${workspaceRoot}",
    "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
    "windows": {
    "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-forge-vscode-win.cmd"
    },
    "args" : ["."],
    "outputCapture": "std"
    }
    ]
    }
  • 点击需要断点的行号左边,出现小红点断点标识
  • 点击DebugStart Debugging 或者F5 启动程序进入断点位置进行调试
  • 对于前端页面需要使用前端的调试工具通过命令mainWindow.webContents.openDevTools()打开调试工具栏
    1
    2
    3
    const { BrowserWindow } = require('electron')
    let win = new BrowserWindow()
    win.webContents.openDevTools()

通过yarn管理项目

  • 下载安装yarn程序
  • 删除原先的node_modules
  • 进入工程主目录执行yarn
  • 执行yarn start 启动项目
  • "package": "electron-forge package --arch=ia32",调整脚本打CPU32X架构的包
  • 执行yarn package 打包项目或者yarn run make --platform=win32 --arch=ia32

三种常见打包方式:

  • electron-forge
  • electron-builder
  • electron-packager

官方提供的打包教程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Load Windows 7
Install latest version of Node 4 (4.4.7 at the time of this comment)
Download zip of electron-quick-start (mostly because I didn't feel like trying to install Git)
Unzip electron-quick-start
Open a `cmd.exe` window
cd to your unzipped electron-quick-start
Run `npm install`
Run `node_modules\.bin\electron .` (the final space then period is important) - an Electron window should show up with Node/Chromium/Electron versions and a devtools pane.
Close that window.
Run `npm install --save-dev electron-packager`
Run `SET DEBUG=electron-packager`
Run `node_modules\.bin\electron-packager . --platform=win32 --arch=ia32 --app-version=0.0.1 --out=dist `(the --app-version=0.0.1 flag isn't necessary, but it was in your screenshot)
Run explorer `dist\electron-quick-start-win32-ia32`. It should open up a new folder view of your bundled example app.
Double click on electron-quick-start (possibly electron-quick-start.exe depending on your folder settings). You should see the same thing as in step 8.

有几条命令npm最好换成cnpm

1
cnpm install --save-dev electron-packager

数据存储

可以使用nedb,数据一般需要单例模式,不要多个页面用原型模式同时操作db文件。可以通过定义一个全局变量来实现,避免同时多次加载数据文件。

require()相同模块(相同路径,大小写敏感)得到的模块中的对象都是单例的。在require()首次加栽的时候,Node为其生成一个键,然后将其写入缓存,后面再使用require()的时就会从缓存中去找,如果存在,就直接返回缓存中的模块。

使用的时候出问题也很有可能是依赖包版本问题。

脚手架介绍

  • cnpm install -g electron-forge Electron-forge 是一个类似于傻瓜开发包的Electron工具整合项目
  • electron-forge init notepad 初始化一个项目

问题

  • 不兼容部分win7操作系统,还是不太稳定
  • 不兼容winXP操作系统
  • 打出来的程序包非常大,动不动就是几百M
  • 用户体验不如原生应用
  • 目前该技术还不够成熟
  • 没有足够的技术储备谨慎使用该技术

具体应用

通过子进程启动exec调用系统脚本或者程序child_process

调用的程序不在同级目录可以通过 && 进行多条语句合并,把目录合并进去。还可以通过把目标程序路径配置到系统环境变量的方式直接调用

1
2
3
exec('infotech.exe a b', (err, stdout, stderr) => {
// ...
});

如果提供了 callback,则调用时传入参数 (error, stdout, stderr)。 当成功时,则 error 将会为 null。 当出错时,则 error 将会是 Error 的实例。 error.code 属性将会是子进程的退出码, error.signal 将会被设为终止进程的信号。 除 0 以外的任何退出码都被视为出错。

执行完命令也可以通过echo查看返回码,正常c程序退出都是会return 0linux下一般使用exit(0),错误情况各种返回码都可能比如1,2,3,4…

1
2
3
## windows
git --version
echo %errorlevel%

ChildProcess类还提供了,close事件(stdio流关闭触发),error事件(发生错误后触发,比如无法杀死进程,无法向子进程发消息),exit事件(子进程结束触发)等多种方法

串口支持serialport

使用官方基础模板

1
2
3
4
5
6
7
8
9
10
11
12
13
# 先决条件,python2.7 node npm git vscode
git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
npm install -g node-gyp
npm install serialport --save
npm install serialport --save-dev # cnpm install serialport --save-dev
npm install electron-rebuild # cnpm install electron-rebuild
npm install --save-dev electron-rebuild # cnpm install --save-dev electron-rebuild

npm install

.\node_modules\.bin\electron-rebuild.cmd
npm rebuild

如果还是失败的话多试几次,查看jason文件是否添加相关依赖然后执行npm install,重新编译等操作。
用到了node-gyp 主要是为了跨平台,用来编译原生C++模块,可以从平台无关的配置生成平台相关的Visual Studio、Xcode、Makefile的项目文件,所以发布源码使用的时候根据具体环境进行编译。还有个node-pre-gyp用来发布安装二进C++插件。

GCC The GNU Compiler Collection (GCC) is an optimizing compiler produced by the GNU Project supporting various programming languages, hardware architectures and operating systems. The Free Software Foundation (FSF) distributes GCC as free software under the GNU General Public License (GNU GPL). GCC is a key component of the GNU toolchain and the standard compiler for most projects related to GNU and the Linux kernel. With roughly 15 million lines of code in 2019, GCC is one of the biggest open source programs in existence.[5] It has played an important role in the growth of free software, as both a tool and an example.
libstdc++ The GCC project includes an implementation of the C++ Standard Library called libstdc++, licensed under the GPLv3 License with an exception to link closed source application when sources are built with GCC.[61] The current version is 11.
CMake is an open-source, cross-platform family of tools designed to build, test and package software.

在main.js中加入打印串口信息的js代码

1
2
3
4
5
6
7
8
9
10
11
12
13

//main.js

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

SerialPort.list().then(
ports => ports.forEach(console.log),
err => console.error(err)
);

// ...

json文件:

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
{
"name": "electron-quick-start",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"repository": "https://github.com/electron/electron-quick-start",
"keywords": [
"Electron",
"quick",
"start",
"tutorial",
"demo"
],
"author": "GitHub",
"license": "CC0-1.0",
"devDependencies": {
"electron": "^13.1.4",
"electron-rebuild": "^2.3.5",
"serialport": "^9.2.0"
},
"dependencies": {
}
}

执行npm start,控制台打印出

1
2
3
4
5
6
7
8
9
{
path: 'COM3',
manufacturer: 'xxx',
serialNumber: 'xxxxx',
pnpId: 'USB\\VID_067.&PID_2300\\5&26C29000&0&3',
locationId: 'Port_#0001.Hub_#0001',
vendorId: '0600',
productId: '2300'
}

发送命令: 先读取串口信息,去除一个串口设置相关属性,调用串口的write方法

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
30
31
32
33
34
35
36
37
38
const SerialPort = require('serialport');
var Readline = SerialPort.parsers.Readline;
var ByteLength = SerialPort.parsers.ByteLength;

// 列出串口信息
SerialPort.list().then(
ports => ports.forEach(console.log),
err => console.error(err)
);

//设置串口号,波特率,关闭自动开启
var port = new SerialPort("COM3", {
baudRate: 9600, // 两端波特率要一致
dataBits: 8,
parity: 'none',
stopBits: 1,
autoOpen: false
});


// var parser = port.pipe(new ByteLength({length: 8}));
var parser = port.pipe(new Readline());// 按行/r/n分隔

//串口打开
port.open(function (err) {
if ( err ) {
return console.log('failed to open: ',err.message);
} else {
console.log('open');
//接受串口数据,并打印到终端
parser.on('data', function(data) { // 通过parse处理换行等格式
console.log('recieve data: ' + data);
});
}
});

// 发送消息
port.write('ls\n');

需要用到虚拟工具:

Virtual Serial Port Driver 6.9 虚拟串口
XCOM V2.0 发送接收指令,可以给物理接口,也可以给虚拟接口发送命令

可能出现ERROR:connect ETIMEDOUT

重新执行cnpm install
npm config set registry https://registry.npm.taobao.org/

多线程

js的世界是单线程的,于是出现了SetTimeout,Ajax这些异步的函数(这个比较特别是由浏览器开一个线程请求),函数同步执行时遇到异步函数,异步函数被放到异步队列,代码自上往下执行,会根据事件轮询机制执行异步函数。
js本身是没有异步的,Ajax也是由浏览器实现的。

参考