之前发过一个装逼的朋友圈:感谢 Electron,我现在有两个身份了:前端开发和 Mac 端开发。

今年开始了一个全新的产品,但项目组并没有 Mac 的开发人员,然后我们前端就顺利的扛下了这面大旗,并且选择了火爆的 Electron(4w+ star)。

年底了,看大家在写各种各样的年终总结,想着我和 Electron 也打情骂俏了好几个月,也该写点东西。不过 Electron 已经够火了,能 google 到很多类似如何使用 Electron 开发桌面端应用的文章,比如用Electron开发桌面应用,也能找到官方中文文档,虽然滞后了一点。所以我也就不再赘述怎样从头写一个 Electron 应用了,在阅读下面的内容之前,最好能先跟随官方的 Quick Start 走一遍。

为什么选择 Electron

Electron提供了一个Nodejs的运行时,专注于构建桌面应用,同时使用web页面来作为应用的GUI,你可以将其看作是一个由JavaScript控制的迷你版的Chromium浏览器。

够火自不必说,Electron 的作者和 NW.js(原 node-webkit)是同一人,大家可以去知乎围观维护一个大型开源项目是怎样的体验?这个问题下作者的回答。官方也有 Electron 和 NW.js 的对比,相信作者在新的项目中有了新的思考,所以选择 Electron 是个对的选择,并且我们只需要开发 Mac 端(组内有 Windows 开发人员),没有对 XP 系统兼容的要求。

也有考虑过像 MacGap 这样的解决方案,不过 MacGap 是基于 webkit 内核的,并不支持 IndexedDB,而我们的项目依赖的第三方服务是依赖 IndexedDB 做为本地存储的。并且 Electron 更强大,比如新开 webview 加载第三方页面,并且可以预加载(preload) JavaScript来作为 jssdk 供 web 应用使用。

所以 Electron,就是你了!

主进程和渲染进程

个人感觉,理解 Electron 最重要应该就是理解主进程(Main Process)和渲染进程(Render Process)了。理解了这两者,其他内容花费些时间查查API文档即可。

Electron 中,入口是一个 js 文件(和 NW.js 不同,入口是 html 文件),运行这个入口文件(通常会是 package.json 里的 main 脚本)的进程称作主进程,在主进程使用 BrowserWindow 模块可以创建并管理 web 页面,也就是应用的 GUI。

const {BrowserWindow} = require('electron')
// 主进程创建web页面
let someWindow = new BrowserWindow(winOpts)
// 加载本地的文件
someWindow.loadURL('file://' + __dirname + '/index.html')

在主进程创建的一个个web页面也都运行着自己的进程,即渲染进程,渲染进程各自独立,各自管理自己的页面,可以想象是浏览器一个个的 tab。

进程间通信

我们知道,Web 页面因为安全限制,不能直接访问原生的GUI资源(比如dialog、电源监控),Electron 中也是一样,渲染进程如果想要进行原生的GUI操作,就必须和主进程通讯,请求相应的GUI操作。

Electron 提供了几种渲染进程和主进程通信的方式:

一种是使用ipcMain和ipcRenderer模块,在渲染进程中使用ipcRender模块向主进程发送消息,主进程中ipcMain接收消息,进行操作,如果还需要反馈,则通知渲染进程,渲染进程根据接收的内容执行相应的操作:


// 渲染进程中
const {ipcRenderer} = require('electron')
ipcRender.send('somemsg', data);
ipcRender.on('replaymsg', (evt, otherData) => {console.log(otherData)
})// 主进程中
const {ipcMain} = require('electron')
ipcMain.on('somemsg', (evt, data) => {console.log(data)evt.sender.send('replymsg', otherData);
});// 同时Electron 也提供了同步的方式

不过切忌用 ipc 传递大量的数据,会有很大的性能问题,严重会让你整个应用卡住。

第二种是直接在渲染进程使用remote模块,remote 模块可以直接获取主进程中的模块。这种方式其实是第一种方式的简化。

// 在渲染进程打开提示对话框
const {dialog} = require('electron').remote
dialog.showMessageBox({ opts });

第三种是主进程向渲染进程发送消息

this.webviewWindow.webContents.send('ping');

第四种是渲染进程之间的通信

如果数据不需要实时性,只是渲染进程之间数据的共享,那么使用官方的建议即可:How to share data between web pages?。如果要求实时性,需要配合前几种种方式实现。

// 主进程
// 两个窗口互相获取对方的窗口 id, 并发送给渲染进程
win1.webContents.send('distributeIds',{win2Id : win2.id
});
win2.webContents.send('distributeIds',{win1Id : win1.id
});// 渲染进程
// 通过 id 得到窗口
remote.BrowserWindow.fromId(win2Id).webContents.send('someMsg', 'someThing');

Nodejs集成

