logo

鱼肚的博客

Don't Repeat Yourself

Tauri应用版本更新指南

Build smaller, faster, and more secure desktop applications with a web  frontend | Tauri Studio

Tauri 是一个轻便的跨端应用构建工具,类似 Electron。它内置了一套版本更新的方案,下面我分成三个部分给大家做下介绍。

  • 版本发布机制
  • 版本更新机制
  • 注意事项

版本发布机制

跨端应用的版本发布,涉及到多个平台( Win / Mac / Linux )的构建产物,挨个构建比较复杂,可以借助 Github Actions 等自动化 CI 平台进行。

Tauri 官方提供了一个适配 GitHub Actions 的 tauri-action,可以用来加速这个过程。

首先按照其教程配置如下的 Github workflow 配置:

1# .github/workflows/publish.yml
2name: "publish"
3on:
4  push:
5    branches:
6      - release
7
8jobs:
9  publish-tauri:
10    strategy:
11      fail-fast: false
12      matrix:
13        platform: [macos-latest, ubuntu-latest, windows-latest]
14
15    runs-on: ${{ matrix.platform }}
16    steps:
17    - uses: actions/checkout@v2
18    - name: setup node
19      uses: actions/setup-node@v1
20      with:
21        node-version: 16
22    - name: install Rust stable
23      uses: actions-rs/toolchain@v1
24      with:
25        toolchain: stable
26    - name: install dependencies (ubuntu only)
27      if: matrix.platform == 'ubuntu-latest'
28      run: |
29        sudo apt-get update
30        sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
31    - name: install app dependencies and build it
32      run: yarn && yarn build
33    - uses: tauri-apps/tauri-action@v0
34      env:
35        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36      with:
37        tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
38        releaseName: "v__VERSION__"
39        releaseBody: "See the assets to download this version and install."
40        releaseDraft: true  # 不需要 draft 的可以改成 false
41        prerelease: false

有了这个配置文件之后,每当 release 分支推送新代码,就会触发 tauri 的版本构建和发布过程。

下面是 Github Action 的示意图:

image-20220606063710388

如果顺利构建完成的话,会 tauri 会自动根据当前的版本号,创建出对应的 tag 和 release。

Release 附件形如:

image-20220606063900410

如上一个简单的版本发布就完成了。

签名

为使版本的发布更安全,可以使用 tauri 提供的签名功能。

首先使用如下的方式生成签名用的公钥、私钥。(注意保存,丢失后无法再发布新版本

1# 需要先全局安装 @tauri-apps/cli
2# npm i -g @tauri-apps/cli
3
4tauri signer generate -w ~/.tauri/myapp.key

上面 的命令会自动生成一个公钥、私钥对。公钥可以公开分享,私钥必须严密保存。

先在 Github workflow 配置中加入以下内容:

1    - uses: tauri-apps/tauri-action@v0
2      env:
3        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4        TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} # 密钥,需要提前配置在 Github Secrets中
5        TAURI_KEY_PASSWORD: "" # 密钥的加密文本,与ssh-keygen时输入的密码一致即可。如果未输入密码,则此处留空,如果输入了密码,则也需要添加到 secrets 中,然后使用 ${{ secrets.TAURI_PRIVATE_KEY_PASSWORD }} 这种形式
6      with:
7        tagName: "v__VERSION__" # the action automatically replaces \_\_VERSION\_\_ with the app version
8        releaseName: "v__VERSION__"
9        releaseBody: "See the assets to download this version and install."
10        releaseDraft: false # 按需调整
11        prerelease: false

签名的版本发布才会有上面 release 附件中的 .sig 后缀的文件,它们代表着各个不同版本的签名内容。

版本更新机制

Tauri 中提供了关于版本更新的教程,详见 Updater

tauri.conf.json 文件中加入如下的内容:

1"updater": {
2    "active": true,
3    "endpoints": [
4        "https://releases.myapp.com/{{target}}/{{current_version}}"
5    ],
6    "dialog": true,
7    "pubkey": "YOUR_UPDATER_SIGNATURE_PUBKEY_HERE"
8}

