Tauri 1.0 升级到 Tauri 2.0从“能跑”到“跑得稳”的迁移实战指南(含移动端准备、配置重构、插件化 API、权限系统)

40 阅读9分钟

1. 为什么 Tauri 2.0 的升级不是“改个版本号”那么简单

Tauri 2.0 的变化核心有三类:

  1. 配置体系大重构
    tauri.conf.json 的结构变化非常大:顶层字段搬家、tauri 键改名为 app、allowlist 被移除、updater/cli 等移动到插件体系。
  2. API 全面插件化
    以前 @tauri-apps/api 里很多模块(fs/http/shell/notification…)属于“内置模块”,2.0 里这些大多变成插件(Rust 侧 + JS 侧都要装)。
  3. 权限系统(Capabilities)取代 allowlist
    v1 的 allowlist 被替换为更精细的 ACL 模型:可以按窗口、域名、命令、scope 精确放行/拒绝,并且通过 src-tauri/capabilities/ 下的能力文件生效。

这意味着:升级并不难,但必须“按模块拆解迁移”,否则就会出现典型的“编译过了但功能没了”。

2. 升级前的准备清单(强烈建议先做)

  1. 锁定当前可工作的 v1 基线
    打一个 tag:v1-stable
    确保你能随时回滚。
  2. 清点你用到的 v1 API/功能点
    至少列出这些关键项(后面会对应到插件迁移):
  • fs / path / http / shell / notification / clipboard / updater / process / os / cli / global-shortcut
  • tray / menu
  • 自定义协议(asset protocol、pattern、scope)
  • allowlist(尤其是 sidecar / fs scope / shell open / process command)
  1. 清点你当前的配置文件(tauri.conf.json)
    把老结构保存一份,迁移时你会频繁对照字段搬家。

3. 移动端准备:把 crate 变成“可共享库”

如果你的目标包含移动端(Android/iOS),2.0 的移动端接口要求项目能输出共享库,所以需要做这些结构调整。

3.1 修改 Cargo.toml:输出库产物

src-tauri/Cargo.toml 追加:

[lib]
name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]

含义很直白:同一套 Rust 入口需要同时服务桌面端可执行文件和移动端的库载入。

3.2 入口文件拆分:main.rs 变薄,lib.rs 变“通用入口”

  1. src-tauri/src/main.rs 重命名为 src-tauri/src/lib.rs
  2. main() 改成通用的 run(),并加上移动端入口宏:
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    // your code here
}

tauri::mobile_entry_point 会让这个入口在移动端以正确方式被调用。

3.3 重建 main.rs:桌面端只负责调用 run()

重新创建 src-tauri/src/main.rs

#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

fn main() {
  app_lib::run();
}

迁移到这里,你就完成了“同一份 Rust 逻辑,多端复用”的基础改造。

4. 自动迁移:migrate 命令能省力,但不能偷懒

官方给的警告很重要:migrate 不是替代指南,它只是帮你自动做“机械改动”,真正的功能迁移(插件、权限、业务代码)仍然要你手动完成。

4.1 安装 v2 CLI 并运行 migrate

cargo install tauri-cli --version "^2.0.0" --locked
cargo tauri migrate

它通常会帮你做:

  • 部分配置字段的迁移
  • 把 v1 allowlist 解析成 capability 文件的“初稿”

但注意:生成出来的 capability 是否符合你真实的窗口/域名/sidecar 场景,需要你自己复核。

5. 配置文件迁移:tauri.conf.json 的字段搬家地图

下面这一段是升级里最容易“看起来没报错,但运行行为变了”的地方。你贴的 Summary of Changes 很全,我把它整理成“迁移动作”。

5.1 顶层结构变化

  • package > productNamepackage > version 移到顶层
  • package 节点整体移除
  • tauri 键改名为 app
  • tauri > bundle 移到顶层 bundle
  • tauri > bundle > identifier 移到顶层(通常与 bundle 标识相关)

5.2 二进制名称不再自动跟随 productName

v1 里经常“产品名改了,生成的可执行文件名也跟着变”。
v2 不会自动改了,你必须加一个 mainBinaryName,并保证它与 productName 对齐(否则打包/运行时可能找不到主程序)。

5.3 allowlist 移除:改成 Permissions / Capabilities

  • tauri > allowlist 被移除
    迁移方向:创建 src-tauri/capabilities/ 下的能力文件(migrate 命令会帮你生成雏形),再按插件逐项放行。

5.4 安全相关字段的移动

  • tauri > allowlist > protocol > assetScopeapp > security > assetProtocol > scope
  • tauri > patternapp > security > pattern
  • tauri > windows > fileDropEnabledapp > windows > dragDropEnabled
  • build > withGlobalTauriapp > withGlobalTauri
  • build > distDirfrontendDist
  • build > devPathdevUrl

