Electron 实践之基于Github的自动发布与更新

597 阅读5分钟

自动发布

目标: 依托 GitHub 作为安装包的托管平台,对于每一次的版本发布,都可以在对应的仓库里新建一个 release ,并把对应的安装包资源传输到 release 中

基于 electron-builder 库实现自动发布功能

下面是实现自动更新的依赖和配置

第三方包:electron-build(用于构建和发布)

配置package.json里面的构建命令: (这里以window的打包构建命令为例)

{
  "scripts": {
    ...
    "build:win": "npm run build && electron-builder --win --config --publish always",
  },
}

在根目录配置electron-builder.yml: (这里的GitHub Token是 Personal access tokens)

publish:
  provider: github
  owner: github账户名
  repo: 仓库名
  token: GitHub Token
  releaseType: 'release'

当修改完代码后需要修改package.json里面的version版本号,release 里面发布的产物的版本号就是基于package.json

运行打包命令pnpm build:win后, 就会自动把产物推送到 GitHub

基于 GitHub Actions 实现自动发布功能

  1. 下面是实现自动更新的依赖和配置

第三方包:electron-build(用于构建)

配置package.json里面的构建命令: (注意这里的是--publish never,不用electron-build进行发布)

{
  "scripts": {
    ...
    "build:win": "npm run build && electron-builder --win --config --publish never",
    "build:linux": "npm run build && electron-builder --linux --config --publish never",
    "build:mac": "npm run build && electron-builder --mac --config --publish never",
    "build:mac-arm": "npm run build && electron-builder --arm64 --config --publish never",
    "build:mac-mas": "npm run build && electron-builder --mac --config electron-builder-mas.yml --publish never"
  },
}
  1. 在根目录下创建 .github/workflows/build.yml
  • 这个工作流的主要目的是自动化Electron应用的构建和发布过程。
  • 在Windows和macOS上构建应用,清理不必要的文件,
  • 然后创建一个GitHub Release并上传构建产物。
  • 工作流在推送新的版本标签(以v开头)时触发,确保只有正式版本才会被构建
name: AutoBuild  # 工作流的名称

permissions:
  contents: write  # 给予写入仓库内容的权限

on:
  push:
    tags:
      - v*  # 当推送以v开头的标签时触发此工作流

jobs:
  release:
    name: build and release electron app  # 任务名称
    runs-on: ${{ matrix.os }}  # 在matrix.os定义的操作系统上运行

    if: startsWith(github.ref, 'refs/tags/')  # 只在推送标签时运行
    strategy:
      fail-fast: false  # 如果一个任务失败,其他任务继续运行
      matrix:
        os: [windows-latest, macos-latest]  # 在Windows和macOS上运行任务

    steps:
      - name: Check out git repository
        uses: actions/checkout@v4  # 检出代码仓库

      - name: Install Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18  # 安装Node.js 18 (这里node环境是能够运行代码的环境)

      - name: Install Dependencies
        run: |
          npm i -g pnpm
          pnpm install  # 安装项目依赖

      - name: Build Electron App for windows
        if: matrix.os == 'windows-latest'  # 只在Windows上运行
        run: pnpm run build:win  # 构建Windows版应用

      - name: Build Electron App for macos
        if: matrix.os == 'macos-latest'  # 只在macOS上运行
        run: |
          pnpm run build:mac
          pnpm run build:mac-arm  # 构建macOS版应用(包括ARM架构)

      - name: Cleanup Artifacts for Windows
        if: matrix.os == 'windows-latest'
        run: |
          npx del-cli "dist/*" "!dist/*.exe" "!dist/*.zip" "!dist/*.yml"  # 清理Windows构建产物,只保留特定文件

      - name: Cleanup Artifacts for MacOS
        if: matrix.os == 'macos-latest'
        run: |
          npx del-cli "dist/*" "!dist/(*.dmg|*.zip|latest*.yml)"  # 清理macOS构建产物,只保留特定文件

      - name: upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: ${{ matrix.os }}
          path: dist  # 上传构建产物作为工作流artifact

      - name: release
        uses: softprops/action-gh-release@v1
        if: startsWith(github.ref, 'refs/tags/')  # 只在推送标签时创建release
        with:
          files: 'dist/**'  # 将dist目录下所有文件添加到release
  1. 修改 GitHub 上的设置:
  • 点击项目中的 setting

  • 修改 Workflow 为读写权限

image.png

  1. 在本地添加新标签:git tag v1.0.1
  2. 提交标签到 GitHub,这时 GitHub 会基于仓库里面的代码自动执行actionsgit push --tag

这里注意:当修改完代码后需要修改package.json里面的version版本号,release 里面发布的产物的版本号就是基于package.json

自动更新

实现上图的检查更新的功能:

