困扰多日的electron在windows系统下自动更新的问题,终于得到解决,以下是填坑过程。
此教程仅适用于以下条件,使用条件外的,例如使用别的打包方式,未必适用此教程,慎重!
1、系统:windows 64位操作系统
2、使用electron-boilerplate-vue脚手架,其中electron为v1.2.1,vue为v1.0.25
3、使用electron-packager和grunt-electron-installer打包成安装文件
(以打包成windows64位安装包并自动更新为例)
------------->第一步:
首先确保你的项目已安装electron-packager,因为我们要使用electron-packager进行第一步的打包,若未安装请安装,并在项目根目录的package.json的script下有类似这条的命令,命令里要有版本号,具体命令书写要求请阅读electron-packager的说明。
参见下图橘色标注的
满足以上要求后,在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; force_quit = true; autoUpdater.quitAndInstall(); }); autoUpdater.checkForUpdates(); }); }
------------->第四步:
执行grunt,在你指定的目录生成三个文件,exe文件是安装包,RELEASES包含安装及版本信息,nupkg文件目前还没搞懂。
到目前为止,1.0.0版本的安装文件已经搞定,双击exe文件后,弹出绿色的安装动画,无法选择安装目录,会自动安装在C:UsersAdministratorAppDataLocal下,安装结束后动画消失,并自动创建了快捷方式
------------->第五步:
到目前为止,低版本的桌面应用已打包并安装完毕,我把版本号写在了页面上,可以看到是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文件夹删除。
自动更新结束!
从零开始使用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文件中不能包含数字,否则也会报错。