mcpField
D
desktop-and-build-footguns

desktop-and-build-footguns

github.com/maxrave-dev开发1.7k89 次安装1 周前更新
代码仓库

关于 desktop-and-build-footguns

面向桌面 JVM 和 Compose Multiplatform 应用开发者的参考技能,按症状整理原生绑定、媒体、打包和构建陷阱,并提供做法与验证命令。

主要功能

  1. 0124 篇主题明确的参考文件
  2. 02JVM 原生绑定与媒体指导
  3. 03打包、签名和构建陷阱
  4. 04故障症状与可行模式
  5. 05用于验证改动的命令

适用场景

  1. 01排查干净环境中的原生库故障
  2. 02在桌面 JVM 应用中嵌入媒体引擎
  3. 03检查 macOS 应用打包和签名问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/maxrave-dev/kotlin-footguns --skill desktop-and-build-footguns

安装后在 Claude Code 中输入/desktop-and-build-footguns确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
arm64-native-gap-audit.md
buildkonfig-secrets-flavors.md
bundled-native-soname-conflict.md
ci-flaky-timing-luck.md
compose-desktop-video-no-swingpanel.md
config-fails-open-verify-artifact.md
conveyor-desktop-packaging.md
desktop-deep-link-plumbing.md
desktop-system-media-integration.md
embed-media-engine-desktop.md
github-actions-multiplatform-release.md
gradle-config-resolved-too-early.md
jna-native-binding-traps.md
jvm-desktop-memory-footprint.md
macos-codesign-sidecar-strip.md
macos-lsenvironment-path-pin.md
merge-split-av-streams-desktop.md
native-artifact-for-embedding.md
r8-proguard-desktop-survival.md
reproducible-native-bundling-two-tasks.md
transitive-version-pinning.md
upstream-lib-bug-workaround-template.md
windows-msix-offline-installer.md
windows-vm-detection-post-wmic.md

详细介绍

桌面 JVM 与构建陷阱

从一个生产级 Kotlin 和 Compose Multiplatform 应用中整理出的 24 个陷阱,每个都单独放在 references/ 下的一个简短文件中。每个文件都提供可行的模式、陷阱(具体说明实际使用中会如何失败,以及原因),以及一个验证方法部分,其中列出了可在用户自己的代码树中运行的命令。

如何使用此索引。 将即将编写的代码或正在排查的问题症状与下方条目进行匹配:每个条目都会说明其主题,以及遇到何种症状时应查看该条目。提出代码或修复方案之前,请使用 Read 工具阅读所有可能适用的文件;每个文件都少于 150 行。如果验证命令中引用了源项目的路径,请替换为用户代码树中的对应路径。

