用Electron做个伪桌面应用~

讲道理这是篇鸽了一年多的技术分享…最早接触Electron的时候还是0.3x版本,转眼已经1.6.2……

在国内All in mobile的风气下谈论桌面客户端开发似乎是个很非主流的行为,但是作为JavaScript在桌面端伸出的利爪,Electron不仅仅是桌面客户端开发的一个技术选型,也有着其独特的象征意义~

本文主要介绍Electron的应用结构、开发方式以及优缺点。在重温Electron开发的过程中写了个山寨的网易云音乐,这是demo地址

最早听说Electron还得从大三时说起,当时有几个浙大学弟用Electron + React + CoffeeScript做了一个舰娘浏览器,作为前舰狗当然下载试玩了一波感觉体验还不错,最关键的是当时这个应用有Linux(Ubuntu)版本,体验和windows端无太大差别。

后来学习了一波开发姿势,在实习公司hackday上做了个内部IM应用的半成品,捞了个三等奖hhhh…

言归正传…

Electron是什么

Github出品的跨平台桌面应用开发工具。

说白了就是剥离Chromium内核拿来写桌面应用,应用的大部分UI就是web页面,也就是我们前端熟悉的dom. 交互逻辑全部是js,样式还是css写,相当于给用户一个浏览器去渲染应用……看到这里想必读者老爷会骂娘(这不就是web么?要这么折腾还不如直接写个网页)

Electron的本质目的还是利用js构建跨平台的桌面端应用,个人认为它的使用场景主要是一些需要原生功能支持、有离线使用需求、迭代速度较快、对下载安装不太敏感同时桌面端开发人员不足的项目。Electron不仅仅是个“浏览器”,它也封装了一些原生系统的功能,提供给js开发者,比如可以简单地使用js定制不同系统的菜单栏、应用图标、任务栏,控制应用窗口的大小和位置,调用本地的程序等。相比web应用,开发者摆脱了来自浏览器的限制、并可以间接地和原生打交道。

目前基于Electron最著名的桌面端应用是: Atom编辑器VS Code编辑器SlackPostman桌面版Wordpress桌面版等等,基本上都是国外公司在使用。

Electron源于Gihub开发Atom的技术选型,Atom开发初期使用的Cococa原生的开发方式;后来使用了node-webkit(后面略称NW,也是使用浏览器渲染开发的方式);之后由于一些技术限制(如多窗口支持和性能原因)决定自行开发一套开发工具,即Electron。Electron最主要的贡献者也是目前的维护者是工作于Github的国人(国人骄傲~),关于他和NW的爱恨情仇这里略过不谈……

Electron原理

从分享的keynote里面截了一张图过来(keynote下载地址):

Electron运行时分为两个进程:主进程和渲染进程。主进程是启动app时创建的,主要负责app如何调用原生、如何创建并管理新窗口(页面)以及各种和原生相关的逻辑,可粗略理解为跑了个node;渲染进程负责所有页面的绘制(使用Chromium内核)、及其前端js的解析和运行,粗略理解为“前端”。两个进程通过ipc(跨进程交互)通信,窗口之间可以有附属关系,也可以使用消息机制互相通信。

Electron帮开发者完成和原生的连接,和现在Facebook推出的React Native一样,开发者所需要做的无非是阅读文档、通过js调用封装好的接口,无需直接和原生打交道(写原生代码)

Electron开发的诱惑

谈谈开发时感觉很棒的几点以及注意事项:

  • 渲染进程中的页面js运行环境实际上是结合了node环境和浏览器环境

直接可以使用node相关api和第三方库,例如require('child_process')require('request')

需要注意的是require('electron')在不同进程(主进程/渲染进程)中暴露的API是不一样的,具体看文档,例如BrowserWindowipcMain是主进程特有的API

  • 进程间的交互可以使用ipc或者remoteAPI

前端的逻辑可以使用进程间通信传递给app主进程,可以做一些类似原生应用才有的交互,如改变窗口、消息框提醒、任务栏变化。

