应用与管理器
这一部分讲 crates/tauri/src 里把各层串起来的那几个文件:app.rs(2.8k 行)、manager/mod.rs、lib.rs 里的 Manager trait、state.rs、resources/mod.rs、async_runtime.rs、plugin.rs。03 运行时讲到 Wry 怎么建事件循环、怎么把跨线程操作送回主线程为止;这一部分从用户写的 tauri::Builder::default()...run(generate_context!()) 讲起:build 里依次发生了什么,窗口为什么在 setup 之前就已经存在,命令、事件监听器、插件钩子各在哪个线程上跑,退出怎么被拦下来。
- Builder、App 与 AppHandle:
Builder只是攒配置,build建AppManager、调R::new建事件循环、注册并初始化插件,但不建窗口;窗口在事件循环第一次回调Ready时建,紧接着跑setup。App拿着运行时、不能跨线程,run把它吃掉;AppHandle可以克隆、可以送到任何线程。exit先发ExitRequested,prevent_exit只在回调里同步调用才有效。 - AppManager 与 Manager trait:一个
Arc<AppManager>装着窗口表、webview 表、事件监听器、插件、状态、ACL、invoke key 和内嵌资源,App、AppHandle、Window、Webview、WebviewWindow都拿着它;Manager是一个封口的 trait,靠ManagerBase让五种类型共享同一套方法。 - 状态:
manage把值按TypeId装箱存进一张表,State<T>是指向箱子的引用;同一类型第二次manage,Manager上返回false,Builder上直接 panic;命令要一个没manage的State<T>时得到的错误原文;给 JS 一个 rid 的ResourceTable。 - 异步运行时:
async_runtime是一个懒初始化的全局 tokio 多线程运行时,可以在第一次使用前用set换成自己的;实测同步命令、async 命令、事件监听器、插件钩子各在哪个线程上跑。 - 插件:
Plugintrait 和plugin::Builder的每个钩子在什么时候、哪个线程、持着什么锁被调用;plugin:<name>|<cmd>怎么分流;插件命令一律要过 ACL;内置的core:*插件。
flowchart TB bld["Builder 攒配置"] --> build["Builder::build"] build --> mgr["Arc AppManager"] build --> rt["R::new 建事件循环"] build --> plg["插件 initialize"] build --> app["App"] app --> run["App::run 进事件循环"] run --> ready["Ready: 建窗口, setup"] mgr --> handle["AppHandle / Window / Webview"] handle --> state["State 与 ResourceTable"] ready --> cmds["命令与事件"] cmds --> art["async_runtime"]
前两页讲骨架:对象怎么建出来、谁拿着谁;后三页讲挂在骨架上的三样东西。命令宏本身(参数怎么取、State 参数怎么生成)在 #[command] 与 generate_handler!,一次 invoke 进来以后怎么分到命令上在 on_message 与分发,插件命令要的权限怎么声明、怎么解析在 07 安全。
本部分的实验都在 M2 Max、macOS 27、rustc 1.99.0 上用真实的 Wry 运行时跑(窗口 "visible": false,WKWebView 照常加载页面、执行 JS),不是 MockRuntime;Windows 和 Linux 上的行为只读了源码。
💬 关联讨论
发起讨论加载中...