Runtime 与权限
理解 Runtime Adapter、Tauri commands、capabilities、系统权限和浏览器 fallback
你将学到
- Runtime Adapter 的作用和它为什么把原生调用隔离在独立文件里
- 模板当前有哪些 adapter 文件和 Rust commands
- Tauri v2 的 capability 模型如何控制前端能调什么
- 操作系统层面还有哪些权限是 Tauri 管不了的
- 新增一个本地能力需要改哪些地方、按什么顺序改
为什么要有 Runtime Adapter
Tauri 应用由两部分组成:前端 WebView 负责界面,Rust runtime 负责系统能力。两边通过 Tauri command 或 plugin 通信。
如果不加约束,前端组件会到处散落 invoke() 调用和 plugin import。改一个原生能力要翻遍整个前端代码,浏览器预览也跑不起来。
模板把所有 Tauri 相关调用集中放在 products/01mvp/apps/desktop/src/runtime 目录。React 组件只调 adapter 导出的函数,不直接碰 Tauri API。这样做有三个好处:
- React 组件不需要到处写
invoke和 plugin import,只调 adapter 就行 - 浏览器预览模式下 adapter 会返回 fallback,UI 依然能跑
- 新增系统能力时有统一的测试和排查入口
当前 adapter 文件
模板里每个 adapter 文件负责一个领域:
| 文件 | 负责什么 |
|---|---|
core.ts | 判断是否运行在 Tauri、封装 invoke 和可选 plugin import |
preferences.ts | 读取、保存、重置桌面偏好 |
app-info.ts | 读取应用名、版本和 identifier |
opener.ts | 打开外部 URL 或 app data 目录 |
updater.ts | 预留自动更新检查入口 |
浏览器预览没有真实 Tauri runtime。模板会返回 unavailable 状态,或用 localStorage 保存临时偏好。这个 fallback 让你不用每次都启动原生窗口就能开发和调试 UI。
新增原生能力时,在 src/runtime 下建一个新文件。不要把 Tauri 调用写进组件或路由 loader 里。
Rust Commands
前端调原生能力的桥梁是 Rust command。当前命令定义在:
products/01mvp/apps/desktop/src-tauri/src/lib.rs模板提供四个命令:
| 命令 | 作用 |
|---|---|
get_desktop_preferences | 从 app data 读取桌面偏好 JSON |
set_desktop_preferences | 把偏好写入 app data |
reset_desktop_preferences | 删除偏好文件,恢复默认值 |
open_app_data_dir | 用系统文件管理器打开 app data 目录 |
前端通过 core.ts 里的 invokeTauri() 调用这些命令。不要在组件里直接写 invoke("get_desktop_preferences"),统一走 adapter 层。
新增命令后,要把它注册到 invoke handler 里:
.invoke_handler(tauri::generate_handler![
get_desktop_preferences,
open_app_data_dir,
reset_desktop_preferences,
set_desktop_preferences
])漏注册是最常见的新手错误:Rust 侧写好了命令,前端调用时却报 "command not found"。
Capabilities
Tauri v2 用 capabilities 控制前端能调用哪些命令和 plugin。这是安全模型的核心:即使 Rust 侧注册了命令,没有在 capability 里开放权限,前端也调不通。
模板的配置在:
products/01mvp/apps/desktop/src-tauri/capabilities/default.json当前只开放三个基础权限:
{
"permissions": ["core:default", "opener:default", "process:default"]
}core:default 允许基础窗口和事件操作。opener:default 允许打开外部链接。process:default 允许退出应用。
新增 plugin 时只开放产品真正需要的权限。比如你只需要检查更新,就优先用 updater 的 check 权限,不要直接开放完整安装流程。
官方文档:Tauri permissions
系统权限
有些能力不是 Tauri capabilities 能完全决定的。操作系统还会单独要求用户授权。即使 Tauri 侧放行了,用户拒绝系统弹窗后功能一样用不了。
| 能力 | macOS | Windows | Linux |
|---|---|---|---|
| 麦克风 | Microphone 权限 | 隐私设置 | PipeWire / PulseAudio |
| 截屏 | Screen Recording 权限 | 屏幕捕获权限 | 通常不需要 |
| 全局快捷键 | Accessibility | 全局快捷键支持 | X11/Wayland 差异 |
| 输入监听 | Input Monitoring | 全局钩子权限 | 取决于桌面环境 |
| 文件读取 | 文件选择器或 FDE | 文件选择器 | 文件选择器 |
模板默认不启用这些能力。你的产品需要用到时,要做三件事:在 UI 里解释为什么需要这个权限、检测当前权限状态、引导用户去系统设置里授权。
如何新增本地能力
如果产品需要一个 Tauri 没有现成 plugin 的功能,按这个顺序走:
确认需要原生 runtime
先写清楚这个能力为什么浏览器做不了。如果只是 HTTP 请求、DOM 操作或 IndexedDB,不需要原生能力。
选择 plugin 或 command
找官方 plugin 或成熟第三方 plugin,避免手写平台底层逻辑。Tauri 官方 plugin 列表覆盖了常见的文件系统、通知、剪贴板、全局快捷键等场景。
Rust 侧注册
在 lib.rs 里注册 plugin 或定义 command。如果是自定义 command,记得加 #[tauri::command] 标注。
开放 capability 权限
在 capabilities/default.json 里添加必要的权限。只开放你用到的权限,不要图省事全开。
封装 adapter
在 src/runtime/<feature>.ts 里封装调用逻辑,并提供浏览器 fallback。fallback 可以返回 unavailable 状态,或者用 localStorage 模拟。
UI 展示不可用状态
在组件里处理 adapter 返回的 unavailable 状态。展示可理解的提示,而不是空白或报错。
原生窗口验收
跑 vpr @01mvp/desktop#tauri:dev 在真实桌面窗口里验证。浏览器预览不能替代这一步。
浏览器预览能证明布局、普通 React 状态和 HTTP API。它不能证明 Tauri command 能调用、app data 能写入、tray 能出现、系统权限能弹窗、签名后的 app 能被识别。涉及原生能力的改动,必须跑 vpr @01mvp/desktop#tauri:dev 验收。
Plugin 怎么加
新增一个 Tauri plugin 通常要改三处:
products/01mvp/apps/desktop/package.json-- 添加 JS 绑定(npm 包)products/01mvp/apps/desktop/src-tauri/Cargo.toml-- 添加 Rust cratesrc-tauri/src/lib.rs-- 调用.plugin()注册,并在 capabilities 里开放权限
前端使用时,不要在组件里直接 import plugin。先在 src/runtime/<feature>.ts 封装一层 adapter,保持架构统一。这样做的另一个好处是:如果以后要换 plugin 实现,只需要改 adapter 文件,不用动 UI 代码。
浏览器预览 vs Tauri 原生窗口
两种模式能验证的东西不一样。选错验证模式是桌面端最常见的遗漏。
| 验收项 | 浏览器预览 | Tauri 原生窗口 |
|---|---|---|
| 布局和样式 | 能 | 能 |
| React 状态和路由 | 能 | 能 |
| HTTP API 调用 | 能 | 能 |
| 登录和 auth 流程 | 能 | 能 |
| Tauri command | 不能 | 能 |
| app data 读写 | 不能 | 能 |
| 系统托盘 | 不能 | 能 |
| 系统权限弹窗 | 不能 | 能 |
| 窗口关闭/隐藏行为 | 不能 | 能 |
| 签名和公证验证 | 不能 | 能 |
日常开发用浏览器预览看 UI 就够了,启动快、热更新也方便。改到原生能力相关代码时,必须切到 Tauri 原生窗口验证。验证命令:
vpr @01mvp/desktop#tauri:dev跑完 Rust 检查确认编译没问题:
vpr @01mvp/desktop#tauri:check下一步
了解了 Runtime 和权限体系后,下一步去看 本地存储,了解桌面应用里该把数据放在哪里。
想和其他创造者交流?
这篇文档有问题?