困扰多日的electron在windows系统下自动更新的问题,终于得到解决,以下是填坑过程。
此教程仅适用于以下条件,使用条件外的,例如使用别的打包方式,未必适用此教程,慎重!
1、系统:windows7 64位操作系统
2、使用electron-boilerplate-vue脚手架,其中electron为v1.2.1,vue为v1.0.25
3、使用electron-packager和grunt-electron-installer打包成安装文件,以及 Squirrel.Windows
4、请先安装vs2015,并配置系统变量,保证Squirrel.Windows的安装环境
教程开始
注:此文不适合electron新手,需要对electron有一定的了解,需清楚electron主进程、渲染进程之间的关系,需清楚electron怎么打包。
(以打包成windows64位安装包并自动更新为例)
------------->第一步:
首先确保你的项目已安装electron-packager,因为我们要使用electron-packager进行第一步的打包,若未安装请安装,并在项目根目录的package.json的script下有类似这条的命令,命令里要有版本号,具体命令书写要求请阅读electron-packager的说明。
参见下图橘色标注的
注意 package.json 的额外字段 —— productName、author 和 description,虽然这几个字段并不是打包必备的,但它们会在Squirrel.Windows中使用到。
满足以上要求后,在GitBash中执行 cnpm run-script packager64
执行完成后,会在项目根目录下生成一个文件夹OutApp(我在命令中要求的),文件夹里面的文件名称为Client-win32-x64(也是我在命令中要求的),双击文件Client.exe,如果可以正常运行,说明第一步的打包没有问题。
------------->第二步:
安装electron-squirrel-startup:
npm install electron-squirrel-startup
安装grunt-electron-installer:
npm install -g grunt-cli
npm install grunt grunt-electron-installer --save-dev
安装后,在项目根目录下建Gruntfile.js和gruntPackage.json,包含的代码分别为
Gruntfile.js:
var grunt=require('grunt');
//配置
grunt.config.init({
pkg: grunt.file.readJSON('gruntPackage.json'),
'create-windows-installer': {
x64:{
version:'1.0.0',
authors:'JXB-XL',
projectUrl:'',
appDirectory:'./OutApp/Client-win32-x64',//要打包的输入目录
outputDirectory:'./OutPut',//grunt打包后的输出目录
exe:'Client.exe',
description:'Client',
setupIcon:"./app/assets/icon/jxb.ico",
noMsi:true
}
}
});
//加载任务
grunt.loadNpmTasks('grunt-electron-installer');
//设置为默认
grunt.registerTask('default', ['create-windows-installer']);
配置内容详见grunt的官方文档
gruntPackage.json:
{
"name": "Client",
"version": "1.0.0",
"devDependencies": {
"grunt": "^1.2.0",
"grunt-electron-installer": "^2.1.0"
}
}
------------->第三步:
在你的主进程的js中添加以下代码,并调用函数
const electron = require('electron')
//自动更新
const autoUpdater = electron.autoUpdater
function startupEventHandle(){
if(require('electron-squirrel-startup')) return;
var handleStartupEvent = function () {
if (process.platform !== 'win32') {
return false;
}
var squirrelCommand = process.argv[1];
switch (squirrelCommand) {
case '--squirrel-install':
case '--squirrel-updated':
install();
return true;
case '--squirrel-uninstall':
uninstall();
app.quit();
return true;
case '--squirrel-obsolete':
app.quit();
return true;
}
// 安装
function install() {
var cp = require('child_process');
var updateDotExe = path.resolve(path.dirname(process.execPath), '..', 'update.exe');
var target = path.basename(process.execPath);
var child = cp.spawn(updateDotExe, ["--createShortcut", target], { detached: true });
child.on('close', function(code) {
app.quit();
});
}
// 卸载
function uninstall() {
var cp = require('child_process');
var updateDotExe = path.resolve(path.dirname(process.execPath), '..', 'update.exe');
var target = path.basename(process.execPath);
var child = cp.spawn(updateDotExe, ["--removeShortcut", target], { detached: true });
child.on('close', function(code) {
app.quit();
});
}
};
if (handleStartupEvent()) {
return ;
}
}
function updateHandle(){
ipc.on('check-for-update', function(event, arg) {
let appName='400电话系统';
let appIcon=__dirname + '/assets/jxb.ico';
let message={
error:'检查更新出错',
checking:'正在检查更新……',
updateAva:'下载更新成功',
updateNotAva:'现在使用的就是最新版本,不用更新',
downloaded:'最新版本已下载,将在重启程序后更新'
};
const os = require('os');
const {dialog} = require('electron');
autoUpdater.setFeedURL('放最新版本文件的文件夹的服务器地址');
autoUpdater.on('error', function(error){
return dialog.showMessageBox(mainWindow, {
type: 'info',
icon: appIcon,
buttons: ['OK'],
title: appName,
message: message.error,
detail: '\r'+error
});
})
.on('checking-for-update', function(e) {
return dialog.showMessageBox(mainWindow, {
type: 'info',
icon: appIcon,
buttons: ['OK'],
title: appName,
message: message.checking
});
})
.on('update-available', function(e) {
var downloadConfirmation = dialog.showMessageBox(mainWindow, {
type: 'info',
icon: appIcon,
buttons: ['OK'],
title: appName,
message: message.updateAva
});
if (downloadConfirmation === 0) {
return;
}
})
.on('update-not-available', function(e) {
return dialog.showMessageBox(mainWindow, {
type: 'info',
icon: appIcon,
buttons: ['OK'],
title: appName,
message: message.updateNotAva
});
})
.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
var index = dialog.showMessageBox(mainWindow, {
type: 'info',
icon: appIcon,
buttons: ['现在重启','稍后重启'],
title: appName,
message: message.downloaded,
detail: releaseName + "\n\n" + releaseNotes
});
if (index === 1) return;
autoUpdater.quitAndInstall();
});
autoUpdater.checkForUpdates();
});
}
------------->第四步:
执行grunt,在你指定的目录生成三个文件,exe文件是安装包,RELEASES包含安装及版本信息,nupkg文件目前还没搞懂。
到目前为止,1.0.0版本的安装文件已经搞定,双击exe文件后,弹出绿色的安装动画,无法选择安装目录,会自动安装在C:\Users\Administrator\AppData\Local下,安装结束后动画消失,并自动创建了快捷方式
------------->第五步:
到目前为止,低版本的桌面应用已打包并安装完毕,我把版本号写在了页面上,可以看到是1.0.0版本的
那么怎么更新到新的版本呢?
方法如下:
1、修改版本信息,包括Gruntfile.js、gruntPackage.json、package.json下面所有的版本信息,改为1.0.1,然后从第一步开始执行,直到第四步,获得1.0.1版本的三个文件(release、exe、nupkg)后,将这三个文件上传到放最新版本文件的文件夹的服务器地址,对的,这个就是对应的主进程js中的autoUpdater.setFeedURL(第三步中)。
2、重启1.0.0桌面应用,点击检查更新(这里,我使用了ipc,即渲染进程向主进程发送消息,主进程监听'check-for-update',即第三步中的ipc.on('check-for-update', function(event, arg) {}))。
3、分别弹出以下窗口:
点击现在重启,就会自动关闭1.0.0版本的,并打开1.0.1版本的,打开后发现,已经更新成功
再点击检查更新,会弹出
再打开安装目录,会发现多了一个1.0.1的文件夹
你可以在自动更新成功后,用node将之前的1.0.0文件夹删除。
自动更新结束!
原理
引用自https://github.com/Squirrel/S...
1、根据设置的setFeedURL路径,UpdateManager检查路径下的RELEASES文件,与安装目录下的RELEASES文件进行比对。
2、如果出现版本不同的情况,将下载路径中的更新包,下载完成后自动进行更新(包括修改快捷方式和清除旧版本)。
3、更新成功后,会保留上一个版本,并清除上一个版本之前的所有版本。
参考文章
从零开始使用Electron + jQuery开发桌面应用 (二) 打包应用https://segmentfault.com/a/11...
【译】Electron 自动更新的完整教程(Windows 和 OSX)https://segmentfault.com/a/11...
坑
1、开发阶段就进行检查更新,报错:Cannot find squirrel,这是因为此桌面应用没有安装,必须在安装后才能执行检查更新
2、桌面应用安装成功后,点击检查更新,报错:another instance is exist,这是因为首次安装后,一些安装文件还没有退出,所以尽量在安装完毕的一分钟后再检查更新。自动更新后不会有这个问题,仅发生在首次安装后。
3、你的exe文件名不能包含数字,否则也会报错。
4、一些同学说,安装后检查更新报错:Cannot find module ‘electron-squirrel-startup’,应该是没有安装Squirrel.Windows的原因,请先安装Squirrel.Windows,需要vs2015的环境(vs2015需要下载并安装,安装会占用C盘几个G的空间,请先保证C盘有足够空间。安装后请设置系统变量,即在Path下添加C:\Program Files (x86)\MSBuild\14.0\Bin)
5、更换了办公的电脑,系统变成win10,重新下载安装环境后发现,如果现有的项目版本高于服务器上的项目版本,就会自动更新失败,C盘的安装目录下的squirrel文件显示'local version is greater than remote version'