Rust in Everything
基于 tauri 2.12.5

常见坑

每一章对着一个报错或一个现象:先用最小的程序把它复现出来(输出是 M2 Max、macOS 27、rustc 1.99.0 上 tauri 2.12.5 的原文,窗口一律隐藏),再到源码里找它从哪一行来,最后给出修法和检查办法。机制在前面几部分讲过的,这里只链过去,不再重复。有几个坑是 tauri 自己的问题,章里写明在哪个版本上复现。Windows 和 Linux 上的差异只读了源码,章里另外标出。

  1. 开发模式启动后 bus error 退出:开发模式在第一次 Ready 时用 ImageIO 解码应用图标,DYLD_LIBRARY_PATH 指向 Homebrew 时加载了另一份 libpng,进程无声退出。
  2. does not match the allowlist defined under tauri.conf.json:tauri 依赖的 features 和配置推出的 feature 要逐字一致,经自己的 [features] 间接打开也算缺失。
  3. failed to open icon:generate_context! 编译期要一张 RGBA 的 PNG 图标,缺了或格式不对,过程宏 panic。
  4. 每次 cargo build 都重编整个应用:没有 capabilities/ 目录时 cargo 每次都认为它变了;反过来往 frontendDist 新加的文件不会触发重编。
  5. generate_context! 读的不是你指定的配置文件:只用配置路径的目录,文件名被忽略,读的总是 tauri.conf.json。
  6. command greet missing required key userName:参数键是 lowerCamelCase,只管顶层;嵌套字段按各自的 serde 属性,数组直接传会变成字节。
  7. async commands that contain references as inputs must return a Result:async 命令借用参数时要返回 Result,根子在 future 的 'static 约束。
  8. state not managed for field counter on command hit:状态按 TypeId 存取,manage(Counter) 和 State<Mutex<Counter>> 是两种类型;Builder 上重复 manage 直接 panic。
  9. a webview with label main already exists:窗口和 webview 标签各自唯一;setup 里用 ? 传出这个错误会让进程 abort。
  10. 一个同步命令,别的请求全在等:同步命令在主线程上执行,期间别的 invoke、tauri:// 资源、窗口操作都要等;改成 async。
  11. failed to initiate panic, error 5, aborting:同步命令里的 panic 要穿过 WebKit 的栈帧展开,找不到接住的地方,进程直接退出。
  12. 同步命令里等窗口属性,应用卡死:窗口 getter 要等主线程回话,同步命令又占着主线程。
  13. 插件里注册或移除插件,应用卡死:插件钩子和同步插件命令都在插件表的锁里执行,再锁一次就死锁。
  14. Cannot start a runtime from within a runtime:async 命令里 block_on 让 tokio panic,Promise 永远不落定;改成 .await。
  15. prevent_exit 没拦住退出:回调返回后运行时只查一次,先异步问用户再拦已经晚了;先同步拦下,问完再退。
  16. 命令执行了两次:fetch 失败后同一条消息经 postMessage 重发;响应声明错了类型、页面刷新都会触发,不能重复的命令带幂等键。
  17. 用事件传大数据很慢:emit 把数据拼进一段 eval,10 MiB 结构化数据让页面停住 2.4 秒;走 Channel 约 50 毫秒。
  18. Command greet not allowed by ACL:release 只有这一句;debug 分得清新窗口不在能力里、命令名拼错、插件没授权、配置里列了能力导致新文件被忽略。
  19. 远程页面调不到命令:导航到 http(s) 页面后来源变成远程;remote.urls 经 ipc:// 只匹配不带路径的 Origin,远程能力默认还顺带放行本地。
  20. 写给一个窗口的 deny 对所有窗口生效:拒绝只按来源匹配,不看窗口标签;收窄允许的一侧。
  21. 配了 CSP,IPC 悄悄退回 postMessage:connect-src 没放行 ipc: 时只打一条警告就永久换路,原始字节参数变成 JSON。
  22. 'unsafe-inline' 写了也没用:tauri 补进哈希和 nonce 后 'unsafe-inline' 失效,onclick 和 style 属性被拦。
  23. convertFileSrc 的图片加载失败:feature 没开、CSP 没放行、不在作用域里三种原因,在 <img> 上看起来都一样,用 fetch 区分。
  24. 窗口关不掉:用了 onCloseRequested 就要 allow-destroy;页面导航后旧监听器还登记着,窗口一直被拦。
  25. window.TAURI is undefined:app.withGlobalTauri 默认关闭,写在 1.x 的位置会构建失败,开了也只进主 frame。
  26. 监听器注册之前发的事件丢了:emit 没有队列也不重放,setup 和 on_page_load 里发的都早于页面的 listen;让页面登记完再通知 Rust。

按出在哪里分:

出在哪里坑
构建与配置:tauri-build、generate_context!1 开发模式崩溃、2 feature 不一致、3 图标、4 反复重编、5 配置文件名
命令:参数、状态、返回值6 缺键、7 async 借用、8 状态、9 重复标签
线程:主线程、tokio、锁10 同步命令、11 panic、12 getter 死锁、13 插件锁、14 block_on
生命周期与事件15 prevent_exit、17 大事件、24 关不掉的窗口、26 早发的事件
IPC 通道:fetch 与 postMessage16 执行两次、21 CSP 退路
ACL 与能力18 not allowed、19 远程页面、20 deny
前端:CSP、asset 协议、全局 API22 'unsafe-inline'、23 asset 图片、25 __TAURI__
flowchart TB
  q{"碰到了什么"}
  q -->|编译或构建失败| bf{"哪一句"}
  bf -->|"allowlist"| p2["2 feature 不一致"]
  bf -->|"failed to open icon"| p3["3 图标"]
  bf -->|"must return a Result"| p7["7 async 借用"]
  bf -->|"构建很慢或配置没生效"| p45["4 或 5"]
  q -->|进程退出| ex{"怎么退的"}
  ex -->|"bus error 无输出"| p1["1 开发模式"]
  ex -->|"error 5 aborting"| p11["11 panic"]
  ex -->|"拦不住退出"| p15["15 prevent_exit"]
  q -->|调用失败| cf{"错误原文"}
  cf -->|"missing required key"| p6["6 缺键"]
  cf -->|"state not managed"| p8["8 状态"]
  cf -->|"not allowed by ACL"| acl["18 或 19 或 20"]
  cf -->|"Promise 一直不返回"| p14["14 block_on"]
  q -->|卡住或变慢| hang{"哪种"}
  hang -->|"别的请求都在等"| p10["10 同步命令"]
  hang -->|"永远卡住"| p1213["12 或 13"]
  hang -->|"收事件时页面停住"| p17["17 大事件"]
  q -->|"没报错但行为不对"| odd{"哪种"}
  odd -->|"执行了两次"| p16["16 执行两次"]
  odd -->|"事件没收到"| p26["26 早发的事件"]
  odd -->|"窗口关不掉"| p24["24 关窗"]
  odd -->|"内联脚本或图片不工作"| fe["21 或 22 或 23"]

💬 关联讨论

发起讨论
加载中...