Electron 内集成了 Nodejs,大大的方便了开发。Nodejs 在主进程和渲染进程中都可以使用,上面说到,渲染进程因为安全限制,不能直接操作原生 GUI。虽然如此,因为集成了 Nodejs,渲染进程也有了操作系统底层 API 的能力,Nodejs 中常用的 Path、fs、Crypto 等模块在 Electron 可以直接使用,方便我们处理链接、路径、文件MD5等,同时npm还有成千上万的模块供我们选择。

尤其对于 Electron 不方便实现的功能,Nodejs 可能有奇效。我们应用中用户需要下载文件消息的文件,需要支持同事下载多个,并且需要给出进度,Electron 并没有提供一个好用的下载接口,所以我们使用 Nodejs 的 http、fs 模块结合 Electron 的 dialog 模块实现了文件下载,并且实现了下载进度以及下载超时错误提示。

HTML5增强

不考虑兼容性应该是前端码农的梦想之一吧。Electron 使用 Chromium 来展示 web 页面,也就是我们开发只需要兼容 Chromium 浏览器即可,也就是说好多属性可以肆无忌惮的用:播放语音直接使用 HTML5 audio、大量数据存储使用数据库 IndexedDB、难搞的布局直接使用 Flexbox、方便的检测在线离线等等。

同时 Electron 对一些 HTML5 的特性进行了增强:
* 桌面通知,你可以直接使用 html5 的 notification,Electron会将其转化成为系统原生的桌面通知;
* File 对象,在Web应用中我们能得到的一般是类似 C:/fakePath/xxx.docx 的假路径,Electron在 File 对象上增加了一个path属性,可以用来获取选择的文件在文件系统中的真实路径。
* a 标签的 download 属性,在 Web 应用中 a 标签增加 download 属性会强制浏览器下载,Electron 中会直接调起系统下载框下载,如果没有特殊需求推荐这种方式。

渲染进程调试和在浏览器中的调试完全一致。前面提到每个渲染进程完全独立,当你创建了多个web页面,每个页面都可以打开对应了调试工具,你可以和浏览器调试一样查看DOM、查看log、监听网络请求等等。
同时 Electron 集成了 Nodejs,所以你在控制台或者断点时也能够调试 Nodejs 的 API,甚至因为渲染进程可以使用 remote 模块直接使用主进程的模块,你可以直接获取到这些数据以方便调试。

Electron 中的 Webview

这次的新产品有一个需求,需要在客户端内加载 Webview 应用,并且要提供 jssdk 供 Web 应用使用,以获取更多的本地能力。其实 Electron 天然的优势可以加载外部应用的。但是要考虑的问题还是比较多的,比如要展示页面加载的进度、监听页面何时加载完成、页面 DOM 何时加载完成、服务端一些302重定向如何(比如一些跳转认证)处理、如何给 Web 应用提供 jssdk 等等。

Electron 提供了一系列的事件来监听页面的加载,细化到了页面开始加载、页面加载完成、页面加载失败、DOM Ready、框架加载 (did-frame-finish-load)、重定向(did-get-redirect-request)等等,通过监听这些事件可以对页面状态进行处理。

另外,如何给 Web 应用提供 jssdk 呢?我们需要依赖 BrowserWindow 的一个配置项 - preload,preload 允许你指定一段脚本在页面加载之前载入,这段脚本你可以使用 Electron 和 Nodejs 的 API,即使你在配置中不允许使用 Nodejs。


