说明:
本文的自动更新功能使用的项目为 electron-vue 脚手架搭建一个默认项目。
参考的文章如下:
开始:新建一个 electron 项目
首先你得有一个需要配置自动更新功能的 electron 项目。这里我为了测试自动更新功能是否成功搭建使用的是 electron-vue 脚手架搭建的项目。
搭建过程如下:
# 安装 vue-cli 和 脚手架样板代码 npm install -g vue-cli vue init simulatedgreg/electron-vue autoUpdataTest # 安装依赖并运行你的程序 cd autoUpdataTest npm install npm run dev
程序运行后的界面如下:
脚手架生成的文件结构:
|- autoUpdateTest |- .electron-vue # 压缩及运行环境的配置文件 |- build # |- icons # 图标文件 |- ... # 打包生成的文件在此处 |- dist # 用 webpack 压缩项目后生成的压缩文件在此处 |- node_modules |- src # 资源文件 |- main # 主进程 |- renderer # 渲染进程 |- index.ejx # 入口文件 |- static # 静态资源 |- .babelrc |- .gitignore |- .travis |- appveyor.yml |- package-lock.json # npm 自动生成的文件 |- package.json |- README.md
使用 electron-builder 最关键的配置在 package.json 里:(为了观察我们所需要的地方,把此篇文章里不需要关注的代码给删掉了。)
{ "name": "autoupdatetest", "version": "0.0.0", "author": "wonder", "description": "An electron-vue project", "main": "./dist/electron/main.js", "scripts": { "build": "node .electron-vue/build.js && electron-builder", "dev": "node .electron-vue/dev-runner.js", }, "build": { "productName": "autoupdateteset", "appId": "org.simulatedgreg.electron-vue", "directories": { "output": "build" }, "files": "dist/electron/**/*", "win": { "icon": "build/icons/icon.ico" } }, "dependencies": { }, "devDependencies": { } }
解析:
前四行是一般的 package.json 会有的:
name
— 项目名version
— 版本号author
— 开发人员及邮箱号description
— 项目描述 。下面重点看后面的内容:electron-builder详细配置文档
有关 electron-vue 的使用的更详细的说明请看 中文文档。
自动更新
安装依赖
自动更新功能的实现依赖 electron-builder
和 electron-updater
。
因为我们是用的electron-builder脚手架生成的项目,已经有 electron-builder
依赖了,所以只需要安装 electron-updater
。
# 目录 E:\GitHub\autoupdateteset npm i electron-updater --save # 必须安装为运行依赖,否则运行会出错
配置 package.json
为了配合打包 package.json 需要给 build 新增配置项:
"build": { "publish": [ { "provider": "generic", "url": "http://127.0.0.1:5500/" #这里是我本地开的服务器的地址 } ], ... }
主进程(参考:electron 中文文档)
主进程的入口文件是 src/main/index.js
。
import { app, // app 模块是为了控制整个应用的生命周期设计的。 BrowserWindow, // BrowserWindow 类让你有创建一个浏览器窗口的权力。 ipcMain } from 'electron'; // 引入自动更新模块 const { autoUpdater } = require('electron-updater'); // 不支持 ES6 则用如下方式引入 // const autoUpdater = require("electron-updater").autoUpdater const feedUrl = `http://127.0.0.1:5500/win32`; // 更新包位置 /** * Set `__static` path to static files in production * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html */ if (process.env.NODE_ENV !== 'development') { global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\'); } let mainWindow, webContents; const winURL = process.env.NODE_ENV === 'development' ? `http://localhost:9080` : `file://${__dirname}/index.html`; function createWindow() { /** * Initial window options */ mainWindow = new BrowserWindow({ height: 563, useContentSize: true, width: 1000 }); mainWindow.loadURL(winURL); webCOntents= mainWindow.webContents; mainWindow.on('closed', () => { mainWindow = null; }); } // 主进程监听渲染进程传来的信息 ipcMain.on('update', (e, arg) => { console.log("update"); checkForUpdates(); }); let checkForUpdates = () => { // 配置安装包远端服务器 autoUpdater.setFeedURL(feedUrl); // 下面是自动更新的整个生命周期所发生的事件 autoUpdater.on('error', function(message) { sendUpdateMessage('error', message); }); autoUpdater.on('checking-for-update', function(message) { sendUpdateMessage('checking-for-update', message); }); autoUpdater.on('update-available', function(message) { sendUpdateMessage('update-available', message); }); autoUpdater.on('update-not-available', function(message) { sendUpdateMessage('update-not-available', message); }); // 更新下载进度事件 autoUpdater.on('download-progress', function(progressObj) { sendUpdateMessage('downloadProgress', progressObj); }); // 更新下载完成事件 autoUpdater.on('update-downloaded', function(event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) { sendUpdateMessage('isUpdateNow'); ipcMain.on('updateNow', (e, arg) => { autoUpdater.quitAndInstall(); }); }); //执行自动更新检查 autoUpdater.checkForUpdates(); }; // 主进程主动发送消息给渲染进程函数 function sendUpdateMessage(message, data) { console.log({ message, data }); webContents.send('message', { message, data }); } app.on('ready', () => { createWindow(); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { if (mainWindow === null) { createWindow(); } });
渲染进程
渲染进程的入口文件是 src/renderer/index.js
。
这里我们主要修改 App.vue
,将原来的内容全删掉并使更新的整个周期在界面上打印出来。
- 生命周期过程展示
显示的界面如下:
自动更新过程简单介绍
1.将 webpack.json 里的版本号先改为 0.0.1,然后npm run build
生成一个版本为0.0.1的安装包。
注意上面一步会生成一个latest.yml
文件,autoUpdate 实际上通过检查该文件中安装包版本号与当前应用版本号对比来进行更新判断的。
latest.yml
文件内容如下:
2.然后将上一步生成的安装包放在本地开启的服务器文件夹下,对应你在主程序入口文件中配置的服务器位置。
3.将 package.json 中的版本号改回0.0.0,再npm run build
一遍,运行 build 文件夹下的 exe 安装包,就将软件安装在你电脑里面了。点击安装完成后桌面上的快捷方式,再次点击上面的获取更新的按钮就可以看到显示在界面的自动更新生命周期了。(但这里因为会给你直接自动更新,所以会一闪而过,你可以在 autoUpdate 的各个生命周期事件里设置主进程与渲染进程通信,则可以一步一步观察到整个自动更新的生命周期了。)
通过测试总结 autoUpdate 生命周期图
更新过程展示
1、无版本更新
2、有版本更新
点击取消后会先不更新,在应用关闭后更新:
点击确认后则会直接更新:
踩过的坑
1、主进程与渲染进程通信
最开始我是直接在主进程直接运行更新
然后想在渲染进程中打印主进程传过来的消息,但是发现只有 isUpdateNow 事件运行时才有日志显示。
结果发现原来主进程与渲染进程之间通信必须在渲染进程已经运行的时候(即那个界面完全显示出来)才能够进行。所以我将自动更新改为界面按钮触发,这样才能检测到自动更新的整个流程。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。