交叉引用。 文件中反引号标注的陷阱名称若未列于此处,则位于相邻区域技能中:使用 glob ../*/references/<name>.md 打开。

桌面 JVM 上的原生代码

  • jna-native-binding-traps — 使用 JNA(Java Native Access)手写 C 库的 JVM 绑定——在 Windows 上含义不同的开放标志选项、按原始偏移读取的结构体、绑定会以弱引用持有的回调、注册过晚的搜索路径,以及如何证明实际打开的是哪个文件。当绑定在每位开发者的机器上都能运行,却在干净环境中失败时,或者当第一次符号查找就报出“找不到指定的模块”,而库明明就在那儿时,适合参考。
  • native-artifact-for-embedding — 构建 JVM 应用实际能够加载并随应用分发的原生共享库——为什么预构建的便携包通常根本不是可加载的库、如何在你支持的最旧基础系统上构建、运行路径的选择、哪些库应刻意不放进包中,以及如何通过加载并初始化的冒烟测试来决定是否通过构建。当打包的原生库在每位开发者的机器上都能运行,却在干净环境中失败时,或者当你发现应用一直悄悄使用系统范围内的副本,而不是你自己的副本时,适合参考。
  • bundled-native-soname-conflict — 随桌面应用打包的原生库连带捎上了它自己的通用基础库副本;该副本一旦被你的原生库加载,就会为整个进程占用共享对象名称;随后,一个不相关的平台 API 报告缺少符号,并指出第三个库。当打开链接或系统对话框的功能在你的机器上能用,却在用户的机器上悄无声息地失效时;当平台 API 在运行时报告不受支持时;当你要决定原生包可以包含什么时;或者当针对这个问题合并的修复似乎对用户毫无影响时,适合参考。
  • macos-codesign-sidecar-strip — 在 macOS 应用包中解压任何内容之后、签署应用包之前,清除 macOS 归档工具在带有扩展属性的文件旁写入的 ._* 伴随文件,因为签名工具会将这些伴随文件作为普通包成员封存,而操作系统会在文件管理器首次访问应用时将其删除。当已签名的 macOS 应用在构建机器上能正常启动,用户却收到“应用已损坏,无法打开”的提示时,或者签名验证报告封存资源缺失时,适合参考。
  • jvm-desktop-memory-footprint — 诚实地衡量并降低桌面 JVM 应用的内存占用——查看堆内存与总占用的比例,而不是常驻内存数值;进行一项能够区分内存泄漏和分配器保留空闲页的实验;并了解为什么每线程分配器 arena 会让内存占用取决于用户的核心数。当桌面应用的内存占用稳定在接近 1 GB,或在长时间运行期间持续增长时;当高配机器的用户报告的内存占用远高于你能复现的情况时;或者在调整任何分配器或垃圾回收器标志之前,适合参考。
  • embed-media-engine-desktop — 在 JVM 桌面应用中嵌入原生 C 媒体引擎——每个媒体项使用一个句柄、使用专用事件泵线程、固定输出驱动并按正确顺序创建渲染上下文、将所有属性写入限制在同时释放句柄的线程上、检测引擎可选选项是否可用,以及按引擎解析数字的方式格式化数字。当应用在设置属性时停止运行、引擎自行打开一个窗口,或者应用明明设置了某个值却被悄悄忽略时,适合参考。
  • merge-split-av-streams-desktop — 通过媒体引擎的编辑列表 URL 格式,在 JVM 桌面应用中将单独的纯音频流和纯视频流作为一个来源播放——这是合并媒体来源的桌面端方案;其中包括为流 URL 添加长度前缀的引用方式,以及为什么在交叉淡入过程中不能准备一个合并的双 URL 项。当桌面视频播放时完全没有声音,日志中也没有任何信息时;当流 URL 在第一个分号处被截断时;或者当淡入视频曲目时,正在播放的歌曲会提前被截断时,适合参考。
  • compose-desktop-video-no-swingpanel — 在 Compose Desktop 中渲染原生媒体引擎的视频帧,而不嵌入重量级 AWT 面板——通过 StateFlow 发布不可变的已完成帧快照,并使用普通 Image 绘制;在 UI 线程之外进行转换;匹配引擎的像素字节顺序;并让引擎决定如何适配画面。当嵌入式视频无论 z-order 如何都覆盖所有内容、滚动时总是落后一帧、第二块屏幕显示播放器的瞬间第一块屏幕就变黑、红蓝颜色颠倒,或者出现无法通过 content-scale 去除的黑边时,适合参考。
  • desktop-system-media-integration — 通过一个统一门面,将桌面应用接入各操作系统的系统正在播放界面和媒体控制界面,让原生初始化失败时禁用集成,而绝不影响播放。内容涵盖:如何在打包应用中于平台主线程上进行初始化、如何通过 JVM 的原生访问层调用操作系统的媒体框架、如何强引用传给操作系统的回调,以及如何将集成限制在其自身线程中。当媒体键或系统正在播放面板在普通 Gradle 运行时正常工作、在打包应用中却无法工作时;当界面只显示应用名称而不是曲目标题时;或者媒体控制回调过一段时间后不再触发时,适合参考。
  • upstream-lib-bug-workaround-template — 当你无法修补的库存在缺陷时,应采用的变通方案结构——尽可能追溯问题机制、说明你接受的取舍、留出故障时能够降级而不是静默失效的退路、写明移除方案的明确条件,并记录为什么你的使用模式会触发库自身用户从未遇到的缺陷。当你准备因为他人的缺陷而固定某项设置、避开某条代码路径或增加防御性分支时,或者当你要审查的变通方案注释没有说明何时可以删除时,适合参考。
  • macos-lsenvironment-path-pin — 在打包的 macOS 应用属性列表中声明 Launch Services 环境字典(LSEnvironment),会将进程的 PATH 固定为四个裸系统目录,因此应用启动的每个外部进程都会无法访问安装在其他位置的所有内容。在向 macOS 应用包添加任何环境变量之前;当应用调用的辅助程序仅在已安装应用的用户环境中报告“找不到命令”时;或者当某项功能从终端启动时正常工作、从 Dock 启动时却悄无声息地失效时,适合参考。

打包、签名、CI 与构建

  • conveyor-desktop-packaging — 使用配置驱动的打包工具为 JVM 桌面应用打包,该工具会静默忽略未知键,其配置采用 HOCON 格式:哪些键绑定到应用级别、哪些绑定到操作系统专属区段或嵌套组,如何通过命令行覆盖键值,如何固定打包 JDK,以及会悄悄固定 PATH 的环境区块。当你编写的键对生成的安装程序毫无影响,而构建日志也没有报错时,可以参考此文。
  • config-fails-open-verify-artifact — 对于会以开放方式失败并忽略未知键的格式,如何根据生成的产物而非配置来验证配置驱动的功能:双构建 A/B 差异对比、要搜索的产物指纹,以及防止回归的 CI 断言。当配置键看起来正确、构建也成功,但配置的功能却从未被观察到正常工作时,可以参考此文。
  • desktop-deep-link-plumbing — 在 JVM 桌面应用中端到端接入自定义 URL 方案:各操作系统上的注册、启动时的参数筛选器、单实例转发,以及将回调令牌传递到应用状态。当点击链接或从浏览器重定向返回时,应用只是切换到前台,而本应完成的流程却停在那里,可以参考此文。
  • r8-proguard-desktop-survival — 对 JVM 桌面应用运行字节码压缩器:哪些优化类别必须关闭以及原因、混淆为何会破坏渲染和反射层、使用本机绑定、协程和 HTTP 客户端的应用所需的 keep 规则类别,以及如何将压缩后的 JAR 提供给打包工具。当发布构建启动时出现验证错误、渲染出透明或空白界面,或仅在打包后的安装程序中失败而开发运行正常时,可以参考此文。
  • gradle-config-resolved-too-early — 诊断 Gradle 的“cannot mutate a configuration after its child configuration was resolved”类错误:为什么错误消息提到的是你修改的配置,而不是解析它的插件;如何针对最小可运行模板逐个排查插件;以及有哪些修复方法已被证实行不通。当添加一行再普通不过的依赖声明就导致构建无法配置,且无论如何改写那一行都无济于事时,可以参考此文。
  • transitive-version-pinning — 处理传递依赖的严格版本约束覆盖你所选版本,并导致整个构建中的共享底层库升级或降级的情况:如何查明是谁固定了什么版本、何时应强制恢复某个版本而非将所有依赖与固定版本对齐,以及如何记录版本固定以免有人升级后再次引发故障。当添加一个无关的库后,运行时在你未修改的组件中(渲染过程内)出现缺少方法的故障时,可以参考此文。
  • reproducible-native-bundling-two-tasks — 将预构建的本机库交付给多平台桌面构建:拆分为两个 Gradle 任务,并分别在不同环境中运行。开发机器上的任务负责构建各平台切片、打包 tarball 并打印其摘要;CI 任务只负责下载,并与构建文件中固定的摘要进行校验。当 CI 不应安装本机工具链、升级本机依赖后却悄悄打包了旧二进制文件,或打包后的安装程序启动时完全缺少本机库时,可以参考此文。
  • windows-vm-detection-post-wmic — 在 Windows 11 移除传统命令行管理查询工具后,检测桌面应用是否运行在虚拟机中:通过 PowerShell 查询管理层、探测制造商和型号字段,并有意选择检测失败时的处理方向。当透明或无边框窗口在虚拟机中无法渲染任何内容,但进程仍在运行;或多年正常工作的检测探针突然在所有现代主机上都返回空值时,可以参考此文。
  • windows-msix-offline-installer — 交付用户无需托管更新站点即可安装的自签名 MSIX(现代 Windows 应用程序包格式):在软件包旁附上安装脚本和签名证书、编写先信任再侧载的步骤,并确保各版本使用相同的签名密钥。当双击打包工具的输出无法安装、其封装安装程序在获取返回 404 的 URL 时崩溃,或新构建无法覆盖安装旧版本时,可以参考此文。
  • arm64-native-gap-audit — 在为多平台桌面构建承诺支持某个 CPU 架构之前,审查每个原生依赖是否都提供对应架构的切片。只要缺少一个原生依赖,整个目标平台就会在首次使用时而非构建时崩溃,因此应将审查做成针对已解析产物的可重复命令,并在每次依赖升级时重新运行。当你在考虑是否添加 ARM64 目标平台,或构建已成功打包并安装,却在首次使用数据库、渲染器或媒体层时崩溃,可以参考此文。
  • ci-flaky-timing-luck — 找出并修复那些只是碰巧赶上时序才通过的 CI 步骤:异步卸载同名已挂载卷的操作与下一轮挂载发生冲突,以及下载器悄悄将错误页面保存为产物。当某个连续数月运行正常的步骤在 Runner 映像更新后开始失败,或作业成功后,几分钟后的步骤却因收到损坏或空文件而失败时,可以参考此文。
  • github-actions-multiplatform-release — 为多平台桌面应用设计 GitHub Actions 发布流水线:由一个 Linux Runner 交叉构建所有平台的产物,另一个精简的 macOS 作业仅执行确实需要 macOS 的步骤;两者之间交接产物,不在昂贵的 Runner 上编译。当你的发布工作流运行三个操作系统作业、每个都从头构建所有内容,或 macOS 用户在流水线正确签名的应用上遇到硬性阻止对话框时,可以参考此文。
  • buildkonfig-secrets-flavors — 使用 BuildKonfig 将构建时配置接入 Kotlin Multiplatform 应用:从未跟踪的本地属性文件读取密钥,并将其注入为生成的常量;无密钥分支使用空字符串,让功能自行禁用,而不是导致构建失败;另外还包括较新版本 Gradle 对生成源码所需的任务依赖配置。当通用代码需要编译时常量、开源构建不得包含凭据,或构建因生成源码任务与使用方之间存在隐式依赖而失败时,可以参考此文。

评论

支持 Markdown