前段时间,我用electron-vue开发了一款跨平台(目前支持Mac和Windows)的免费开源的图床上传应用——PicGo,在开发过程当中踩了很多的坑,不只来自应用的业务逻辑自己,也来自electron自己。在开发这个应用过程当中,我学了很多的东西。由于我也是从0开始学习electron,因此不少经历应该也能给初学、想学electron开发的同窗们一些启发和指示。故而写一份Electron的开发实战经历,用最贴近实际工程项目开发的角度来阐述。但愿能帮助到你们。html
预计将会从几篇系列文章或方面来展开:前端
PicGo
是采用electron-vue
开发的,因此若是你会vue
,那么跟着一块儿来学习将会比较快。若是你的技术栈是其余的诸如react
、angular
,那么纯按照本教程虽然在render端(能够理解为页面)的构建可能学习到的东西很少,不过在main端(electron的主进程)应该仍是能学习到相应的知识的。vue
若是以前的文章没阅读的朋友能够先从以前的文章跟着看。node
通过前面几篇文章的实战,我相信你们已经对于构建一个基本的electron应用没有太多的问题了。本文主要阐述一下如何让咱们的应用经过CI系统来自动帮咱们构建应用,而后发布给用户使用。以及以后若是有更新,要如何通知用户更新。react
固然,在此以前,咱们还须要作一件事:给你应用加上好看的LOGO。LOGO的设计和制做不在本文的设计范围内。为了咱们的应用可以跨平台地使用,不一样平台上应用的LOGO尺寸和格式也不尽相同。三个平台所需的图片格式以下:linux
准备一张1024*1024如下,256*256以上(长宽一致)的png图片,(推荐512 * 512)而后咱们能够用一些工具来实现从png到其余两种格式。搜索png转ico或者png转icns的话有不少在线转换的网站,能够去上面在线转换。在mac上我推荐用的是image2icon这个工具。ios
而后咱们将所得的三个图片文件,放到electron-vue项目根目录的build/icons/
目录下。git
本文咱们主要采用electron-vue已经配置好的基于electron-builder的构建脚原本进行咱们的应用构建。构建脚本会读取package.json
里的build
字段里的配置来进行构建。electron-vue默认的配置以下:github
"build": {
"productName": "ElectronVue",
"appId": "org.simulatedgreg.electron-vue",
"dmg": {
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"directories": {
"output": "build"
},
"files": [
"dist/electron",
"node_modules/",
"package.json"
],
"mac": {
"icon": "build/icons/icon.icns"
},
"win": {
"icon": "build/icons/icon.ico"
},
"linux": {
"icon": "build/icons"
}
}
复制代码
简单讲述一下build配置里的一些字段的含义。docker
首先productName
是你的应用的名字。appId
的做用是用于Windows平台区分应用的标识。(注意该配置必须配置,并且稍后会有使用该配置的地方。若是不配置不使用的话,构建出来的Windows平台的应用将没法发送eletron的桌面通知)dmg
这个配置里描述了macOS平台里,打开dmg
安装包后显示的界面里的信息。以下图:
表示了有两个标识,一个是应用文件,坐标是(130, 150)
, 一个是应用文件夹的快捷方式,坐标是(410, 150)
。
directories
的output
字段是你应用打包完生成的文件放置的目录。
files
指明了要打包的目录。
而mac
,win
,linux
是针对三个平台的不一样的配置了。能够看出默认的配置里对它们的配置都是指向了不一样的icon图标(也就是上一节所说的LOGO)。
PicGo在实际开发中,针对一些状况对默认的build
配置项作出了一些增改:
"build": {
"productName": "PicGo",
"appId": "com.molunerfinn.picgo",
"directories": {
"output": "build"
},
"files": [
"dist/electron/**/*"
],
"dmg": {
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"mac": {
"icon": "build/icons/icon.icns",
"extendInfo": {
"LSUIElement": 1
}
},
"win": {
"icon": "build/icons/icon.ico",
"target": "nsis"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true
},
"linux": {
"icon": "build/icons"
}
},
复制代码
因为PicGo在macOS上主要是一个顶部栏应用,因此在底部docker栏我并不想拥有一个占位的图标,因此在mac
字段里加入了:
"extendInfo": {
"LSUIElement": 1
}
复制代码
这个属性。参考相关issue。
在Windows平台上,默认打包出来的安装包并无办法选择安装的路径,只会默认装到C盘的用户目录。这个并非咱们想要的。咱们想要的是让用户本身选择安装的路径。
因此须要修改windows
的一些配置以及加上一个nsis
的配置来实现:
"win": {
"icon": "build/icons/icon.ico",
"target": "nsis"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true
}
复制代码
因为目前我尚未打包过Linux平台的应用,因此Linux相关的配置暂时先不作修改。
还记得前面说到的一个配置:appId
么,这个配置须要咱们在主进程index.js
里也要使用。不然打包后的应用将失去Windows平台的应用通知功能。这个appId
是能够任意取的,只要保证不和其余应用重复便可。对于PicGo而言,appId
是com.molunerfinn.picgo
。
打开你的main/index.js
,在Windows平台的时候加上这个appId
:
// ...
import pkg from '../../package.json'
// ...
// ...
if (process.platform === 'win32') {
app.setAppUserModelId(pkg.build.appId)
}
复制代码
这样就解决了通知的那个问题。
发布应用实际上是一个比较繁琐的活,每每跟你的版本控制绑在一块,因此一般在项目开始的阶段就要有所布局。我说说个人作法吧,不必定很科学,不过简单易行。
其中简单的更新版本的脚本我是在package.json
里写了简单的scripts
:
"scripts": {
"patch": "npm version patch && git push origin master && git push origin --tags", // 小版本
"minor": "npm version minor && git push origin master && git push origin --tags", // 次版本
"major": "npm version major && git push origin master && git push origin --tags" // 大版本
}
复制代码
里面用到了npm的一个命令,npm version [options]
,具体能够参考version的文档。简单来讲,它可以自动帮你升级版本,修改package.json
里的version,并打上相应的git tag,很方便。
举个例子,一个符合语义的版本号一般由以下三个部分组成:major.minor.patch
,好比1.5.3
。若是我运行了npm run patch
,那么将会将小版本更新:1.5.4
,同时修改package.json
里的version
字段为1.5.4
并自动打上一个git tag 1.5.4
,并将这个修改和tag推送到远端。
不过须要注意的是,一开始我是经过electron-vue自带的npm run build
这个脚本让CI去执行构建,可是发现没法自动上传到GitHub的release里。因此经过查阅相关资料后,发现最简单的就是把对应的npm scripts命名为release
。因而我把本来的npm run build
的脚本复制了一遍,起了一个新名release
:
"scripts": {
// ...
"release": "node .electron-vue/build.js && electron-builder",
// ...
}
复制代码
说到这里都还没说到CI系统。什么是CI?能够参考阮一峰老师给出的解释《持续集成是什么?》。咱们若是每次发布应用都须要咱们在本地构建,而后手动上传到GitHub(或者其余地方)去,而后让别人能下载的话,未免太累了。并且一般咱们开发electron应用就是为了可以跨平台,可是要构建不一样的平台的应用意味着咱们要在不一样的平台分别构建。这也是不能忍受的。
因而网上有一些第三方的CI系统,它们可以帮咱们,在某些分支(好比master)发生了某些更新(好比更新了tag)的时候帮咱们执行某些脚本(好比构建、测试)。这样就省却了咱们在本地、多平台构建的烦心事,并且让一些都变得「自动化」了起来。
有了CI以后,个人electron应用的发布就变成这样的流程了:
这样,咱们只须要Push代码足矣。
针对Linux或者macOS的构建,咱们可使用Travis-CI,针对Windows平台的构建,咱们可使用AppVeyor。一个好消息是,它们对于在GitHub上的开源项目都是能够免费构建的,而且和GitHub的仓库结合地特别好,配置也比较简单,能够说的很是良心了。
在使用它们以前,咱们须要给予它们必定的权限让它们可以访问咱们的GitHub仓库。因此须要:
.travis.yml
和AppVeyor的配置文件模板appveyor.yml
。因此咱们基本上只须要在它们的基础上小修改便可。注册并登陆Travis-CI后,找到你要构建的仓库,而后打开,点击设置进入以下页面:
配置一下环境变量,名为GH_TOKEN
,token的值就是上一步咱们在GitHub生成的token。等会会有用。
PicGo通过修改后的.travis.yml
以下:
# Commented sections below can be used to run tests on the CI server
# https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing
osx_image: xcode8.3
sudo: required
dist: trusty
language: c
matrix:
include:
- os: osx
# - os: linux
env: CC=clang CXX=clang++ npm_config_clang=1
compiler: clang
cache:
directories:
- node_modules
- "$HOME/.electron"
- "$HOME/.cache"
addons:
apt:
packages:
- libgnome-keyring-dev
- icnsutils
before_install:
- mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v1.2.1/git-lfs-$([
"$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-1.2.1.tar.gz
| tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull install:
- nvm install 8.9
- curl -o- -L https://yarnpkg.com/install.sh | bash - source ~/.bashrc - npm install -g xvfb-maybe - yarn script:
- npm run release
- yarn run build:docs
branches:
only:
- master
after_script:
- cd docs/dist
- git init
- git config user.name "Molunerfinn"
- git config user.email "marksz@teamsz.xyz"
- git add .
- git commit -m "Travis build docs"
- git push --force --quiet "https://${GH_TOKEN}@github.com/Molunerfinn/PicGo.git" master:gh-pages
复制代码
抛去不少前置依赖(好比C++编译库之类的)和构建环境(是什么系统,是什么语言),那些都是electron-vue给咱们预置好的。咱们须要注意的仅仅是几个部分:
script
是当系统和环境和依赖都准备好以后,你要CI运行的命令。在这里我运行了两个命令,一个是npm run release
,这个就是打包构建应用啦,而且执行了这个命令以后,electron-builder
会自动将生成好的安装包推送到咱们GitHub仓库的draft release里。另外一个是构建PicGo主页的命令yarn run build:docs
。
branches
声明了你要在哪些分支在GitHub接收到了代码更新以后就构建,这里咱们天然选择的是master。
after_script
是当你执行完script里的脚本以后要作的事。能够为空。对于我而言主要在这个部分将上一步构建好的PicGo主页推送到GitHub的gh-pages
分支。固然若是你的应用有使用说明、文档之类的网站,也能够在这里进行构建和推送。
注意到,在after_script
命令的最后一行,有个${GH_TOKEN}
,这个就是咱们以前在Travis-CI配置里配置的环境变量GH_TOKEN
。用环境变量的好处是不会暴露你的TOKEN,只有构建系统知道。
有了以前的经验,AppVeyor就更简单了。注册登陆后,咱们在主页添加一个PROJECT,选中你要构建的仓库。而后找到SETTING设置:
而后在左侧的Genral
一栏的内容区中,找到构建的分支为master,以及设置咱们仅在tag
更新的时候构建:
固然这个都是根据项目实际来的配置,我只是说PicGo的项目是这样配置的。
而后在左侧的Environment
区,找到环境变量配置,咱们依然写入GH_TOKEN
:
修改完配置都别忘了拉到底部去保存!
这样就算配置完了网页端的。而如今咱们来看看appveyor.yml
这个配置文件:
# Commented sections below can be used to run tests on the CI server
# https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing
version: 0.1.{build}
branches:
only:
- master
image: Visual Studio 2017
platform:
- x64
cache:
- node_modules
- '%APPDATA%\npm-cache'
- '%USERPROFILE%\.electron'
- '%USERPROFILE%\AppData\Local\Yarn\cache'
init:
- git config --global core.autocrlf input
install:
- ps: Install-Product node 8 x64
- git reset --hard HEAD
- npm install
- node --version
build_script:
#- yarn test
- npm run release
test: off
复制代码
依然是只须要关注咱们所关心的配置便可。一个是branches
,一个是build_script
。有了Travis-CI
的.travis.yml
的经验,我相信你也能很快理解它。
通过上述配置以后,你已经实现了一个简单的前端工程的自动化构建推送流程了。而今你只须要关注代码提交,应用的构建都将会由CI系统自动帮你完成。固然CI系统也不只仅是拿来构建electron应用的,正如你所见的,你能想到的其余项目的构建、测试其实它都能帮你经过预约义好的脚本完成。
当CI构建玩应用,会将其推送到你的GitHub的release页面成为一个draft
(草稿),你能够编辑这个草稿,加上标题和更新说明,就能够点击publish
发布你的新版本的应用啦。
electron应用的自动更新其实社区有很好的解决方案electron-updater。而electron-vue也在主进程的main/index.js
里预先帮咱们写好了一段注释的代码:
// import { autoUpdater } from 'electron-updater'
// autoUpdater.on('update-downloaded', () => {
// autoUpdater.quitAndInstall()
// })
// app.on('ready', () => {
// if (process.env.NODE_ENV === 'production') {
// autoUpdater.checkForUpdates()
// }
// }
复制代码
只要引入autoUpdater就能自动帮咱们检查更新和自动下载安装更新。不过,凡事都有不过。这个方式虽然很简单,可是它须要的条件比较严格,须要你拥有证书用于应用签名。而macOS平台下的证书须要你申请开发者,一年99$的费用让我望而却步。
因而我只能退而求其次,能不能经过查询GitHub的release版本号,来比对当前版本,是否须要更新,并提醒用户呢?通过尝试,发现可行。个人实现方法以下:
我首先写了一个updateChecker
的助手:
import { dialog, shell } from 'electron'
import db from '../../datastore'
import axios from 'axios'
import pkg from '../../../package.json'
const version = pkg.version
const release = 'https://api.github.com/repos/Molunerfinn/PicGo/releases/latest'
const downloadUrl = 'https://github.com/Molunerfinn/PicGo/releases/latest'
const checkVersion = async () => {
let showTip = db.read().get('picBed.showUpdateTip').value()
if (showTip === undefined) {
db.read().set('picBed.showUpdateTip', true).write()
showTip = true
}
// 自动更新的弹窗若是用户没有设置再也不提醒,就能够去查询是否须要更新
if (showTip) {
const res = await axios.get(release)
if (res.status === 200) {
const latest = res.data.name // 获取版本号
const result = compareVersion2Update(version, latest) // 比对版本号,若是本地版本低于远端则更新
if (result) {
dialog.showMessageBox({
type: 'info',
title: '发现新版本',
buttons: ['Yes', 'No'],
message: '发现新版本,更新了不少功能,是否去下载最新的版本?',
checkboxLabel: '之后再也不提醒',
checkboxChecked: false
}, (res, checkboxChecked) => {
if (res === 0) { // if selected yes
shell.openExternal(downloadUrl)
}
db.read().set('picBed.showUpdateTip', !checkboxChecked).write()
})
}
} else {
return false
}
} else {
return false
}
}
// if true -> update else return false
const compareVersion2Update = (current, latest) => {
const currentVersion = current.split('.').map(item => parseInt(item))
const latestVersion = latest.split('.').map(item => parseInt(item))
let flag = false
for (let i = 0; i < 3; i++) {
if (currentVersion[i] < latestVersion[i]) {
flag = true
}
}
return flag
}
export default checkVersion
复制代码
而后在main/index.js
里,我在app准备启动的时候,调用这个更新助手:
// ...
import uploader from './utils/uploader.js'
app.on('ready', () => {
// ...
updateChecker()
// ...
})
复制代码
这样就能在启动应用的时候弹出更新提示:
本文简要地讲述了electron应用用上CI系统帮咱们自动化构建和推送,以及在没有申请开发者,没有证书用于应用的代码签名的状况下如何告知用户进行应用更新。要作一个健壮的应用就应该考虑到应用的版本发布、版本更新和对用户的更新通知。
本文不少都是我在开发PicGo
的时候碰到的问题、踩的坑。也许文中简单的几句话背后就是我无数次的查阅和调试。但愿这篇文章可以给你的electron-vue
开发带来一些启发。文中相关的代码,你均可以在PicGo的项目仓库里找到,欢迎star~若是本文可以给你带来帮助,那么将是我最开心的地方。若是喜欢,欢迎关注个人博客以及本系列文章的后续进展。
注:文中的图片除未特意说明以外均属于我我的做品,须要转载请私信