工作中接触到Electron桌面开发,摸索了几天,结合网上的教程,整理一下笔记,方便自己今后查阅也方便刚接触Electron的朋友参考
Electron是一个基于Node.js与Chromium的框架,可以使用HTML/JS/CSS,jQuery,Vue来编写页面,优势在于编写的程序可以跨平台(Windows,Linux,Mac),使用前端的脚手架的同时还能享受Node生态带来的便利
经过一周的尝试,走通了开发一个EXE安装程序的流程,加载运行DLL的小工具及生成安装包
先从环境搭建开始,国内配置环境着实耽误了我不少时间,如果手里有全局加速上网工具最好不过
所需的软件环境
- vs2013
- Python 2.7
- Node.js
VS系列软件用于编译C++代码,2015,2017版本也都是可以的,Python需要是2.7.X版本(必须),Node.js 32或者64位都可以,不过这里有个蛮坑的地方,32位版本只能加载32位的DLL,64位的版本只能加载64位的DLL,这个还是挺需要注意的
小Tips: 在安装Python过程中设置添加环境变量(此处默认为不设置环境变量)
安装Electron
使用淘宝提供的cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
然后使用cnpm安装
cnpm install -g electron
可能是我这里的网络问题,下载Electron的中途会断,报错如下
没有报错最好,如果遇到同样的报错,可以看下面的补充或手动下载Electron放置在缓存目录
如果本机存在HTTP代理,可以使用
npm config set proxy http://server:port
npm config set registry http://registry.npmjs.org/
代理方式可能会在下载安装包的过程中自动断掉导致下载失败
设置源:
在不使用cnpm的前提下,也可以配置npm让其使用taobao源
npm config set registry https://registry.npm.taobao.org # 注册模块镜像
npm config set disturl https://npm.taobao.org/dist # node-gyp 编译依赖的 node 源码镜像
npm config set electron_mirror https://npm.taobao.org/mirrors/electron/ # electron 二进制包镜像
另外,Npm源配置会保存在C:\Users\Administrator\ .npmrc文件中,可直接编辑配置文件修改或删除设置
参考:https://segmentfault.com/a/1190000008410558
手动下载Electron并安装
针对cnpm与设置代理下载Electron都可能报错的问题,手动下载Electron并将其放在指定位置,npm安装的时候会在缓存目录查找,这样就可以把Electron安装成node模块
在 https://npm.taobao.org/mirrors/electron 下载相应版本及SHASUMS256.txt校验文件
将下载到的electron及校验文件放置在当前用户目录下的“.electron”文件夹中,之后使用npm或cnpm安装即可
ia32是指32位版本,x64为64位版本,这个需要根据你安装的Node.js位数决定
运行官方示例
网站:https://electronjs.org/
# 克隆示例项目的仓库
$ git clone https://github.com/electron/electron-quick-start
# 进入这个仓库
$ cd electron-quick-start
# 安装依赖并运行
$ cnpm install && cnpm start
接下来对demo进行一些改造,使其能够调用dll文件中函数
使用Electron调用DLL文件
Electron同样也支持Node模块,但由于和官方的Node相比使用了不同的V8引擎,如果重新编译原生模块,则需要下载Electron的headers头文件。
Node-gyp编译需要使用Node的源文件头以及Electron的源文件头,这个从npm仓库下载也会很慢,不过我们可以预先把头文件下载下来
预先下载Node.js与Electron的头文件
编译需要用到当前版本Node.js的头文件,可以通过淘宝源预先下载
node-gyp install --dist-url https://npm.taobao.org/mirrors/node
如果提示找不到node-gyp,运行cnpm install node-gyp -g
进行安装
node-gyp会把它放在C:\Users\Administrator\.node-gyp
Electron的头文件也需要下载,也是存放在.node-gyp目录,你大可跳过这部分,如果之后重编译模块的时候下载Electron超时,再回过来看也不迟
node-gyp rebuild --target=1.8.2 --arch=ia32 --dist-url=https://atom.io/download/electron
如果你在rebuild的时候卡住了,那可以手动下载electron的头文件放置在用户目录下的.node-gyp
目录下,下载地址如下,你可能需要根据Electron软件的版本去修改下载路径
https://atom.io/download/electron/v1.8.2/iojs-v1.8.2.tar.gz https://atom.io/download/electron/v1.8.2/SHASUMS256.txt https://atom.io/download/electron/v1.8.2/win-x64/iojs.lib https://atom.io/download/electron/v1.8.2/win-x86/iojs.lib
8.9.4文件夹对应的是Node.js的头文件 Iojs-1.8.2文件夹对应的是Electron编译所需的头文件(很奇怪为什么electron的头文件保存在iojs文件下,难道是因为Electron创建的时候是基于的分裂后的Node,也就是iojs吗?)
把下载的iojs.lib根据x86和x64保存在相应的文件夹下(如下图,文件夹手动创建),然后再次使用node-gyp重新编译,会发现自动使用缓存目录中的文件,不会再从网络下载了
我倒是觉得,更好的方式是在开发时锁定Electron版本,打包.node-gyp文件夹及.electron文件夹分发即可,免除网络方面的困扰,并且桌面应用可能没有那么高的框架更新需求,定期进行升级依赖版本即可
使用ffi模块加载DLL
安装ffi模块
cnpm install ffi --save
在根目录下创建一个test_load_dll.js
文件,我们先使用node调用ffi模块,并看一下输出
PcInfo.dll 是我随手找到的一个DLL文件,用来获取公司产品标识码,就不去生成个做加减法的DLL了,PcInfo.dll下载: PcInfo.dll
新建一个DLL目录,把它放在里面
var ffi = require("ffi")
var DLL = ffi.Library('dll/PcInfo.dll', {
'GetHylinkDeviceId' : ['string', []]
});
var result = DLL.GetHylinkDeviceId();
console.log(result)
这个代码不用多解释,声明了DLL有一个GetHylinkDeviceId函数,不传递参数,返回string类型
在cmd下运行node test_load_dll.js
,输出如下:
别慌,输出ERROR代表调用DLL成功了,因为在非指定设备上,比如个人PC电脑,输出就是ERROR
接下来在这个DEMO中引入DLL,先简单看一下目录结构
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
We are using Node.js <script>document.write(process.versions.node)</script>,
Chromium <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</body>
</html>
默认的index.html文件,之前运行demo的页面内容就是在这里定义的,下边是修改后引入DLL的index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<script>
var ffi = require("ffi")
var DLL = ffi.Library('dll/PcInfo.dll', {
'GetHylinkDeviceId' : ['string', []]
});
var result = DLL.GetHylinkDeviceId();
</script>
</head>
<body>
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
We are using Node.js <script>document.write(process.versions.node)</script>,
Chromium <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
<br />
<br />
Load PcInfo.dll <script>document.write("GetHylinkDeviceId: "+ result)</script>
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</body>
</html>
如果我们直接运行npm start
,看看会发生什么(使用Ctrl + Shift + I
打开调试页面)
报错信息:
E:\code\electron-project\electron-quick-start-master\node_modules\_bindings@1.3.0@bindings\bindings.js:96 Uncaught Error: Could not locate the bindings file. Tried:
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\build\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\build\Debug\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\build\Release\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\out\Debug\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\Debug\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\out\Release\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\Release\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\build\default\binding.node
→ E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\compiled\8.2.1\win32\ia32\binding.node
at bindings (E:\code\electron-project\electron-quick-start-master\node_modules\_bindings@1.3.0@bindings\bindings.js:93:9)
at Object.<anonymous> (E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\lib\ref.js:5:47)
at Object.<anonymous> (E:\code\electron-project\electron-quick-start-master\node_modules\_ref@1.3.5@ref\lib\ref.js:1465:3)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
基本上Uncaught Error: Could not locate the bindings file.
就说明是模块未编译的原因了,接下来重新编译ffi模块,以便electron使用
重编译原生Node模块
此处需要重新编译的有ffi和ref两个模块,命令如下(ref模块不需要手动安装,在安装ffi模块的时候就会自动安装ref)
cd node_modules\ffi
node-gyp rebuild --target=1.8.2 --arch=ia32 --dist-url=https://atom.io/download/electron
cd node_modules\ref
node-gyp rebuild --target=1.8.2 --arch=ia32 --dist-url=https://atom.io/download/electron
简单解释: target指明electron版本,arch表明想要重新编译成多少位的,ia32位x86平台,x64位64位平台,DLL位数,模块位数,Node.js位数应保持一致,否则会报错,dist-url指定了去哪里下载electron的头文件,可能这里你下载的很缓慢,去前边看看手动下载electron头文件的方法
显示ERROR,证明DLL已经调用成功
Uncaught Error: Dynamic Linking Error: Win32 error 126 报错为DLL未找到,遇到这个提示看看dll放的位置和html文件中引用的位置是不是不一致
接下来,或许你有闲暇时间可以试试运行这个demo:https://github.com/wzdxy/electron-ffi-demo
有了前边的基础,可以试着运行这个demo,我运行这个demo的时候遇到了一些小问题,可以尝试解决
1,提供的DLL是64位的,可以按照说明给出的代码编译一个32位的使用 2,package.json中指定的版本好都是1.7.11,如果安装依赖会安装1.8.2版本的electron,npm run rebuild-ffi 运行的命令中指定的1.7.11不匹配,所以应该修改package.json凡出现1.7.11的地方设置为当前electron版本(如:1.8.2)
有一个比较坑的地方是electron网上查询了解到只能使用C标准DLL而不能使用C++ DLL,我没进行测试,大家可以试试,另外Node.js 32位的版本只能引用x86的DLL,64位置能引用x64位的DLL,所以如果需要引入很多的三方DLL,也不是那么很方便,先这样,也许以后会有改善
配置electron与加载DLL的内容差不多就是这样,涉及到DLL的,以后会跟进并补充,下一篇记录一下打包electron应用,使其可以成为一个单独运行的exe,或者是一个可安装程序,先这样