macOS SwiftPM App Packaging(无 Xcode)
用途
该技能用于在不创建 Xcode 工程的前提下,引导生成完整的 SwiftPM macOS 应用目录,并完成构建、打包与运行。适合需要从零搭建 macOS 应用布局、使用 SwiftPM 目标与资源、以及进行打包发布的场景。
主要能力
- 提供 assets/templates/bootstrap/ 作为起步骨架,包含 Package.swift、Sources/ 与 version.env。
- 提供打包与发布参考文档:references/packaging.md 与 references/release.md。
- 提供多个脚本模板:package_app.sh(构建二进制、创建 .app bundle、复制资源、签名)、compile_and_run.sh(开发循环:结束运行中的应用、打包、启动)、build_icon.sh(从 Icon Composer 文件生成 .icns,需安装 Xcode)、sign-and-notarize.sh(公证、装订、打包发布版 zip)、make_appcast.sh(生成 Sparkle 更新条目)、setup_dev_signing.sh(创建稳定的开发代码签名身份)、launch.sh(简单启动已打包的 .app)、version.env(打包脚本使用的示例版本文件)。
使用方式(两步工作流)
第一步:引导项目文件夹
- 将 assets/templates/bootstrap/ 复制到新仓库。
- 重命名 Package.swift、Sources/MyApp/ 与 version.env 中的 MyApp。
- 自定义 APP_NAME、BUNDLE_ID 与版本号。
第二步:构建、打包并运行引导后的应用
- 将 assets/templates/ 中的脚本复制到仓库(例如 Scripts/)。
- 构建/测试:swift build 与 swift test。
- 打包:Scripts/package_app.sh。
- 运行:Scripts/compile_and_run.sh(推荐)或 Scripts/launch.sh。
- 发布(可选):Scripts/sign-and-notarize.sh 与 Scripts/make_appcast.sh。
- 打标签与 GitHub 发布(可选):创建 git tag,将 zip/appcast 上传到 GitHub release 并发布。
最小端到端示例
从引导到运行应用的最短路径:
1. 复制并重命名骨架
cp -R assets/templates/bootstrap/ ~/Projects/MyApp cd ~/Projects/MyApp sed -i '' 's/MyApp/HelloApp/g' Package.swift version.env
2. 复制脚本
cp assets/templates/package_app.sh Scripts/ cp assets/templates/compile_and_run.sh Scripts/ chmod +x Scripts/*.sh
3. 构建并启动
swift build Scripts/compile_and_run.sh
验证检查点
在关键步骤后运行以下命令,以便在进入下一阶段前尽早发现失败。
打包后(Scripts/package_app.sh):
确认 .app bundle 结构完整
ls -R build/HelloApp.app/Contents
检查二进制文件存在且可执行
file build/HelloApp.app/Contents/MacOS/HelloApp
签名后(Scripts/sign-and-notarize.sh 或 ad-hoc 开发签名):
检查签名与 entitlements
codesign -dv --verbose=4 build/HelloApp.app
在本地验证 bundle 通过 Gatekeeper 检查
spctl --assess --type execute --verbose build/HelloApp.app
公证与装订后:
确认装订票据已附加
stapler validate build/HelloApp.app
重新运行 Gatekeeper 确认公证被识别
spctl --assess --type execute --verbose build/HelloApp.app
常见公证失败
- 症状:The software asset has already been uploaded。可能原因:同一版本重复提交。恢复:在 version.env 中提升 BUILD_NUMBER 并重新打包。
- 症状:Package Invalid: Invalid Code Signing Entitlements。可能原因:.entitlements 文件中的 entitlements 与 provisioning 不匹配。恢复:对照 Apple 允许集合审计 entitlements,移除不支持的键。
- 症状:The executable does not have the hardened runtime enabled。可能原因:codesign 调用缺少 --options runtime 标志。恢复:编辑 sign-and-notarize.sh,在所有 codesign 调用中添加 --options runtime。
- 症状:Notarization hangs / no status email。可能原因:xcrun notarytool 网络或凭据问题。恢复:运行 xcrun notarytool history 检查状态;若 App Store Connect API key 过期则重新导出。
- 症状:stapler validate fails after successful notarization。可能原因:票据尚未传播。恢复:等待约 60 秒,然后重新运行 xcrun stapler staple。
模板说明
- assets/templates/package_app.sh:构建二进制、创建 .app bundle、复制资源、签名。
- assets/templates/compile_and_run.sh:开发循环,结束运行中的应用、打包、启动。
- assets/templates/build_icon.sh:从 Icon Composer 文件生成 .icns(需要安装 Xcode)。
- assets/templates/sign-and-notarize.sh:公证、装订并打包发布版 zip。
- assets/templates/make_appcast.sh:为更新生成 Sparkle appcast 条目。
- assets/templates/setup_dev_signing.sh:创建稳定的开发代码签名身份。
- assets/templates/launch.sh:用于已打包 .app 的简单启动器。
- assets/templates/version.env:打包脚本使用的示例版本文件。
- assets/templates/bootstrap/:最小 SwiftPM macOS 应用骨架(Package.swift、Sources/、version.env)。
注意事项
- 保持 entitlements 与签名配置显式;编辑模板脚本,而不是重新实现。
- 如果不使用 Sparkle 进行更新,请移除 Sparkle 相关步骤。
- Sparkle 依赖 bundle 构建号(CFBundleVersion),因此每次更新都必须提升 version.env 中的 BUILD_NUMBER。
- 对于菜单栏应用,打包时设置 MENU_BAR_APP=1,以在 Info.plist 中输出 LSUIElement。