运行时
这一部分讲 tauri 本体下面的三层:tauri-runtime(2.12.2,约 2900 行,只有 trait 和数据结构)、tauri-runtime-wry(2.12.3,lib.rs 一个文件 5416 行)、以及两个独立仓库里的库:wry 0.57.1(webview)和 tao 0.37.2(窗口和事件循环)。02 编译期 把配置和前端资源做成了 Context;从 Builder::build 调用 R::new 开始,到 App::run 进入事件循环为止,启动主线上「建窗口、建 webview、跑起来」的部分都落在这一层。
贯穿四页的只有一条规则:窗口和 webview 只能在主线程上碰。macOS 上 AppKit 和 WebKit 的对象只许在主线程使用,tao 的 EventLoop 只能在主线程上创建,wry 的 WebView 不是 Send。tauri 给别的线程的东西(AppHandle、Window、Webview)都是一个 Clone + Send 的「派发器」,方法调用变成一条 Message,经 EventLoopProxy 送回主线程执行。
- tauri-runtime 的抽象:
Runtime、RuntimeHandle、WindowDispatch、WebviewDispatch、EventLoopProxy几个 trait 各管什么,哪些要求Send;PendingWindow/PendingWebview到DetachedWindow/DetachedWebview;RunEvent;MockRuntime作为第二个实现,同一段泛型代码在它和Wry上的不同结果。 - tauri-runtime-wry 与事件循环:
Wry记下创建它的线程,send_user_message在主线程上直接执行、在别的线程上经 proxy 排队;getter 用一个 channel 阻塞等主线程回答;tao 事件怎么变成RunEvent;PendingWebview怎么交给 wry;主线程等别的线程、别的线程又等主线程时的死锁。 - wry 在 macOS 上:自定义协议变成每个 scheme 一个
WKURLSchemeHandler类,请求在主线程进来,响应可以在任何线程、任何时候发出;初始化脚本是WKUserScript,可以选只进主 frame;window.ipc.postMessage只注入主 frame;evaluate_script在首次导航之前会排队。Windows、Linux 上的对应实现只读源码。 - tao:窗口与主线程:tao 是 winit 的分叉,菜单、托盘在 0.22 被拆出去;macOS 上事件循环就是
NSApplication.run,回调靠 run loop observer 驱动;EventLoopProxy是一个 channel 加一个唤醒 run loop 的 source;窗口设置有的同步、有的异步派发到主队列。
flowchart TB app["tauri 本体 R: Runtime"] --> traits["tauri-runtime trait"] traits --> rw["tauri-runtime-wry"] rw --> wry["wry WebView"] rw --> tao["tao EventLoop 和 Window"] wry --> wk["WKWebView"] tao --> ns["NSApplication 和 NSWindow"] other["其他线程"] -->|"Message 经 proxy"| tao
前两页是 tauri 仓库里的代码,后两页是它依赖的两个库。窗口和 webview 在 tauri 本体里怎么拆分、WebviewWindowBuilder 怎么变成 PendingWindow,在 Window、Webview、WebviewWindow;tauri://、ipc:// 这两个协议的处理函数本身在 tauri:// 协议与 CSP 和 ipc 协议处理,这一部分只讲它们挂到 webview 上的机制。
💬 关联讨论
发起讨论加载中...