跳至主要内容

更新程序

Tauri 为 NSIS(Windows)、MSI(Windows)、AppImage(Linux)和 App 捆绑包(macOS)分发格式提供了内置更新程序。

Tauri 项目准备就绪后,你可以配置 Tauri 的更新程序,为用户启用自动更新。

签名更新

Tauri 的更新程序具有内置签名机制,以确保更新安全可安装。

要签名更新,你需要两样东西

  1. 公钥,稍后将添加到你的 tauri.conf.json 文件中,以在安装之前验证更新工件。
  2. 私钥,用于签名更新工件,切勿与任何人共享。此外,如果你丢失此密钥,将无法向当前用户群发布新更新。将其存储在始终可以访问的安全位置至关重要。

要在 Linux 和 macOS 上生成密钥,可以使用 Tauri CLI

npm run tauri signer generate -- -w ~/.tauri/myapp.key

如果您使用的是 Windows,您应该使用 $HOME/.tauri/myapp.key 或您选择的其他路径

npm run tauri signer generate -- -w $HOME/.tauri/myapp.key

Tauri 配置

现在您需要配置 Tauri 的更新程序。为此,请将此内容添加到您的 Tauri 配置

tauri.conf.json
{
"tauri": {
"updater": {
"active": true,
"endpoints": [
"https://releases.myapp.com/{{target}}/{{arch}}/{{current_version}}"
],
"dialog": true,
"pubkey": "YOUR_UPDATER_SIGNATURE_PUBKEY_HERE"
}
}
}

必需的键是 "active""endpoints""pubkey" 以启用更新程序。"dialog" 是可选的,如果没有设置,将默认为 true

"active" 必须是布尔值。默认情况下设置为 false。

"endpoints" 必须是字符串形式的更新程序端点 URL 数组。在生产模式下强制使用 TLS。
每个更新程序 URL 都可以包含以下变量,允许您在 服务器端 确定是否有可用更新

  • {{current_version}}:请求更新的应用程序版本。
  • {{target}}:操作系统名称(linuxwindowsdarwin 之一)。
  • {{arch}}:机器的架构(x86_64i686aarch64armv7 之一)。

"pubkey" 必须是使用 Tauri 的 CLI 上面 生成的有效公钥。

如果存在,"dialog" 必须是布尔值。默认情况下设置为 true。如果启用,更新程序 事件 将被禁用,因为内置对话框处理所有内容。如果您需要自定义事件,则必须关闭内置对话框。

Windows 上的 installMode

在 Windows 上,还有一个可选的附加配置 "installMode" 来更改更新程序的安装方式。

tauri.conf.json
{
"tauri": {
"updater": {
"windows": {
"installMode": "passive"
}
}
}
}
  • "passive":将有一个带有进度条的小窗口。更新程序将安装,无需任何用户交互。通常推荐,并且是默认模式。
  • "basicUi":将显示一个基本的用户界面,需要用户交互才能完成安装。
  • "quiet":不会向用户提供进度反馈。在此模式下,安装程序无法自行请求管理员权限,因此它仅适用于用户范围内的安装或您的应用程序本身已使用管理员权限运行时。通常不推荐。

更新工件

一旦更新程序正确配置并启用,Tauri 的捆绑器将自动生成并签名更新工件。

在构建应用之前,您需要为私钥和密码设置环境变量

  • TAURI_PRIVATE_KEY:私钥的路径或内容
  • TAURI_KEY_PASSWORD:私钥密码(可选)

如果您想为当前控制台会话设置这些变量,可以在控制台中执行这些命令,稍后您将使用这些命令来构建应用

export TAURI_PRIVATE_KEY="content of the generated key"
export TAURI_KEY_PASSWORD="password"

之后,您可以像往常一样运行 tauri build,Tauri 将生成更新包及其签名。

  • Linux:在 Linux 上,Tauri 将在 target/release/bundle/appimage/ 文件夹中从 AppImage 创建一个 .tar.gz 存档

    • myapp.AppImage - 标准应用包。
    • myapp.AppImage.tar.gz - 更新程序包。
    • myapp.AppImage.tar.gz.sig - 更新程序包的签名。
  • macOS:在 macOS 上,Tauri 将在 target/release/bundle/macos/ 文件夹中从应用程序包创建 .tar.gz 存档

    • myapp.app - 标准应用包。
    • myapp.app.tar.gz - 更新程序包。
    • myapp.app.tar.gz.sig - 更新程序包的签名。
  • Windows:在 Windows 上,Tauri 将在 target/release/bundle/msi/target/release/bundle/nsis 文件夹中从 MSI 和 NSIS 安装程序创建 .zip 存档

    • myapp-setup.exe - 标准应用包。
    • myapp-setup.nsis.zip - 更新程序包。
    • myapp-setup.nsis.zip.sig - 更新程序包的签名。
    • myapp.msi - 标准应用包。
    • myapp.msi.zip - 更新程序包。
    • myapp.msi.zip.sig - 更新程序包的签名。

只要您的私钥是安全的,就可以安全地上传和共享签名。

服务器支持

Tauri 的更新程序支持两种方式来发布更新数据

  • 一个静态 JSON 文件(用于 S3 或 GitHub gist 等服务)
  • 一个动态更新服务器