5.5 插件配置位置变化

  • tauri > cliplugins > cli
  • tauri > updaterplugins > updater
  • tauri > updater > active/dialog 等旧字段移除(2.0 updater 行为不同,见后文)
  • tauri > systemTrayapp > trayIcon

5.6 bundle 子结构重命名(按 OS 归档)

  • tauri > bundle > dmgbundle > macOS > dmg
  • tauri > bundle > debbundle > linux > deb
  • tauri > bundle > appimagebundle > linux > appimage
  • Windows WebView Runtime 字段变化:
    bundle > windows > webviewFixedRuntimePath 移除 → 用 bundle > windows > webviewInstallMode

5.7 Updater 的兼容性坑:createUpdaterArtifacts 与 v1Compatible

  • 新增 bundle > createUpdaterArtifacts
    如果你之前已经分发过 v1 应用,并且希望用户能“从旧版本升级到新版本”,通常需要设置为 v1Compatible(它影响升级包生成方式)。这是“升级后用户收不到更新”的高发原因之一。

6. Rust 侧变化:API 模块被拆成插件,很多熟悉的路径都没了

6.1 Cargo feature 变化

新增:

  • linux-protocol-body(需要 webkit2gtk 2.40)用于自定义协议 request body 解析

移除/更名(重点):

  • process-command-apishell-open-api:都改用 tauri-plugin-shell
  • updater:Updater 变成插件
  • system-tray:改名为 tray-icon
  • windows7-compat:移动到 notification 插件

6.2 Rust crate API 变化(你最可能遇到的报错来源)

以下是典型“编译报错 → 对应迁移方向”:

  • tauri::api::* 模块整体移除:每个 API 去对应插件里找

    • tauri::api::dialogtauri-plugin-dialog
    • tauri::api::httptauri-plugin-http
    • tauri::api::shell / tauri::api::process::Commandtauri-plugin-shell
    • tauri::updatertauri-plugin-updater
    • tauri::api::notificationtauri-plugin-notification
  • tauri::api::file:直接用 Rust 的 std::fs

  • tauri::api::pathtauri::PathResolver:迁移到 tauri::Manager::path

示例(path 迁移):

use tauri::{path::BaseDirectory, Manager};

tauri::Builder::default()
  .setup(|app| {
      let home = app.path().home_dir().expect("failed to get home dir");
      let p = app.path().resolve("path/to/something", BaseDirectory::Config)?;
      Ok(())
  });

6.3 Menu/Tray 重构(muda + 新 builder)

Menu:改到 tauri::menu,大量旧类型移除,换成 Builder 风格(你贴的 MenuBuilder / MenuItemBuilder / SubmenuBuilder 就是迁移模板)。

Tray:SystemTray 全部改名为 TrayIcon(更一致),事件拆成:

  • on_menu_event
  • on_tray_icon_event

你可以直接套用你贴的 TrayIconBuilder 示例结构去改。

7. JavaScript 侧变化:@tauri-apps/api “瘦身”,其他都去插件包

v2 的结论非常明确:

  • @tauri-apps/api 只保留:core(原 tauri)、path、event、window/webviewWindow
  • 其他模块:fs/http/shell/os/process/notification/dialog/clipboard/updater/cli/global-shortcut 全部变成 @tauri-apps/plugin-*

7.1 最常见的一刀:@tauri-apps/api/tauri → @tauri-apps/api/core

import { invoke } from "@tauri-apps/api/tauri"
import { invoke } from "@tauri-apps/api/core"

这一步非常常见,很多项目第一处报错就来自这里。

7.2 插件迁移的统一模式(记住这个模板就够了)

每个插件基本都要做三件事:

  1. Rust Cargo 加依赖:tauri-plugin-xxx = "2"
  2. Rust Builder 初始化:.plugin(tauri_plugin_xxx::init()) 或 Builder 风格
  3. 前端 npm/pnpm/yarn 加依赖:@tauri-apps/plugin-xxx
  4. 前端 import 改到插件

比如 Dialog:

Rust:

tauri::Builder::default()
  .plugin(tauri_plugin_dialog::init())

前端:

import { save } from '@tauri-apps/plugin-dialog';

你贴的 Clipboard/CLI/FS/HTTP/Notification/Process/Shell/Updater/OS/Global Shortcut 都是同样套路。

7.3 FS 插件的 API 改名坑

v1 常见函数重命名如下(你贴的很关键):

  • createDirmkdir
  • readBinaryFilereadFile
  • writeBinaryFilewriteFile
  • removeDir/removeFileremove
  • renameFilerename
  • Dir 别名移除 → 用 BaseDirectory

如果你迁移后“明明装了插件但类型/函数不存在”,通常就是这里没改干净。

8. 权限系统迁移:Capabilities 取代 allowlist(这是 v2 的安全核心)

