之前介紹過在electron-builder打包基礎(chǔ)下怎么使用electron-updater實(shí)現(xiàn)應(yīng)用自動(dòng)監(jiān)測(cè)版本以及更新的拙吉,現(xiàn)在來記錄一下怎么實(shí)現(xiàn) 熱更新
electron應(yīng)用熱更新具體實(shí)現(xiàn)流程圖
正常執(zhí)行electron-builder進(jìn)行打包耘戚,打包完成后將win-ia32-unpacked\resources下的文件壓縮成latest.zip文件(注意:壓縮時(shí)需要選中三個(gè)文件壓縮蜓萄,而非壓縮三個(gè)文件的上級(jí)文件夾杀餐,推薦使用mac電腦壓縮)裙盾,上傳到服務(wù)器泄鹏;客戶端每次重啟執(zhí)行一次檢測(cè)更新郎任,比較本地與遠(yuǎn)程服務(wù)器的版本,如有最新版本命满,則下載zip包涝滴,通過Node fs模塊寫入本地,解壓覆蓋到本地resources下文件胶台,重啟app完成更新歼疮;
electron應(yīng)用熱更新具體實(shí)現(xiàn)步驟
1、 在渲染進(jìn)程引入ipcRenderer诈唬,監(jiān)聽從主進(jìn)程傳過來的更新事件韩脏,應(yīng)用啟動(dòng)后在渲染進(jìn)程調(diào)用接口比對(duì)服務(wù)器最新資源版本和本地資源版本是否一致,若不一致則向主進(jìn)程觸發(fā)資源熱更新函數(shù)铸磅。
ipcRenderer.send('upgrading', url + 'latest.zip') // 用來觸發(fā)熱更新函數(shù)
2赡矢、 在主進(jìn)程模塊下添加 upgrade.js主要處理更新資源的下載和替換杭朱,并將資源更新進(jìn)度發(fā)送給渲染進(jìn)程進(jìn)行渲染,讓進(jìn)度可視化吹散。
const path = require('path')
const http = require('http')
const fs = require('fs')
const dir = path.resolve(__dirname, '../')
var AdmZip = require('adm-zip')
const { beforeWriteAppLog } = require('./export.js')
const upgradeFn = function (appResourcesUrl) {
var destUrl = `${dir}/latest.zip`
downloadFile(appResourcesUrl, destUrl, (state, data) => {
if (state === 'progress') {
global.mainWindow.webContents.send('hotDownloadProgress', data) // 通知渲染進(jìn)程更新資源下載進(jìn)度
} else if (state === 'Download completed') {
} else if (state === 'finish') {
try {
var zip = new AdmZip(destUrl)
zip.getEntries()
zip.extractAllTo(dir, true)
deleteFile(destUrl)
global.mainWindow.webContents.send('isUpdateHotNow') // 通知渲染進(jìn)程更新資源下載完成
} catch (err) {
errorFn('AdmZip', err)
global.mainWindow.webContents.send('hot-updata-error') // 通知渲染進(jìn)程更新資源下載錯(cuò)誤
}
} else if (state === 'error') {
errorFn('hot-updata-downloadFile', 'stream error' + data)
global.mainWindow.webContents.send('hot-updata-error')
}
})
}
/*
* url 網(wǎng)絡(luò)文件地址
* dest 文件存儲(chǔ)位置
* cb 回調(diào)函數(shù)
*/
const downloadFile = (url, dest, cb = () => {} ) => {
const stream = fs.createWriteStream(dest)
http.get(url, (res) => {
if (res.statusCode !== 200) {
cb('error', 'response.statusCode error:' + res.statusCode)
return
}
// 進(jìn)度
const len = parseInt(res.headers['content-length']) // 文件總長(zhǎng)度
let cur = 0
const total = (len / 1048576).toFixed(2) // 轉(zhuǎn)為M 1048576 - bytes in 1Megabyte
res.on('data', function (chunk) {
cur += chunk.length
const progress = (100.0 * cur / len).toFixed(2) // 當(dāng)前下載進(jìn)度百分比
const currProgress = (cur / 1048576).toFixed(2) // 當(dāng)前下載大小
console.log(progress, currProgress, total)
cb('progress', progress)
})
res.on('end', () => {
cb('Download completed')
})
// 超時(shí),結(jié)束等
stream.on('finish', () => {
stream.close(cb('finish'))
}).on('error', (err) => {
deleteFile(dest)
if (cb) cb('error', 'stream error:' + err.message)
})
res.pipe(stream)
})
}
/*
* 刪除文件
*/
function deleteFile (url) {
fs.unlink(url, function (err) {
if (err) {
errorFn('deleteFile', JSON.stringify(err))
}
})
}
3弧械、 在主進(jìn)程main.js文件中引入 ipcMain,監(jiān)聽資源熱更新函數(shù)upgrading空民,觸發(fā)upgrade.js中的upgradeFn函數(shù)
// 監(jiān)聽熱更新
ipcMain.on('upgrading', (evt, url) => {
upgradeFn(url)
})
4刃唐、在渲染進(jìn)程中添加熱更新事件的監(jiān)聽,獲取資源下載進(jìn)度界轩,在這一步實(shí)現(xiàn)可視化效果
if (isElectron()) {
// 熱更新下載進(jìn)度
ipcRenderer.on('hotDownloadProgress', (event, percent) => {
})
// 資源替換完成画饥,重啟app完成更新
ipcRenderer.on('isUpdateHotNow', (event) => {
ipcRenderer.send('appRelaunch')
})
// 熱更新失敗
ipcRenderer.on('hot-updata-error', (event) => {
})
}