// preload 示例
var opts = {autoHideMenuBar: true,fullscreenable: false,webPreferences: {javascript: true,plugins: true,nodeIntegration: false, // 不集成 NodejswebSecurity: false,preload: path.join(__dirname, 'preload/window_sdk.js') // 但预加载的 js 文件内仍可以使用 Nodejs 的 API}
}this.webviewWindow = new BrowserWindow(opts);

预加载 js 文件与其他 js 并无二致,你只要根据你的业务,在 preload 的 js 中使用 remote 或者 ipc 通信给你的 Web 应用提供够用接口就好了。

写在后面

Electron 并不是很复杂,在写完不多的主进程代码后,其他的业务代码几乎和 Web 应用没什么区别,甚至可以将一个线上应用迅速的包装成为一个客户端应用,比如electronic-wechat、worktile桌面端。
不过坑不可避免(比如无法将 gif 写入剪切板等等),有时候也会感到很难像 Native 那样灵活,虽然如此,我还是很欣慰能有这样的工具,让我们前端可以做更多的事情。

最后多说一句:虽然Electron 的进程间通信很方便,而且支持多窗口,但我还是倾向于使用 Electron 构建单窗口应用,类似网易云音乐、Atom 等等,更简洁,思维方式上更像我们熟悉的 web 应用。

小广告

小前端FE博文的首发地址:http://blog.smallsfe.com
另外,欢迎我们的微信公众号:小前端FE(smallsfe)

我眼中的 Electron相关推荐

  1. Electron 主进程、渲染进程及进程间的通信

    简介 Electron是由GIthub开发,用HTML.CSS.JS来构建跨平台桌面应用程序的一个开源库.Electron将Chromium和Nodejs合并到同一个运行时环境中,并将其打包为Mac. ...

  2. Electron、QT和JAVA PC桌面开发技术比较

    近几年PC桌面开发越来越多的被Electron,QT和Java技术占领.下面简单比较一下它们的优劣. Electron,势是开发用时快,社区轮子多,整合一下就能用.缺点是打包大,js计算弱. Java ...

  3. electron调用python_在Electron app中运行python脚本

    asar Whether to package the application's source code into an archive, using Electron's archive form ...

  4. 【亲测可用】用Electron和electron-builder打包Vue项目为exe可执行文件安装包(不推荐,个人觉得没有VNISEdit和NW好用,而且有些配置文件还挺脑残!)

    官方帮助文档http://www.electronjs.org/docs 有时候运行安装依赖包会很慢建议在(c)npm config edit之后弹出的.(c)npmrc记事本里面加入 electro ...

  5. 使用Rust + Electron开发跨平台桌面应用 ( 一 )

    前言 近段时间学习了Rust,一直想着做点什么东西深入学习,因为是刚学习,很多地方都不熟悉,所以也就不能拿它来做编译器这些,至于web开发,实际上我并不建议拿这个来学习一门语言,大概有几个方面,一是w ...

  6. 程序媛眼中的程序猿原来是这样子的!

    2019独角兽企业重金招聘Python工程师标准>>> 一直都想写一篇关于描述程序员的文章,但是一直没能开头,一来因为文笔不好,更主要的原因是貌似对程序员既熟悉又不熟悉,很怕写出来的 ...

  7. electron打包可选择安装位置,可自动更新

    Electron打包调参软件(windows版) ----------------------------------可选安装位置,可自动更新,手动更新 一:引包:electron,electron- ...

  8. electron.js_在使用Electron.js之前我希望知道的事情

    electron.js In this article, I'll share how you can avoid some of the mistakes I made when learning ...

  9. 学习使用React和Electron一次构建自己的桌面聊天应用程序

    by Alex Booker 通过亚历克斯布克 学习使用React和Electron一次构建自己的桌面聊天应用程序 (Learn to build your own desktop chat app ...

最新文章

  1. Django连接数据mysql
  2. 【控制】《多智能体机器人系统信息融合与协调》范波老师-第6章-基于分布式强化学习的多 Agent 协调方法
  3. 求100以内的素数c语言_100万以内的四胞胎素数166组
  4. springboot(七) 配置嵌入式Servlet容器
  5. 数据结构是如何装入 CPU 寄存器的?
  6. Nginx-ingress部署及使用
  7. 小学奥数_7829神奇序列求和 python
  8. idea通过数据库生成实体类插件_idea数据库生成实体类
  9. MySQL复制 自动监控脚本
  10. vim常用命令(二)
  11. 阶段2 JavaWeb+黑马旅游网_15-Maven基础_第5节 使用骨架创建maven的java工程_16maven工程servlet实例之jar包冲突...
  12. mysql概念模型中的3种基本联系_数据库建模三步骤:概念模型
  13. 净资产收益率ROE连续3年超过15%的股票排名
  14. PCIe Expansion Roms
  15. 单8通道数字控制模拟电子开关CD4051
  16. 第2关:求解出n以内所有能被5整除的正整数的乘积-------C语言程序设计技术(循环结构程序设计1)
  17. 解决AS升级3.4 ERROR: All flavors must now belong to a named flavor dimension.Learn more at https://d.and
  18. ECharts 地图绘制
  19. 用计算机程序实现离散化的对象模型,模糊PID应用
  20. [4G5G专题-30]:物理层-基带无线资源、物理层帧结构、无线资源调度

热门文章

  1. 使用虚拟机中Inter VT-x处于禁用状态的解决办法
  2. android开发工具简介及下载地址
  3. Java面试-String、StringButtfer和StringBuilder之间的区别
  4. 谷歌推出Android开发工具Android-Studio
  5. 阳康后为啥心累心慌?解答来了!
  6. kafka启动Initial heap size set to a larger value than the maximum heap size报错(windows系统)
  7. 【防止恶意用户注册】-- 手机在网状态 API 的防欺诈应用解析
  8. 从产品经理的角度算一算,做一个 APP 需要多少钱
  9. jfreechart java配置_JFREECHART环境安装配置
  10. Win32-进程锁-进程异步-进程互斥-CreateMutex-OpenMutex-WaitForSingleObject-ReleaseMutex