主进程负责设置下载目录,下载,获取下载进度,安装;
渲染进程负责检查更新,展示更新界面,调用下载,显示下载进度,调用安装;
主进程模块
封装download.js,实现下载、进度获取、安装
const { ipcMain, dialog, shell } = require('electron')
const path = require('path')
exports.initDownload = function (win) {
let downloadObj = {
downloadPath: '', // 要下载的链接或文件
fileName: '', // 要保存的文件名,需要带文件后缀名
savedPath: '' // 要保存的路径
}
//重置信息
function resetDownloadObj() {
downloadObj = {
downloadPath: '',
fileName: '',
savedPath: ''
}
}
// 监听渲染进程发出的download事件
ipcMain.on('download', (evt, args) => {
downloadObj.downloadPath = args.downloadPath
downloadObj.fileName = args.fileName
let ext = path.extname(downloadObj.fileName)
let filters = [{ name: '全部文件', extensions: ['*'] }]
if (ext && ext !== '.') {
filters.unshift({
name: '',
extensions: [ext.match(/[a-zA-Z]+$/)[0]]
})
}
// 弹出另存为弹框,用于获取保存路径
dialog.showSaveDialog(win, {
filters,
defaultPath: downloadObj.fileName
}).then((result) => {
downloadObj.savedPath = result.filePath
if (downloadObj.savedPath) {
win.webContents.downloadURL(downloadObj.downloadPath) // 触发will-download事件
}
}).catch(() => {})
})
//捕获下载事件
win.webContents.session.on('will-download', (event, item) => {
//设置文件存放位置
item.setSavePath(downloadObj.savedPath)
item.on('updated', (event, state) => {
if (state === 'interrupted') {
console.log('Download is interrupted but can be resumed')
} else if (state === 'progressing') {
if (item.isPaused()) {
console.log('Download is paused');
} else {
console.log(`Received bytes: ${item.getReceivedBytes()}`);
win.webContents.send('downloadProgressing', {progress:item.getReceivedBytes(),totalSize:item.getTotalBytes()});
}
}
})
item.once('done', (event, state) => {
if (state === 'completed') {
console.log('Download successfully');
win.webContents.send('downloadCompleted', {filePath: downloadObj.savedPath});
} else {
win.webContents.send('downloadFailed', {});
console.log(`Download failed: ${state}`);
}
resetDownloadObj()
})
})
// 监听渲染进程发出的setup事件
ipcMain.on('setup', (evt, {filePath}) => {
console.log('setup', filePath)
shell.showItemInFolder(filePath)
shell.openPath(filePath)
setTimeout(() => {
!!win && win.close()
},2000)
})
}
入口文件引用
...
const { initDownload } = require('./download')
...
//主程序初始化之后
initDownload(win);
渲染进程核心逻辑
调用主进程下载方法,接收下载进度,调用主进程安装
let initAppVersionInfo = storage.getSessionItem(StorageKeys.AppVersionInfo);
const [appVersionInfo] = useState(initAppVersionInfo);
const [downLoadStatus, setDownLoadStatus] = useState('ready');//ready, downloading, downloaded, failed
const [downloadProgress, setDownloadProgress] = useState(0);
const [downloadTotalSize, setDownloadTotalSize] = useState(0);
const [filePath, setFilePath] = useState('');
const appName = `Setup${appVersionInfo?.version}.exe`;
//判断是否有新版本信息
function getHaveAppVersionInfo(){
return !!appVersionInfo && (appVersionInfo?.updateType>=0)
}
//下载文件
function download(){
try {
setDownloadProgress(0);
setDownloadTotalSize(0);
ipcRenderer.send('download', {
downloadPath: appVersionInfo?.updateLink, // 下载链接
fileName: appName // 下载文件名,需要包含后缀名
})
ipcRenderer.removeAllListeners('downloadProgressing');
ipcRenderer.removeAllListeners('downloadCompleted');
ipcRenderer.removeAllListeners('downloadFailed');
ipcRenderer.on('downloadProgressing', (event, res) => {
console.log('downloadProgressing: ',res.progress,res.totalSize);
setDownLoadStatus('downloading');
setDownloadProgress(res.progress);
setDownloadTotalSize(res.totalSize);
});
ipcRenderer.on('downloadCompleted', (event, res) => {
console.log('downloadCompleted: ',res);
setDownLoadStatus('downloaded');
setFilePath(res.filePath);
message.success('下载成功');
});
ipcRenderer.on('downloadFailed', (event, res) => {
console.log('downloadFailed: ',res);
setDownLoadStatus('failed');
message.error('下载失败,请重试!');
});
} catch (error) {
}
}
//安装文件
function setup(){
try {
ipcRenderer.send('setup', {filePath: filePath});
} catch (error) {
}
}
//字节转kb mb gb tb
function bytesToSize(bytes) {
const sizes = ['B', 'K', 'M', 'G', 'T'];
if (bytes === 0) return '0 B';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
}