静态 JSON 文件更容易使用,而动态更新服务器将为您提供对更新机制的更精细控制。

静态 JSON 文件

采用此方法时,Tauri 将始终请求同一个 JSON 文件,并通过将响应的版本字段与请求应用的当前版本进行比较来确定是否需要更新应用。Tauri 期望以这种格式进行响应

{
"version": "v1.0.0",
"notes": "Test version",
"pub_date": "2020-06-22T19:25:57Z",
"platforms": {
"darwin-x86_64": {
"signature": "Content of app.tar.gz.sig",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-x86_64.app.tar.gz"
},
"darwin-aarch64": {
"signature": "Content of app.tar.gz.sig",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-aarch64.app.tar.gz"
},
"linux-x86_64": {
"signature": "Content of app.AppImage.tar.gz.sig",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-amd64.AppImage.tar.gz"
},
"windows-x86_64": {
"signature": "Content of app-setup.nsis.sig or app.msi.sig, depending on the chosen format",
"url": "https://github.com/username/reponame/releases/download/v1.0.0/app-x64-setup.nsis.zip"
}
}
}

必需的键是 "version""platforms.[target].url""platforms.[target].signature";其他键是可选的。

  • "version" 必须是有效的 semver,可以带或不带前导 v,这意味着 1.0.0v1.0.0 都是有效的。
  • "platforms":每个平台键都采用 OS-ARCH 格式,其中 OSlinuxdarwinwindows 之一,ARCHx86_64aarch64i686armv7 之一。
  • "url" 必须是更新包的有效 URL。
  • "signature" 必须是生成的 .sig 文件的内容。每次运行 tauri build 时签名都可能发生变化,因此请务必始终对其进行更新。
  • "notes":此处可以添加有关更新的说明,例如发行说明。Tauri 的默认对话框会在询问是否允许更新时向用户显示此说明。
  • 如果存在,"pub_date" 必须按照 RFC 3339 进行格式化。

请注意,Tauri 会在检查版本字段之前验证整个文件,因此请确保所有现有的平台配置都是有效且完整的。

动态更新服务器

采用此方法时,Tauri 将遵循更新服务器的说明。要禁用内部版本检查,可以 覆盖 Tauri 的版本比较 以始终安装服务器发送的版本。如果你需要快速回滚应用版本,这可能很有用。

你的服务器可以使用上面 endpoint URL 中定义的变量来确定是否需要更新。如果你需要更多数据,可以根据喜好向 Rust 中包含其他 请求标头

如果无可用更新,你的服务器应响应状态代码 204 无内容

如果需要更新,你的服务器应响应状态代码 200 确定 和以下格式的 JSON 响应

{
"version": "0.2.0",
"pub_date": "2020-09-18T12:29:53+01:00",
"url": "https://mycompany.example.com/myapp/releases/myrelease.tar.gz",
"signature": "Content of the relevant .sig file",
"notes": "These are some release notes"
}

必需的键是“url”、“version”和“signature”;其他键是可选的。

  • "version" 必须是有效的 semver,可以带或不带前导 v,这意味着 1.0.0v1.0.0 都是有效的。
  • "url" 必须是更新包的有效 URL。
  • "signature" 必须是生成的 .sig 文件的内容。每次运行 tauri build 时签名都可能发生变化,因此请务必始终对其进行更新。
  • "notes":此处可以添加有关更新的说明,例如发行说明。Tauri 的默认对话框会在询问是否允许更新时向用户显示此说明。
  • 如果存在,"pub_date" 必须按照 RFC 3339 进行格式化。

检查更新

内置对话框

默认情况下,更新程序使用 Tauri 的 dialog.ask API 在内部显示对话框。该对话框仅在应用刚启动时或您手动发出"tauri://update" 事件时检查是否有新更新。

Default updater dialog

对话框版本说明由 服务器 提供的更新notes 表示。如果用户接受,则下载并安装更新。之后,系统会提示用户重新启动应用程序。

自定义对话框

警告

您需要在 Tauri 配置 中禁用内置对话框才能启用 JavaScript API 和更新程序事件!

Rust

请参阅 docs.rs 上的更新程序模块文档,了解 Rust API。

JavaScript

有关完整的 API 文档,请参阅 此处。使用 JavaScript API 的示例如下所示

updater.ts
import {
checkUpdate,
installUpdate,
onUpdaterEvent,
} from '@tauri-apps/api/updater'
import { relaunch } from '@tauri-apps/api/process'

const unlisten = await onUpdaterEvent(({ error, status }) => {
// This will log all updater events, including status updates and errors.
console.log('Updater event', error, status)
})

try {
const { shouldUpdate, manifest } = await checkUpdate()

if (shouldUpdate) {
// You could show a dialog asking the user if they want to install the update here.
console.log(
`Installing update ${manifest?.version}, ${manifest?.date}, ${manifest?.body}`
)

// Install the update. This will also restart the app on Windows!
await installUpdate()

// On macOS and Linux you will need to restart the app manually.
// You could use this step to display another confirmation dialog.
await relaunch()
}
} catch (error) {
console.error(error)
}

// you need to call unlisten if your handler goes out of scope, for example if the component is unmounted.
unlisten()