- 桌面应用
- 跨平台
- 移动开发
【免费下载链接】tauri
Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
本篇技术指南以仓库中 crates/tauri-macros/CHANGELOG.md 为骨架,系统梳理tauri-macroscrate 从 v1 时代到 2.7.0 的全部功能演进、破坏性变更与依赖升级,并结合crates/tauri-macros/src下的真实源码,深入讲解#[tauri::command]、generate_handler!、generate_context!、mobile_entry_point等宏的底层实现机制。读完本文,你将掌握 Tauri 2 命令系统与代码生成管线的工作方式、各版本升级时的关键注意点,以及rename、removeUnusedCommands、include_image等新特性在实际工程中的用法。
一、tauri-macros 是什么
tauri-macros是 Tauri 框架的过程宏(proc-macro)crate,在 crates/tauri-macros/Cargo.toml 中声明为proc-macro = true,当前版本2.7.0,描述为 "Macros for the tauri crate."。它的定位是胶水代码生成器:把开发者写的普通 Rust 函数、配置文件和启动入口,转换成可在 Webview 前端通过invoke()调用的 IPC 命令、嵌入二进制中的Context以及移动端原生启动符号。
从源码结构看(crates/tauri-macros/src/lib.rs),该 crate 对外暴露以下宏:
| 宏 | 类型 | 作用 |
|---|---|---|
#[command] | 属性宏 | 把函数包装为可被前端调用的命令处理函数 |
generate_handler! | 函数宏 | 收集命令列表,生成统一的分发 handler |
generate_context! | 函数宏 | 读取配置并生成::tauri::Context |
mobile_entry_point | 属性宏 | 标记移动端应用入口函数 |
include_image! | 函数宏 | 编译期把 PNG/ICO 嵌入为Image |
do_menu_item! | 函数宏(doc(hidden)) | 按kind分发菜单项操作 |
default_runtime | 属性宏(doc(hidden)) | 按 feature 给泛型设置默认 runtime |
官方明确建议:不要直接依赖本 crate,应使用tauri重新导出的同名宏(crates/tauri-macros/src/lib.rs)。
本文所有源码引用均为当前仓库的实际内容,版本与特性以仓库为准;CHANGELOG 中列出的 commit 链接属外部引用,本文不展开。
二、从 v1 到 v2:宏体系的关键演进脉络
2.1 v1 时代的奠基(1.0.0-beta 系列)
CHANGELOG 显示tauri-macros的核心形态在 v1 的 beta 阶段就已定型:
- 1.0.0-beta.0:
#[command]开始生成宏而非函数,以便透传Params等泛型;generate_handler!改为消费生成的#[command]宏(wrapper.rs 中的macro_rules!定义正是这一设计的延续)。同期加入:仅async fn在独立 task 上执行、#[command]返回Result的支持、State<'_, T>参数状态注入。 - 1.0.0-beta.1:修复命令函数名为
invoke、message、resolver、cmd时的标识符冲突。 - 1.0.0-beta.3:由 tauri-codegen 负责在编译期注入 invoke key,支持 ES Module 场景。
- 1.0.0-beta.5:开发模式在二进制中嵌入
Info.plist。 - 1.0.0-rc.0:支持 JSON5 格式的
tauri.conf.json(解析回退逻辑:优先serde_json,失败再试json5)。
2.2 2.0.0 稳定版前后的破坏性变更
- 2.0.0-alpha.5:为
generate_handler!中每个命令路径增加 attribute 支持;shell 功能剥离为独立插件;MSRV 升至 1.65。 - 2.0.0-alpha.7:
tauri::api::ipc整体移动并重构为tauri::ipc。 - 2.0.0-alpha.9:CLI 钩子环境变量从
TAURI_PLATFORM等重命名为TAURI_ENV_PLATFORM系列;MSRV 升至 1.70。 - 2.0.0-beta.0:实现IPC 访问控制列表(ACL),是 v2 权限模型的地基。
- 2.0.0-beta.2:
generate_context!增加capabilities属性,可传入支持条件编译的 capability 文件路径数组。 - 2.0.0-beta.9:
Context代码生成支持assets输入以定义自定义tauri::Assets实现。 - 2.0.0-beta.17:改用
tauri.conf.json > identifier设置 Android 的PackageName与 iOS 的BundleId。 - 2.0.0-beta.18:新增
include_image!宏。 - 2.0.0-beta.19:
generate_context!支持test = true跳过部分代码生成(目前仅跳过 macOS 开发构建的Info.plist嵌入)。 - 2.0.0:正式 promote 为 stable,MSRV 1.78。
- 2.0.1:MSRV 降回1.77.2以支持 Windows 7。
2.3 2.x 中期:新特性与工程化打磨
| 版本 | 核心变化 |
|---|---|
| 2.1.0 | 新增build > removeUnusedCommands:让构建脚本与宏按 capabilities 裁剪未使用命令([#12890]) |
| 2.2.0~2.5.x | 持续跟随tauri-utils/tauri-codegen升级 |
| 2.5.0 | 修复 release 构建下单个 invoke handler 命令过多导致的栈溢出 |
| 2.5.1 | 修复 iOS 模拟器从 Xcode 运行时的死锁(stdout/stderr 走 OSLog) |
| 2.6.0 | #[tauri::command]新增rename属性,可自定义命令对外名称([#14473]) |
| 2.7.0 | 迁移edition 2024;MSRV 升至1.90;修复菜单相关命令被非法输入直接invoke时的 panic;非稳定 tauri crates 锁定 minor 版本 |
三、#[tauri::command]命令宏:从函数到 IPC 处理器的完整链路
3.1 宏展开核心逻辑(源码级)
#[tauri::command]的入口是 lib.rs 中的command(),委托给command::wrapper()(wrapper.rs)。整个展开过程分为四步:
- 解析属性(
WrapperAttributes):支持rename_all("camelCase"默认 /"snake_case")、rename、root、async四种选项,非法值直接报编译错误。 - 参数名归一化(
parse_args→parse_arg):支持Pat::Ident、通配符、struct、tuple struct 模式;按rename_all用heck库转换为 camelCase 或 snake_case。每个参数被展开为CommandArg::from_command(CommandItem { plugin, name, key, message, acl }),其中key就是前端 payload 的字段名。 - 生成隐藏包装宏:为每个命令生成
__cmd__<函数名>宏与__tauri_command_name_<函数名>宏。前者在generate_handler!中被以wrapper!(path, invoke)形式调用,包在一个IIFE(立即执行闭包)中——wrapper.rs 源码注释明确说明这是为了避免 Windows 上的栈溢出问题(对应 2.5.0 的修复)。 - 按执行上下文生成 body:
- 同步命令(
Blocking):在主线程执行,逐参数match解析,失败即resolver.invoke_error(err)提前返回; - 异步命令(
Async/async fn):通过respond_async_serialized(async move { ... })提交到异步运行时,(&result).async_kind().future(result).await处理返回值的 async 语义。
- 同步命令(
3.2async属性与"引用参数必须返回 Result"约束
CHANGELOG 2.0.3 提到"增强 async 命令带引用参数时的错误提示"。这一约束的源码实现在 wrapper.rs 的async_command_check部分:当async fn的参数含引用或含生命周期泛型参数时,若返回类型不是Result,宏会通过#[diagnostic::on_unimplemented]生成专用诊断;返回类型缺失时直接compile_error!。
实战规则:async 命令若接收&T或带生命周期的引用类型,必须返回Result,否则无法跨线程安全地传递引用。
3.3rename属性:前端名称与函数名解耦(2.6.0 新特性)
2.6.0 引入rename后,前端调用名可以完全不同于 Rust 函数名:
// 前端用 invoke("greetUser") 调用 // 注册时仍写 generate_handler![greet_user] #[tauri::command(rename = "greetUser")] fn greet_user() {}其实现机制在 wrapper.rs 中非常巧妙:宏会为每个命令生成一个返回命令名字面量的隐藏宏__tauri_command_name_<函数名>;generate_handler!生成的match分发语句就通过调用这个宏得到命令名字符串进行匹配,而函数标识符仍可用于generate_handler![原函数名]。这与文档中root属性(当tauri被改名或重导出时指定 crate 路径,默认::tauri,特殊值"crate"解析为$crate)一起,构成了命令宏的完整定制面。
3.4generate_handler!:命令分发器与 removeUnusedCommands
generate_handler!的实现在 handler.rs,核心产物是一个闭包:
move |invoke| { let cmd = invoke.message.command(); match cmd { #(命令名 => wrapper!(路径, invoke),)* _ => return false, } }它支持为每条命令附带内层属性#![plugin(plugin_name)],用于标识命令属于哪个内联插件(非独立 crate 的插件),这样build > removeUnusedCommands(2.1.0 特性)才能把命令与插件权限正确对应。源码流程:
try_get_plugin_name:优先解析#![plugin(...)],否则从CARGO_PKG_NAME的tauri-plugin-前缀推导;filter_unused_commands:读取tauri_utils::acl::read_allowed_commands()(crates/tauri-utils/src/acl/mod.rs),把不在 ACL 允许列表中的命令直接从分发器中剔除,并打印Removed unused commands from ...日志;- 注意事项:动态添加的 ACL 不在统计范围(CHANGELOG 2.1.0 明确提醒);
__TAURI_CHANNEL__特例始终放行。
触发该逻辑的环境变量是REMOVE_UNUSED_COMMANDS(crates/tauri-utils/src/acl/mod.rs),由构建脚本检测(crates/tauri-utils/src/acl/build.rs);wrapper.rs 还会在启用该变量时给生成的包装宏加#[allow(unused)]以便死代码消除。
四、generate_context!:配置、资产与 ACL 的编译期嵌入
4.1 支持的属性
generate_context!(context.rs)按 CHANGELOG 与文档支持以下参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
| 首个字符串字面量 | 配置文件路径,相对CARGO_MANIFEST_DIR;相邻的平台专属配置(如tauri.windows.conf.json)会自动合并 | tauri.conf.json |
| 路径参数 | 生成代码引用的 crate 路径 | ::tauri |
capabilities = [...] | 额外 capability 文件(JSON/TOML)数组,叠加到capabilities目录与app > security > capabilities之上 | 无 |
assets = 表达式 | 自定义tauri::Assets实现,替代frontendDist嵌入 | 无 |
test = true | 跳过会在测试二进制中出错的代码生成(当前仅 macOS 开发构建的Info.plist嵌入) | false |
源码解析细节:目标平台通过TARGET或TAURI_ENV_TARGET_TRIPLE环境变量获取;配置文件路径还会用tauri_utils::config::parse::does_supported_file_name_exist校验存在性;capabilities 数组中的每个元素必须是字符串字面量。
4.2 与 tauri-codegen 的分工
generate_context!本身只负责解析参数,真正的代码生成在tauri_codegen::context_codegen(crates/tauri-codegen/src/context.rs)中完成:嵌入前端资产、应用图标、解析后的 ACL 与配置到二进制,最终产出传给tauri::Builder::run/build的Context。错误处理采用compile_error!直接输出为编译错误。
五、移动端入口:mobile_entry_point宏
5.1 典型用法
#[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .run(tauri::generate_context!()) .expect("error while running tauri application"); }仓库 examples/api/src-tauri/src/lib.rs 正是这种标准写法:cfg_attr(mobile, ...)保证桌面端二进制仍从main.rs正常启动,而 Android/iOS 原生工程在启动时调用由该宏生成的符号。
5.2 生成内容(mobile.rs 源码)
mobile_entry_point(mobile.rs)展开后生成:
stop_unwind包装:用std::panic::catch_unwind捕获 panic,避免 panic 穿越 FFI 边界导致进程崩溃,失败时打印并process::abort();- async 函数包装:2.0.0-rc.12 起支持 async 入口,通过
::tauri::async_runtime::block_on阻塞等待; - iOS:调用
::tauri::log_stdout()把 stdout 接入系统日志(对应 2.5.1 的 Xcode 控制台/OSLog 修复); - Android:调用
::tauri::android_binding!(domain, app_name, _start_app, ::tauri::wry)生成 JNI 绑定,其中domain与app_name来自TAURI_ANDROID_PACKAGE_NAME_PREFIX/TAURI_ANDROID_PACKAGE_NAME_APP_NAME环境变量(由tauri-build设置)——因此项目必须有调用tauri_build::build的 build script,否则宏会以 "env var not set" 编译错误失败; - 导出
start_appC 符号:#[no_mangle] extern "C",源码注释特别提醒"重命名时务必小心,CLI 会检查这个符号"。
六、include_image!:编译期嵌入图标
2.0.0-beta.18 引入的include_image!让你在编译期把 PNG/ICO 转成tauri::image::Image常量,用于窗口、菜单、托盘图标:
const APP_ICON: Image<'_> = include_image!("./icons/32x32.png"); // 之后可用于 TrayIconBuilder::new().icon(APP_ICON) 或窗口 .icon(APP_ICON)源码要点(lib.rs 与 crates/tauri-codegen/src/image.rs):
- 相对路径基于
CARGO_MANIFEST_DIR解析,文件不存在会直接compile_error!; - 底层由
CachedIcon完成:PNG 要求 RGBA 色彩类型并逐行读出像素,ICO 则选取最大且位深最高的条目解码(largest_ico_entry),最终以Image::new(include_bytes!(...), width, height)形式嵌入; - 文档特别提醒:图像以原始像素存入最终二进制,图标尺寸过大(宽高)会显著膨胀可执行文件体积。
七、2.7.0 菜单/图标错误处理加固与工程化变更
2.7.0 是本仓库当前版本(Cargo.toml 中version = "2.7.0"),其修复集中在"非法输入不再 panic":
do_menu_item!宏(menu.rs)把unreachable!()改为返回Err(crate::Error::UnexpectedMenuKind)。该宏接受resources_table, rid, kind, |i| ...闭包语法,并支持Check | Submenu正向列表或!Check负向列表筛选(源码对重复与否定做了去重排序处理)。- 新增错误类型
tauri::Error::UnexpectedMenuKind(crates/tauri/src/error.rs),在 crates/tauri/src/menu/plugin.rs 与 crates/tauri/src/tray/plugin.rs 的多个命令分支中被返回。 menu:new的Predefined类型:缺失item选项时返回错误而非 panic(PredefinedMenuItemPayload在 crates/tauri/src/menu/plugin.rs 中要求item字段)。- 图标校验:
Image转菜单/托盘图标时,若 RGBA 缓冲区字节数与宽 × 高 × 4不符,返回tauri::Error::InvalidIcon(crates/tauri/src/image/mod.rs),避免 Linux 上渲染图标时才 panic——因为muda与tray-icon的 Linux 后端不校验尺寸。
以上行为均有仓库测试佐证:menu/plugin.rs 的测试new_rejects_invalid_input_without_panicking明确断言"缺少item选项的 Predefined"与"尺寸不符的图标"都返回Err而非崩溃。
2.7.0 的工程化变更还包括:迁移 Rust edition 2024、MSRV 升至 1.90、锁定非稳定 tauri crates 到 minor 版本(依赖同步升级为tauri-utils@2.10.0与tauri-codegen@2.7.0)。
八、版本升级检查清单与依赖关系速查
8.1 MSRV 与工具链演进
| 版本 | MSRV |
|---|---|
| 1.0.0-rc.0 | 1.56 |
| 1.3.0 | 1.60 |
| 2.0.0-alpha.1 | 1.64 |
| 2.0.0-alpha.5 | 1.65 |
| 2.0.0-alpha.9 | 1.70 |
| 2.0.0 | 1.78 |
| 2.0.1 | 1.77.2(支持 Windows 7) |
| 2.7.0 | 1.90 |
8.2 依赖耦合
tauri-macros的依赖集中在tauri-codegen与tauri-utils两个 workspace crate(见 Cargo.toml),CHANGELOG 中几乎所有版本条目的 "Dependencies" 部分都在同步升级二者。因此升级tauri-macros时,应同时更新tauri-codegen与tauri-utils到配套版本,保持 trio 版本一致(如 2.7.0 对应tauri-codegen@2.7.0+tauri-utils@2.10.0)。
8.3 升级前自查清单
- 工具链是否满足目标版本的 MSRV(2.7.0 要求 Rust 1.90+);
- 若启用
removeUnusedCommands,确认所有动态 ACL 注入点(它不统计运行时动态添加的权限); - 菜单/图标相关命令是否依赖旧的 panic 行为——2.7.0 起应显式处理
UnexpectedMenuKind/InvalidIcon错误; generate_context!的capabilities、assets、test参数在 2.0 系列已全部稳定可用;- 移动端入口函数若为 async,确认版本 ≥ 2.0.0-rc.12。
九、参考资源
- 宏定义与文档:crates/tauri-macros/src/lib.rs
- 命令包装与分发实现:crates/tauri-macros/src/command/wrapper.rs、crates/tauri-macros/src/command/handler.rs
- 上下文生成:crates/tauri-macros/src/context.rs、crates/tauri-codegen/src/context.rs
- 移动端入口:crates/tauri-macros/src/mobile.rs
- 图标嵌入:crates/tauri-codegen/src/image.rs
- ACL 与命令裁剪:crates/tauri-utils/src/acl/mod.rs、crates/tauri-utils/src/acl/build.rs
- 错误类型与校验:crates/tauri/src/error.rs、crates/tauri/src/image/mod.rs、crates/tauri/src/menu/plugin.rs
- 真实用法示例:examples/api/src-tauri/src/lib.rs、examples/api/src-tauri/src/cmd.rs
- 桌面应用
- 跨平台
- 移动开发
【免费下载链接】tauri
Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
相关推荐
axum-macros 完全指南:Rust Web 开发中的派生宏、调试宏与版本演进全解析
axum macros 完全指南:Rust Web 开发中的派生宏、调试宏与版本演进全解析 axum macros 是 axum 官方仓库中为 axum htt
后端Web框架Serial Studio 宏命令(Macros)完全指南:进程内命令终端与 JS/Lua 脚本自动化
Serial Studio 宏命令(Macros)完全指南:进程内命令终端与 JS/Lua 脚本自动化 Serial Studio 为遥测仪表盘的每个可执行操作
桌面应用数据可视化物联网ReMe快速入门指南:安装、启动服务并写入第一个记忆节点
ReMe快速入门指南:安装、启动服务并写入第一个记忆节点 ReMe 是一个面向 AI Agent 的本地优先记忆管理套件(Memory Management K
桌面应用跨平台移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考