Electron应用内更新(自更新)

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有了差异更新后,就更没有必要搞两套了

你可能感兴趣的:(Electron应用内更新(自更新))