渲染进程可以使用remoteAPI调用一些主进程才有的API,例如remote.BrowserWindow,可不用ipc完成进程间的通信(比如页面上点击一个按钮后,使用remote隐藏掉当前窗口)

注意事项:最好统一管理ipc,避免信号重复;ipc监听过多时复杂的逻辑和时序问题需要考虑。

  • 没有跨域

前端的各种跨域对于初级开发者来说简直是一个噩梦,然而因为有node的存在,摆脱了浏览器的束缚,请求可以用各种姿势完成。

  • 兼容性 & Write once, run every where

因为本身UI是浏览器产出的,各个平台同用的Chromium,不需要考虑兼容性问题,浏览器前缀也只保留-webkit即可。用js写的逻辑基本上直接打包编译一波就能在windows/linux/mac三端安装使用。

在开发时真正需要注意的是“跨平台兼容性”,不同的功能可能在不同平台上实现不同,或者未完全实现。这个时候就需要做一些妥协和让步,或者使用一些tricky的方法让大家保持一致。大部分问题活跃的社区都能给出方案~

  • 简单地实现很“Native”的功能

用最近做的山寨云音乐举几个例子(目前只针对mac版开发)

栗子1.利用node-notifier定制系统提醒

当然也可以直接选择使用HTML5的 Notification API,不过相对来说用这个第三方模块可定制性会更高,而且多平台兼容性也不错。

至于如何定制弹框的icon,可以看这个issue里@mbushpilot2b提供的解决方案。

栗子2.利用MenuAPI定制程序的菜单栏和快捷键

栗子3.利用remoteAPI在渲染进程中定义鼠标右键菜单

web开发中我们写的右键菜单肯定是dom模拟的,但这里我们可以用js简单地写出原生的菜单,并且能有一定的层级。

栗子4.自定义窗口

这个例子是主窗口缩小成迷你播放器并开启歌词窗口(歌词窗口可以设置成常驻最顶层,不被其他应用窗口覆盖)

仔细观察上面的截图可以发现,窗口中使用了mac原生的毛玻璃模糊效果。而且和一般mac程序的窗口不同,没有顶部栏。


简而言之,好好读文档,随着Electron社区对项目的迭代,各种原生的功能触手(js)可及。

  • 热更新

这个热更新和前端开发时避免疯狂刷新页面不同,是应用的热更新。桌面应用被web应用不断替代的原因便是更新速度的缓慢及繁琐,web页面的上线便是开销非常小的“客户端更新”,用户几乎没有感知到文件变化(如css/js/html缓存失效重新加载)带来的延迟,保证了较好的体验。

不过这里说的也不是在Electron中使用一个远程url渲染页面的方式(尽管这是可行的),而是整个应用的逻辑更新。Electron自带的auto updater按文档的意思是可以根据Github的release包自动更新应用,具体使用暂时没有经验……不过我的Atom编辑器确确实实无痕地在升级。

Electron的打包发布

在整个项目打包前,要做的是对主进程和渲染进程代码的打包、压缩、混淆,这里可以使用webpack之类的工程化工具。

而后真正打包成应用时需要结合Electron的内核。目前有两种方式:一种是使用electron-packager,直接打包成可运行的程序,基本在100mb+(体积相对正常原生应用偏大,主要是内核的原因);另一种是使用electron-builder制作压缩安装包,可以打成deb/msi/dmg等格式,基本40mb+,不过electron-builder的文档真心非常非常烂,折腾了好久才配置出来(连一个完整示范和配置项对象的结构都没注明)

我目前是两者都在使用,一个打包一个压缩。

End

没打算贴代码教程,文档上对API的功能介绍得比较详细,入门级别的例子google上也能搜到不少。需要注意的是一些文章中借用第三方实现的功能可能已经被Electron支持,推荐还是使用官方的做法。

想看云音乐的开发demo可以到Github上下载、build、然后安装,不过仍在开发中。