点击“检查更新”的按钮,检查当前版本和版本是否一致,主要是看打包后的其中一个产物 latest.yml(版本配置)里面的version进行检测更新,发现有更新后才会下载对应的安装包。

下面是实现自动更新的依赖和配置

第三方包:electron-build(用于构建和发布)和electron-updater(用于实现更新功能)

配置electron-builder.yml:(基于electron-builder 库实现自动发布功能就不需要再修改)

  • 当GitHub的仓库设为私有就需要设置GitHub Personal Access Token用于自动更新
  • 如果你的仓库是公开的,且你的 releases 也是公开的,那么你不需要提供 token 来下载更新
publish:
  provider: github
  owner: 你的账户名
  repo: 仓库名

主进程接入 electron-updater 实现更新脚本

创建脚本 updater.ts

  1. checkForUpdates检查是否有新更新可用
import { is } from '@electron-toolkit/utils'
import { BrowserWindow, dialog, shell, ipcMain } from 'electron'
import { autoUpdater } from 'electron-updater'

// 自动下载更新
autoUpdater.autoDownload = false
// 退出时自动安装更新
autoUpdater.autoInstallOnAppQuit = false

export default (win: BrowserWindow) => {
  if (is.dev) return
  const checkForUpdates = (manual = false) => {
    autoUpdater.checkForUpdates().catch((error) => {
      console.error('Error checking for updates:', error)
    })

    if (manual) {
      dialog.showMessageBox({
        type: 'info',
        title: '检查更新',
        message: '正在检查更新...'
      })
    }
  }
  // 监听来自渲染进程的手动检查更新请求
  ipcMain.on('startForCheckUpdate', () => {
    checkForUpdates()
  })

  // 监听来自渲染进程的手动检查更新请求
  ipcMain.on('CheckForUpdates', () => {
    checkForUpdates(true)
  })
}
  1. 监听update-available事件:有新版本可用,使用downloadUpdate进行下载
// 有新版本时
  autoUpdater.on('update-available', (info) => {
    dialog
      .showMessageBox({
        type: 'info',
        title: '更新提示',
        message: `发现新版本 ${info.version},是否更新?`,
        detail: info.releaseNotes ? `更新说明:${info.releaseNotes}` : '',
        buttons: ['更新', '取消'],
        cancelId: 1
      })
      .then((res) => {
        if (res.response === 0) {
          // 开始下载更新
          autoUpdater.downloadUpdate()
        }
      })
  })
  1. 监听update-not-available事件:没有新版本,没有新版本则弹窗告诉用户
// 没有新版本时
  autoUpdater.on('update-not-available', (info) => {
    dialog.showMessageBox({
      type: 'info',
      title: '更新提示',
      message: `当前版本 ${info.version} 已是最新版本`
    })
  })
  1. 监听download-progress事件:下载进度
// 监听下载进度
  autoUpdater.on('download-progress', (prog) => {
    win.webContents.send('downloadProgress', {
      speed: Math.ceil(prog.bytesPerSecond / 1000), // 网速
      percent: Math.ceil(prog.percent) // 百分比
    })
  })
  1. 监听update-downloaded:更新下载完毕, 用quitAndInstall()安装更新
// 更新下载完毕
  autoUpdater.on('update-downloaded', () => {
    win.webContents.send('downloaded')
    dialog
      .showMessageBox({
        type: 'info',
        title: '更新已就绪',
        message: '更新已下载完成,是否立即安装?',
        buttons: ['是', '否'],
        cancelId: 1
      })
      .then((res) => {
        if (res.response === 0) {
          // 退出并安装更新
          autoUpdater.quitAndInstall()
        }
      })
  })
  1. 监听error事件:更新发生错误,可以用网站下载进行兜底
// 更新发生错误
  autoUpdater.on('error', (error) => {
    dialog
      .showMessageBox({
        type: 'error',
        title: '更新错误',
        message: '软件更新过程中发生错误',
        detail: error ? error.toString() : '',
        buttons: ['网站下载', '取消更新'],
        cancelId: 1
      })
      .then((res) => {
        if (res.response === 0) {
          shell.openExternal('https://github.com/owner/xxx/releases')
        }
      })
  })

在主进程文件中引入

import { app, BrowserWindow, ipcMain } from 'electron'
import updater from './updater'

app.whenReady().then(() => {
  // 创建浏览器窗口(渲染进程)
  let win = new BrowserWindow({
    width: 600,
    height: 600,
    webPreferences: {
      contextIsolation: false,
      preload,
    },
  });
  updater(win, ipcMain);
});

补充文章:

想了解autoUpdate生命周期可以看一下这篇文章:

使用 electron-builder 及 electron-updater 给项目配置自动更新_electron-updater electron-builder-CSDN博客