electron全量更新

365 阅读2分钟

electron自动更新需要用到插件electron-updater,该插件提供了checkForUpdates方法去监听是否需要更新插件,还提供了更新过程的监听函数用于操作应用的更新。

import { autoUpdater } from 'electron-updater';
import { dialog, BrowserWindow ,app } from 'electron';
import path from 'path';
import logger from './util/logger';
import  winTool from './WinTools' //窗口工具类函数

// 定义一个标志,如果为 true,表示更新检查正在进行,禁用按钮
let isNext = false;

/**检测更新 */
export const checkUpdate = (currentWin: BrowserWindow) => {
  // 更新前,删除本地安装包
  let updaterCacheDirName = '应用名-updater'
  const updatePendingPath = path.join(autoUpdater?.app?.baseCachePath, updaterCacheDirName, 'pending')

  logger.info(`删除本地安装包:${updatePendingPath}`);

  //删除本地安装包的文件夹
  deleteFolderContents(updatePendingPath)

  //默认会自动下载新版本,如果不想自动下载,设置autoUpdater.autoDownload = false
  autoUpdater.autoDownload = false;
  
  // 设置更新检测的资源路径,会检测对应路径下的 last.yaml文件中的版本信息 上线后确保该文件能正常访问
  if (process.platform == 'darwin') {
     autoUpdater.setFeedURL(`${updateUrl}/mac`);
  } else if (process.platform == 'linux') {
     autoUpdater.setFeedURL(`${updateUrl}/linux`);
  } else {
     autoUpdater.setFeedURL(`${updateUrl}/package`);
  }
  
 //检测更新
  autoUpdater.checkForUpdates();

  autoUpdater.on('checking-for-update', (res?: any) => {
    logger.info('获取版本信息:' + JSON.stringify(res));
  });

  autoUpdater.on('update-not-available', (res) => {
    // currentWin?.webContents.send('message', '没有可更新版本');
    logger.info('没有可更新版本');
    logger.info('是否显示获取版本信息弹窗:' + isNoUpdate);

      dialog.showMessageBox({ message: '没有可更新版本' })
      currentWin.webContents.send('afterUpdate');
    
  });

  //监听'error'事件
  autoUpdater.on('error', (err) => {
    dialog.showMessageBox({ title: '更新出错拉!',  message: err.message , type:'error'})
    currentWin.webContents.send('afterUpdate');
    logger.error('更新出错:' + JSON.stringify(err));
  });

  //监听'update-available'事件,发现有新版本时触发
  autoUpdater.on('update-available', (res) => {
    logger.info('是否显示更新弹窗' + isUpdate);
    logger.info('更新弹窗信息:' + JSON.stringify(res));
  
      dialog
        .showMessageBox(currentWin, {
          type: 'info',
          title: '软件更新',
          message: '发现新版本, 确定更新?',
          buttons: ['确定', '取消'],
        })
        .then((resp) => {
          if (resp.response === 0) {
            autoUpdater.downloadUpdate().then(res=>{
              logger.info('下载中:'+JSON.stringify(res))
            });
          }else{
            currentWin.webContents.send('afterUpdate');
          }
         
        });
    
  });

  // 更新包下载百分比回调
  autoUpdater.on('download-progress', function (progressObj) {
    logger.info('更新包下载:' + JSON.stringify(progressObj));
    currentWin.webContents.send('downloadProgress', progressObj.percent);
  });

  //监听'update-downloaded'事件,新版本下载完成时触发
  autoUpdater.on('update-downloaded', (res:any) => {
    logger.info('是否展示安装弹窗:' + isNext);
    logger.info('安装:' + JSON.stringify(res));
    if (!isNext) {
      isNext = true;
      dialog
        .showMessageBox(currentWin, {
          type: 'info',
          title: '应用更新',
          message:
            '需要退出程序和手动关闭设计浏览器才能安装新版本,安装完后需重新安装扩展,是否安装?',
          buttons: ['是', '否'],
        })
        .then((buttonIndex) => {
          if (buttonIndex.response === 0) {
            //选择是,则退出程序,安装新版本
            closeApp()
            autoUpdater.quitAndInstall();

          }else{
            currentWin.webContents.send('afterUpdate');
          }
          isNext = false;
        });
    }
  });
};

用户通过点击更新按钮去查看版本,当有新版本时,会从package.json中配置的发布地址去下载安装包

"build": {
     "publish": [
          {
            "provider": "generic",
            "url": "xxxxx"
          }
      ],
 }

主进程接收用户在网页上的操作

//主进程监听版本更新检测
ipcMain.on('check-update', (e: any,id:string) => {
  // 获取发送通知的渲染进程窗口
  const currentWin = winTool.getWindow(id);
  if (currentWin) {
    // 升级校验
    checkUpdate(currentWin);
  }
});

//渲染进程
window.ipcRenderer.send('check-update', 'setting');

渲染进程制作简易的下载进度弹窗

<template>
  <el-dialog :title="title" v-model="visible">
    <div v-if="process">正在下载安装包:{{ process }} %</div>
  </el-dialog>
</template>
<script setup lang="ts">
    
let process = ref(0);
let visible = ref(false)

ipcRenderer.on('downloadProgress', (_, data: any) => {
  console.log('process', data)
  process.value = parseInt(data);
});

ipcRenderer.on('beforeUpdate',(_,data:any)=>{
   visible.value = true
})

ipcRenderer.on('afterUpdate',(_,data:any)=>{
  visible.value = false
})
</script>