其中各个字段的含义解释如下:

  • active 是否启用
  • endpoints 检查版本更新的地址列表
  • dialog 是否启用内建的新版本提醒对话框,如果不启用的话,需要在 JS 中自行监听事件并进行提醒
  • pubkey 上面提到 tauri signer generate 生成的钥匙对中的公钥的内容。

Endpoints 可以有多个,tauri 会依次尝试。它的内容也可以有两种不同的格式

  • 动态接口形式
  • 静态文件形式

动态接口形式的 endpoint 地址,形如 https://releases.myapp.com/{{target}}/{{current_version}},在 url 中已经有了当前平台和当前版本号的参数,因此只需要返回当前平台的信息即可,形如:

1{
2  "url": "https://mycompany.example.com/myapp/releases/myrelease.tar.gz",
3  "version": "0.0.1",
4  "notes": "Theses are some release notes",
5  "pub_date": "2020-09-18T12:29:53+01:00",
6  "signature": ""
7}

而静态文件形式的方式,则需要同时指定多个平台的最新版本信息,形如:

1{
2  "name": "v1.0.0",
3  "notes": "Test version",
4  "pub_date": "2020-06-22T19:25:57Z",
5  "platforms": {
6    "darwin": {
7      "signature": "",
8      "url": "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.app.tar.gz"
9    },
10    "linux": {
11      "signature": "",
12      "url": "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.AppImage.tar.gz"
13    },
14    "win64": {
15      "signature": "",
16      "url": "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.x64.msi.zip"
17    }
18  }
19}

需要注意无论是哪种形式,endpoint 的 url 都需要是 https 协议的。

因为上面版本发布时使用了 GitHub Actions 自动发布,有一定的规律,因此这里我们也可以使用动态接口的形式,实时获取 Github 中最新的 release 信息。

伪码如下:

1const platformSuffixMap: Record<string, string> = {
2  darwin: '.app.tar.gz',
3  linux: '.AppImage.tar.gz',
4  win64: '.msi.zip',
5};
6
7const [platform, version] = params // 获取当前请求对应的平台和版本号
8const suffix = platformSuffixMap[platform ?? ''];
9if (suffix) {
10  // 获取 github 上公开的版本号信息,只取第一页
11  const releases = await axios.get(
12    'https://api.github.com/repos/<user>/<repo>/releases'
13  );
14  
15  // 过滤状态得到最后一个正式的版本号
16  const latestRelease = releases.data.find(
17    (item: any) => !item.draft && !item.prerelease
18  );
19  if (latestRelease) {
20    // 分别查找安装包和签名文件
21    const binaryAsset = latestRelease.assets.find((e: any) =>
22                                                  e.name.endsWith(suffix)
23                                                 );
24    const sigAsset = latestRelease.assets.find((e: any) =>
25                                               e.name.endsWith(`${suffix}.sig`)
26                                              );
27    if (binaryAsset && sigAsset) {
28      const sigContent = await axios.get(sigAsset.browser_download_url);
29      
30      // 返回版本更新信息
31      res.status(200).json({
32        url: binaryAsset.browser_download_url,
33        version: latestRelease.tag_name,
34        notes: latestRelease.body,
35        pub_date: latestRelease.published_at,
36        signature: sigContent.data,
37      });
38      return;
39    }
40  }
41}
42
43// 没有找到可用的更新,返回 HTTP 204 no content
44res.status(204).end();

按如上方式配置之后,就可以实现版本号的自动更新与 Github Release 的动态结合了。

注意事项

如上的方式也有一些需要注意的事项:

  • Endpoint 必须为 https 的地址,不然会构建失败

  • 签名信息请妥善保存,私钥(以 .key 结尾的文件)不能外传

  • Github 的 assets 保存在 s3 之上,因为众所周知的原因,无法正常下载。需要指定 HTTPS_PROXY 和 HTTP_PROXY 为本地代理地址之后,方能正常运行。不然会出现版本正常提醒,但是点击确定后无法正常安装的现象。