Electron代码签名及打包
引入 electron-updater
- 在主进程入口
const { autoUpdater } = require('electron-updater')
。。。
let message = {
error: '检查更新出错',
checking: '正在检查更新……',
updateAva: '检测到新版本,正在下载……',
updateNotAva: '现在使用的就是最新版本,不用更新'
}
process.env.CSC_LINK = '客户端的证书位置'
process.env.CSC_KEY_PASSWORD = '证书密码'
// 主进程主动发送消息给渲染进程函数
let sendUpdateMessage = (text, type = 'message') => {
win && win.webContents.send(type, text)
}
autoUpdater.setFeedURL(‘安装包远端服务器地址’)
// 下面是自动更新的整个生命周期所发生的事件
autoUpdater.on('error', function(err) {
console.error(message.error + ': ' + JSON.stringify(err))
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) {
sendUpdateMessage(progressObj, 'downloadProgress')
})
// 更新下载完成事件
autoUpdater.on('update-downloaded', function() {
ipcMain.on('updateNow', (e, arg) => {
autoUpdater.quitAndInstall()
if (process.platform == 'darwin') checkForUpdates.quitAndInstall_mac()
})
sendUpdateMessage(null, 'isUpdateNow')
})
//执行自动更新检查
autoUpdater.checkForUpdates()
// ---- 解决mac quitAndInstall 后关不掉应用
checkForUpdates.quitAndInstall_mac = () => {
setTimeout(() => {
new BrowserWindow({
title: '更新中',
height: 50,
width: 310,
frame: false,
resizable: false,
movable: false,
autoHideMenuBar: true,
show: true,
hasShadow: true,
center: true
}).loadURL(`file://${__dirname}/static/updatingMac.htm`)
setTimeout(() => app.quit(), 7000) // 马上运行会阻止应用更新
}, 1000)
}
打包后出现 latest.yml、latest-mac.yml 这两个文件,需要上传到服务器上,autoUpdater.checkForUpdates方法根据这两个文件判断是否有更新
yml文件中的安装包的名字需要和真实名的名字一样,yml文件不可编辑。
可能遇到的问题
- 下载进度事件download-progress在mac上不会被执行,查看日志发现:
Proxy server for native Squirrel.Mac is closed (was started to download https://xxx/xxx-mac.zip)
squirrel-mac 这个包看起来很大,还不包括它的依赖。所以干脆自己算
class ComputMacDownloadProgress {
constructor() {
if (process.platform === 'darwin') {
this.filedir = `${process.env.HOME}/Library/Application Support/Caches/项目名-updater/pending/temp-项目名-mac.zip`;
} else {
this.filedir = `${process.env.LOCALAPPDATA}/项目名-updater/pending/temp-项目名-win.exe`;
}
this.downloadSize = 0
try {
fs.lstatSync(this.filedir.replace('pending/temp-', 'pending/'));
// 本地有更新包
this.sendProgress(100);
} catch {
this.check();
}
}
check() {
if (this.downloadSize >= this.filesize && this.downloadSize > 0) return;
try {
const stats = fs.lstatSync(this.filedir);
if (this.downloadSize >= this.filesize) return;
if (this.downloadSize === stats.size) throw new Error();
this.downloadSize = stats.size;
const progress = ((stats.size / this.filesize) * 100) << 0;
// 通知渲染进程更新进度 {percent}
。。。
if (progress >= 100) this.stop();
else throw new Error();
} catch (e) {
setTimeout(() => this.check(), 1000);
}
}
stop(){
this.downloadSize = this.filesize;
}
}
let macProgress
autoUpdater.on('update-available', function(info) {
sendUpdateMessage(message.updateAva)
macProgress = new ComputMacDownloadProgress(); // --- new
if (info.files && info.files.length) {
const file = info.files.find(item => item.blockMapSize || item.path && item.path.includes('.exe'));
// 要下载的文件真实大小
macProgress.filesize = file ? file.size : 100000
}
})
autoUpdater.on('update-downloaded', function() {
ipcMain.on('updateNow', (e, arg) => {
autoUpdater.quitAndInstall()
if (process.platform == 'darwin') checkForUpdates.quitAndInstall_mac()
})
sendUpdateMessage(null, 'isUpdateNow')
macProgress.stop(); // --- new
})
- win上打包出现错误 “Cannot download differentially, fallback to full download...”
win更新会先采用差异更新(比较新旧版本的.exe.blockmap),差异下载不成功会去走全量下载。这个逻辑会导致更新出来两个进度(已经90%了又从0开始重新走)
....a. blockmap的路径上要有带有版本号,方便electron-updater比较
....b. 删除blockmap,直接走全量下载
....c. 假进度条
.
利用electron-asar-hot-updater进行asar包更新。electron-updater有了差异更新后,就更没有必要搞两套了