v1 allowlist 只是一种“模块级开关”。
v2 Capabilities 是真正的 ACL:可以精确到“允许哪个窗口在什么域名下调用哪个命令,scope 是什么”。

你必须做的事情:

  • src-tauri/capabilities/ 创建能力文件(migrate 会帮你生成初稿)
  • 按插件逐项配置允许项
  • 如果你有 sidecar、remote URL、多窗口(甚至未来 multiwebview),能力文件要同步升级,否则功能会“静默失效”

一句话经验:
迁移成功的标准不是“能编译”,而是“权限文件覆盖了你真实的调用路径”。

9. 事件系统、窗口系统、Windows origin:升级后行为变化最大的三块

9.1 事件系统:emit 默认广播,新增 emit_to / emitTo

  • emit() 现在会发给所有监听器
  • 新增 emit_to/emitTo:定向发给某个 target
  • listen_globallisten_any
  • JS 的 event.listen() 行为更接近 listen_any(除非你设置 target)

如果你原来依赖“按窗口隔离事件”,升级后要重点检查:有没有出现“别的窗口也收到了消息”。

9.2 Window → WebviewWindow(为 multiwebview 做铺垫)

Rust:

  • Window 改名为 WebviewWindow
  • WindowBuilderWebviewWindowBuilder
  • WindowUrlWebviewUrl
  • get_windowget_webview_window

JS:

  • @tauri-apps/api/window 改到 @tauri-apps/api/webviewWindow

9.3 Windows 生产环境 origin 变了:tauri.localhost

v2 在 Windows 生产环境下,前端文件从 https://tauri.localhost 变成 http://tauri.localhost。直接影响:

  • IndexedDB / LocalStorage / Cookies 可能被重置(因为 origin 变了)

解决方案(你贴的官方建议):

  • 设置 app > windows > useHttpsScheme 为 true
    或 Rust 侧用 WebviewWindowBuilder::use_https_scheme 保持 https 方案。

这是那种“用户升级后发现登录态没了”的典型坑,务必提前处理。

10. Updater 迁移:默认自动弹窗没了,你必须自己做更新流程

v2 移除了“内置的自动检查 + 内置弹窗”。
如果你不手动实现检查与安装,你的用户可能永远不会再收到更新。

迁移路径:

  • Rust:tauri-plugin-updater = "2".plugin(tauri_plugin_updater::Builder::new().build())
  • JS:@tauri-apps/plugin-updater,自己调用 check(),然后 downloadAndInstall(),最后用 @tauri-apps/plugin-processrelaunch() 重启。

你贴的示例就是标准实现模板。

11. 环境变量改名:CI/CD、签名、打包脚本要同步更新

这一块特别容易“本地能打包,CI 全挂”。

你贴的改名清单建议直接做两件事:

  1. 搜索你仓库里的旧 env 名称(GitHub Actions / GitLab CI / Jenkinsfile / bat/sh 脚本)
  2. 全量替换为新名称(例如 TAURI_PRIVATE_KEYTAURI_SIGNING_PRIVATE_KEY 等)

如果你有签名/自动发布流水线,这一步是必做项。

12. 迁移路线建议:按“最小可用”分阶段推进

为了避免一次性改太多导致不可控,我建议你按这个顺序做(每一步都能形成可运行状态):

阶段 A:基础可编译 + 前端可打开

  • CLI/依赖升级
  • 配置文件结构迁移(字段搬家、mainBinaryName、devUrl/frontendDist)
  • JS 的 core 模块改名(tauri → core)
  • Rust 入口整理(必要时把 run() 抽到 lib.rs,为移动端留口)

阶段 B:插件逐个恢复功能(每次迁移一个插件就验收一次)

  • dialog / fs / shell / http / notification / os / process / clipboard / cli / global-shortcut / updater

阶段 C:权限系统补齐

  • capability 文件审核与加固
  • sidecar、remote domain、多窗口 target 范围验证

阶段 D:行为变化专项验证

  • 事件系统是否广播导致串扰
  • Windows origin 变化导致存储丢失(useHttpsScheme)
  • tray/menu 行为是否符合预期

13. 最后给你一个“迁移验收 Checklist”(建议复制到你的 PR 描述里)

  • cargo tauri dev 正常启动
  • 生产构建能打包(Windows/macOS/Linux 各自至少跑一遍)
  • mainBinaryNameproductName 配置正确
  • @tauri-apps/api/tauri 全部替换为 @tauri-apps/api/core
  • 用到的 v1 模块全部替换为对应插件,并完成 Rust .plugin(...) 初始化
  • src-tauri/capabilities/ 存在且覆盖你真实调用(特别是 fs/shell/sidecar/updater)
  • Updater 已实现手动检查与安装,否则用户后续无法更新
  • Windows 下如需保留 https origin,已配置 useHttpsScheme
  • 事件系统升级后,窗口间事件不串台(或已改用 emit_to)