предисловие
Недавно помогал компании разрабатывать десктопные приложения.Выбирал из NW.js и Electron,и в итоге остановился на Electron.Ничего особо сложного.Vue scaffolding+vue-cli-plugin-electron-builder это челнок,запишите онлайн обновление и шаг на некоторые из ям, я сделаю резюме для себя кстати, и простите меня за любые недостатки.
основное введение
Что такое электрон?
Фреймворк для разработки кроссплатформенных настольных приложений. Виндовс | Мак | Линукс
Зачем его использовать, какие плюсы и минусы?
преимущество
- Быстро упаковывайте приложения vue/react
- Кроссплатформенность
недостаток
- Большой размер, занимает много памяти
Как общаться
Технические предпосылки для сетевых обновлений
Техническая предпосылка схемы, обсуждаемой в этой статье, заключается в следующем: Приложение Electron, созданное с помощью скаффолдинга vue/cli + плагин vue-cli-plugin-electron-builder (Использование фреймворка Electron, прямой импорт проекта vue или использование vue-electron, принцип аналогичен и выходит за рамки этой статьи)
Программа онлайн-обновлений
Обновление с помощью плагина electronic-updater
Установить плагин
npm install electron-updater --save
настроить публикацию
В файле vue.config.js добавьте публикацию в конфигурацию сборщика следующим образом:
Элемент публикации настроен на создание файла last.yml после упаковки, который используется для оценки обновления версии. Генерируется в процессе упаковки.Во избежание ошибок автоматического обновления,запрещено изменять содержимое файла после генерации.Если файл неверный,его нужно переупаковать и сгенерировать.Обратите внимание, что здесь есть яма.Если адрес обновления сервера часто меняется, рекомендуется не заполнять здесь url.После того, как основной процесс получит url, сбросьте его через апи. В файле last.yml записывается номер версии, путь к пакету обновления, размер пакета, дата и т. д.
код основного процесса
Код плагина electronic-updater должен выполняться в основном процессе
import { autoUpdater } from 'electron-updater'
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle (updateConfig) {
let message = {
error: 'update error',
checking: 'updating...',
updateAva: 'fetch new version and downloading...',
updateNotAva: 'do not to update'
}
// 设置服务器更新地址
autoUpdater.setFeedURL({
provider: 'generic',
url: updateConfig.download
})
autoUpdater.on('error', function () {
sendUpdateMessage(message.error)
})
autoUpdater.on('checking-for-update', function () {
sendUpdateMessage(message.checking)
})
// 版本检测结束,准备更新
autoUpdater.on('update-available', function (info) {
sendUpdateMessage(message.updateAva)
})
autoUpdater.on('update-not-available', function (info) {
sendUpdateMessage(message.updateNotAva)
})
// 更新下载进度事件
autoUpdater.on('download-progress', function (progressObj) {
console.log('下载进度百分比>>>', progressObj.percent)
})
// 下载完成
autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
// 退出且重新安装
autoUpdater.quitAndInstall()
})
ipcMain.on('checkForUpdate', () => {
// 执行自动更新检查
autoUpdater.checkForUpdates()
})
// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage (text) {
mainWindow.webContents.send('message', text)
}
}
export default updateHandle
код процесса рендеринга
// ####### 请保证updateHandle方法在主进程已经调用过一遍,事件监听都存在
// 检测更新
ipcRenderer.send('checkForUpdate')
Чтение компонента индикатора выполнения
Основной процесс отправляет данные о ходе выполнения на страницу процесса рендеринга для отображения текущего хода обновления.
<template>
<div class="update">
<div class="con">
<el-progress :percentage="percentage"></el-progress>
<span>正在检测版本,请稍后</span>
</div>
</div>
</template>
<script>
const { ipcRenderer } = require('electron')
export default {
name: 'update-loading',
data () {
return {
percentage: 0
}
},
created () {
let vm = this
ipcRenderer.on('download-progress', (e, data) => {
vm.percentage = Number(data)
})
}
}
Яма в практике онлайн-обновлений
Правильная ссылка на autoUpdater
// 不要引用electron自带的autoUpdater
// const { autoUpdater } = require('electron')
import { autoUpdater } from 'electron-updater'
Серверный файл last-mac.yml не найден
решение: Сервер добавляет сопоставление типов MIME формата файла yml
Неверный номер локальной версии
Сам баг электрон-апдейтера пойдет на получение версии Электрона; решение: Измените код функции isUpdateAvailable в appUpdater.js в электронном обновлении.
const pkg=require('../../../package.json');
// const isLatestVersionNewer = (0, _semver().gt)(latestVersion, currentVersion);
const isLatestVersionNewer = (0, _semver().gt)(latestVersion, pkg.version);
Среда разработки сообщает, что файл dev-app-update.yml не существует.
решение: В методе updateHandle добавьте следующий код, адрес — это путь к локально упакованному файлу app-update.yml.
if (process.env.NODE_ENV === 'development' && !isMac) {
autoUpdater.updateConfigPath = path.join(__dirname, 'win-unpacked/resources/app-update.yml')
// mac的地址是'Contents/Resources/app-update.yml'
}
Ошибка обновления из-за загрузки кеша пакетов
решение: Значение updaterCacheDirName совпадает со значением updaterCacheDirName в src/main/app-update.yml В Windows файл, аналогичный //C:\Users\Administrator\AppData\Local\electron-updater1\pending, будет создан для хранения обновленных скачанных файлов.Файлы "*.exe" и "update-info.json" Перед каждым обновлением удаляйте локальный инсталляционный пакет В методе updateHandle добавьте следующий код
// 更新前,删除本地安装包
let updaterCacheDirName = 'electron-admin-updater'
const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
fs.emptyDir(updatePendingPath)
Обновления системы Mac требуют подписи кода
Я не буду здесь углубляться, если вам интересно, вы можете узнать большесегмент fault.com/ah/119000001…
Обновите полный код приложения
import { ipcMain } from 'electron'
import { autoUpdater } from 'electron-updater'
// win是所有窗口的引用
import { createWindow, win } from '../background'
const path = require('path') // 引入path模块
const _Store = require('electron-store')
const fs = require('fs-extra')
const isMac = process.platform === 'darwin'
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle (updateConfig = undefined) {
// electron缓存
let localStore = new _Store()
// 更新配置
updateConfig = updateConfig !== undefined ? updateConfig : localStore.get('updateConfig')
// 更新前,删除本地安装包 ↓
let updaterCacheDirName = 'electron-admin-updater'
const updatePendingPath = path.join(autoUpdater.app.baseCachePath, updaterCacheDirName, 'pending')
fs.emptyDir(updatePendingPath)
// 更新前,删除本地安装包 ↑
let message = {
error: 'update error',
checking: 'updating...',
updateAva: 'fetch new version and downloading...',
updateNotAva: 'do not to update'
}
// 本地开发环境,改变app-update.yml地址
if (process.env.NODE_ENV === 'development' && !isMac) {
autoUpdater.updateConfigPath = path.join(__dirname, 'win-unpacked/resources/app-update.yml')
}
// 设置服务器更新地址
autoUpdater.setFeedURL({
provider: 'generic',
url: updateConfig.download
})
autoUpdater.on('error', function () {
sendUpdateMessage(message.error)
})
autoUpdater.on('checking-for-update', function () {
sendUpdateMessage(message.checking)
})
// 准备更新,打开进度条读取页面,关闭其他页面
autoUpdater.on('update-available', function (info) {
sendUpdateMessage(message.updateAva)
createWindow('update-loading', {
width: 500,
height: 300,
minWidth: 720,
resizable: false,
fullscreenable: false,
frame: false
})
for (let key in win) {
if (key !== 'update-loading') {
win[key] && win[key].close()
}
}
})
autoUpdater.on('update-not-available', function (info) {
sendUpdateMessage(message.updateNotAva)
})
// 更新下载进度
autoUpdater.on('download-progress', function (progressObj) {
win['update-loading'] && win['update-loading'].webContents.send('download-progress', parseInt(progressObj.percent))
})
// 更新完成,重启应用
autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
ipcMain.on('isUpdateNow', (e, arg) => {
// some code here to handle event
autoUpdater.quitAndInstall()
})
win['update-loading'] && win['update-loading'].webContents.send('isUpdateNow')
})
ipcMain.on('checkForUpdate', () => {
// 执行自动更新检查
autoUpdater.checkForUpdates()
})
// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage (text) {
win['update-loading'] && win['update-loading'].webContents.send('message', message.error)
}
}
export default updateHandle