存档说明(2026-07-12): 在根目录清理中从
.planning/移到这里。 下文中的内部.planning//specs/路径均为历史路径——这些目录树已被移除;请参阅 git 历史。
决策 — AppImage AppRun 注入策略¶
日期: 2026-05-20
阶段: 01(安装 + 令牌持久化 + 文档 + 错误体验)
波次: 3
计划: 01-03-PLAN.md
问题: #56(Fedora 44 / Ubuntu 24.04 上的 AppImage 白屏问题)
已解决的未决问题: RESEARCH.md 中的 #1(“AppRun 在这个 Tauri 项目树中位于何处?”)
TL;DR¶
Tauri 2 的 AppImage 打包器会在 .AppImage squashfs 内自动生成一个 AppRun shell 启动器。截至撰写本文时,Tauri 2.x 中并没有内置的 bundle.linux.appimage.template 配置键。所选的注入策略是:
一个来自
frontend/src-tauri/appimage/AppRun的自定义AppRun模板,通过beforeBundleCommand安装到 Tauri 的项目本地 AppImage 工具缓存中。然后 Tauri 会将该启动器复制到 AppDir。
负责预置缓存的脚本位于 scripts/inject-apprun.sh。最终的发布冒烟测试会解包 AppImage,并将其 AppRun 与源模板逐字节比较,从而确保默认启动器不会再次被静默打包发布。
背景 — Tauri 2 自动生成的 AppRun 做了什么¶
当运行 cargo tauri build --bundles appimage 时,Tauri 的打包器会:
- 在
target/release/bundle/appimage/${appname}.AppDir/下创建暂存目录 - 将主二进制文件放到
usr/bin/${binary_name} - 在
${appname}.AppDir/AppRun生成一个AppRunshell 脚本,该脚本会: - 将
LD_LIBRARY_PATH设置为随附的库目录 - 将
XDG_DATA_DIRS设置为包含 AppDir 的usr/share - 使用
"$@"执行usr/bin/${binary_name} - 通过
appimagetool将 AppDir 打包为单文件 AppImage
自动生成的 AppRun 不会设置 WEBKIT_DISABLE_COMPOSITING_MODE。在 Fedora 44(以及任何随附 WebKitGTK 2.44.x / 2.46.x 且使用 Wayland 的发行版)上,这会在首次启动时表现为白屏——这些 WebKit 版本中的 GPU 合成路径存在已记录的回归问题,会导致界面空白。
考虑的方案¶
A. 通过 tauri.conf.json 配置键使用自定义 AppRun 模板¶
状态:截至 2026-05,Tauri 2 稳定版中不存在此配置。 Tauri 的 bundle.linux.appimage 接受 bundleMediaFramework: bool 和 files: HashMap<PathBuf, PathBuf>,但不接受 appRun / template 键。跟踪问题 tauri-apps/tauri#7616 仍然开放。
B. 通过 beforeBundleCommand 替换暂存的 AppDir(已否决)¶
beforeBundleCommand 在 tauri-bundler 创建 AppDir 之前运行。旧的实现会对该未来目录进行 glob 匹配,结果什么都没找到,于是以 0 状态退出,v0.4.2 最终随附了 Tauri 的默认启动器。这种时序无法做到可靠。
C. 预置 Tauri 的本地 AppImage 工具缓存(已选择)¶
通过 bundle.useLocalToolsDir,Tauri 会从 target/.tauri/AppRun-<arch> 读取其启动器,并将其复制到新创建的 AppDir 中。该 hook 会在打包器运行前,将我们的启动器安装到这个现有的扩展点。bundle.linux.appimage.files 会把生成的 WebKitGTK 版本标记携带到 usr/lib 中,启动器会在这里读取该标记。
D. 使用 appimagetool 在打包后进行重打包¶
状态:已否决。 这需要在 Tauri 生成 AppImage 后解包其 squashfs,替换 AppRun,重新运行 appimagetool --no-appstream,并重新签名。虽然可行,但会令打包时间翻倍,并将 appimagetool 额外作为发布流水线的显式依赖。策略 B 可以避免这两点。
所选策略¶
策略 C — 项目本地 Tauri 工具缓存 + 自定义 AppRun 模板。
文件¶
| 路径 | 用途 |
|---|---|
frontend/src-tauri/appimage/AppRun |
自定义启动器 shell 脚本(唯一事实来源,受版本控制) |
frontend/src-tauri/appimage/AppRun.test.sh |
Shell 单元测试(W-1)— 针对 WebKit 版本条件的 4 个用例 |
scripts/inject-apprun.sh |
预置 target/.tauri/AppRun-<arch> 并生成随附的 WebKitGTK 版本标记 |
scripts/inject-apprun.test.sh |
缓存预置、可执行权限和版本标记的回归测试 |
frontend/src-tauri/tauri.conf.json |
启用本地工具缓存并打包其生成的标记 |
.github/workflows/release.yml |
解包最终产物并拒绝默认启动器或缺失标记 |
接入方式¶
// frontend/src-tauri/tauri.conf.json
{
"build": {
"beforeBundleCommand": "bash ../scripts/inject-apprun.sh"
// ... existing keys
}
}
该 hook 在非 Linux 主机上是空操作。在 Linux 上,未知架构或缺少 WebKitGTK 版本会构成构建失败,而不是产出一个静默损坏的工件。
为什么 WEBKIT_DISABLE_COMPOSITING_MODE 是有条件的,而不是无条件设置¶
根据 RESEARCH.md 中的 Pitfall #3:在健康的 WebKit 版本(2.48+)上设置此环境变量,会重新引入它原本旨在绕过的合成 bug(在 Apple Silicon Linux 移植版上)。我们通过 pkg-config 检测 WebKit 版本(同时查询 webkit2gtk-4.1 和 webkit2gtk-4.0),并且只在已知有问题的 2.44.x 和 2.46.x 范围内设置该环境变量,再加上 pkg-config absent / unknown version 回退(故障安全地采用该规避措施)。
未来维护¶
当 Tauri 2 提供一等公民的 appRun 模板键时(参见未关闭的 tauri-apps/tauri#7616),迁移步骤为:
- 将
frontend/src-tauri/appimage/AppRun的内容移入新的配置键 - 删除
scripts/inject-apprun.sh及其缓存预置测试 - 移除调用它的
beforeBundleCommand行 - 保持
AppRun.test.sh原样——它仍然验证条件逻辑
在此之前,本文所述的策略即为文档化的路径。
参考来源¶
- Tauri 2 —
beforeBundleCommand钩子 — HIGH - Tauri issue #7616 — 自定义 AppRun 模板支持 — HIGH(状态:开放)
- WebKitGTK 2.44 缺陷跟踪器 — Fedora 上的 Wayland 白屏 — HIGH
- AppImage AppRun 参考 — HIGH
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 om/VoiceStudio