关于 releasing-macos-apps
releasing-macos-apps 是面向 macOS 应用开发者的发布工作流技能,涵盖签名、公证、Sparkle 更新、DMG 制作和 GitHub 发布,并提供逐步验证流程。
主要功能
- 01版本更新、构建与归档
- 02代码签名与公证
- 03Sparkle 更新签名和 appcast
- 04DMG 安装包制作
- 05管理 GitHub 发布资源
- 06发布验证清单
适用场景
- 01准备经过签名的 macOS 应用发布
- 02发布 Sparkle 更新和 DMG 安装包
- 03排查公证或发布验证问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jamesrochabrun/ skills --skill releasing-macos-apps安装后在 Claude Code 中输入/releasing-macos-apps确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
NOTARIZATION.mdSPARKLE.mdTROUBLESHOOTING.md详细介绍
发布 macOS 应用
使用 Sparkle 自动更新、DMG 安装器和 GitHub 发布来创建经过公证的 macOS 应用发布的完整工作流。
发布检查清单
复制此检查清单并跟踪进度:
Release Progress:
- [ ] Step 1: Check prerequisites (certificates, credentials)
- [ ] Step 2: Update version in .xcconfig file
- [ ] Step 3: Build and archive the app
- [ ] Step 4: Export with proper code signing
- [ ] Step 5: Create zip and generate Sparkle signature
- [ ] Step 6: Create DMG with Applications folder
- [ ] Step 7: Submit for notarization
- [ ] Step 8: Staple notarization ticket to DMG
- [ ] Step 9: Update appcast.xml with new signature
- [ ] Step 10: Commit and push changes
- [ ] Step 11: Update GitHub release assets
- [ ] Step 12: Verify DMG and version number
前提条件
开始发布前,请确认:
- 已安装且有效的 Apple Developer ID Application 证书
- 用于公证的 Apple ID 凭据:
- Apple ID 邮箱
- App 专用密码(在 appleid.apple.com 生成)
- Team ID
- 用于签署更新的 Sparkle 私钥
- 已安装并完成身份验证的 GitHub CLI(
gh) - 已确定版本配置文件的位置(通常是
.xcconfig文件)
检查证书:
security find-identity -v -p codesigning | grep "Developer ID Application"
第 1 步:更新版本
找到版本配置文件(通常是 ProjectName.xcconfig 或 project.pbxproj)。
对于 .xcconfig 文件:
# Edit the APP_VERSION line
# Example: APP_VERSION = 1.0.9
验证更新:
xcodebuild -project PROJECT.xcodeproj -showBuildSettings | grep MARKETING_VERSION
第 2 步:构建并归档
使用新版本归档应用:
xcodebuild -project PROJECT.xcodeproj \
-scheme SCHEME_NAME \
-configuration Release \
-archivePath ~/Desktop/APP-VERSION.xcarchive \
archive
确认已创建归档:
ls -la ~/Desktop/APP-VERSION.xcarchive
第 3 步:导出并进行代码签名
创建导出选项文件:
cat > /tmp/ExportOptions.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>destination</key>
<string>export</string>
<key>method</key>
<string>developer-id</string>
<key>signingStyle</key>
<string>automatic</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>signingCertificate</key>
<string>Developer ID Application</string>
</dict>
</plist>
EOF
将 YOUR_TEAM_ID 替换为你的实际团队 ID。
导出归档:
xcodebuild -exportArchive \
-archivePath ~/Desktop/APP-VERSION.xcarchive \
-exportPath ~/Desktop/APP-VERSION-Export \
-exportOptionsPlist /tmp/ExportOptions.plist
验证导出应用的版本:
defaults read ~/Desktop/APP-VERSION-Export/APP.app/Contents/Info.plist CFBundleShortVersionString
这里应显示新的版本号。
验证代码签名:
codesign -dvvv ~/Desktop/APP-VERSION-Export/APP.app
在 Authority 行中查找 “Developer ID Application”。
第 4 步:创建 Zip 并生成 Sparkle 签名
创建用于 Sparkle 自动更新的 Zip 文件:
cd ~/Desktop/APP-VERSION-Export
ditto -c -k --keepParent APP.app APP.app.zip
生成 Sparkle EdDSA 签名(系统会提示输入私钥):
echo "YOUR_SPARKLE_PRIVATE_KEY" | \
~/Library/Developer/Xcode/DerivedData/PROJECT-HASH/SourcePackages/artifacts/sparkle/Sparkle/bin/sign_update \
APP.app.zip --ed-key-file -
输出格式:
sparkle:edSignature="BASE64_SIGNATURE" length="FILE_SIZE"
保存签名和文件大小,以便更新 appcast.xml。
更多详情请参阅 SPARKLE.md。
第 5 步:创建带有 Applications 文件夹的 DMG
创建带有 Applications 文件夹符号链接的 DMG 安装器,以支持拖放安装:
TEMP_DMG_DIR="/tmp/APP_dmg" && \
rm -rf "${TEMP_DMG_DIR}" && \
mkdir -p "${TEMP_DMG_DIR}" && \
cp -R ~/Desktop/APP-VERSION-Export/APP.app "${TEMP_DMG_DIR}/" && \
ln -s /Applications "${TEMP_DMG_DIR}/Applications" && \
hdiutil create -volname "APP VERSION" \
-srcfolder "${TEMP_DMG_DIR}" \
-ov -format UDZO ~/Desktop/APP-VERSION.dmg && \
rm -rf "${TEMP_DMG_DIR}"
确认 DMG 内容:
hdiutil attach ~/Desktop/APP-VERSION.dmg -readonly -nobrowse -mountpoint /tmp/verify_dmg && \
ls -la /tmp/verify_dmg && \
hdiutil detach /tmp/verify_dmg
你应能看到 APP.app 和 Applications(符号链接)。
第 6 步:提交公证
将 DMG 提交给 Apple 进行公证(系统会提示输入凭据):
xcrun notarytool submit ~/Desktop/APP-VERSION.dmg \
--apple-id [email protected] \
--team-id YOUR_TEAM_ID \
--password YOUR_APP_SPECIFIC_PASSWORD \
--wait
--wait 标志会让命令等待处理完成(通常需要 1-2 分钟)。
预期输出:
Processing complete
id: [submission-id]
status: Accepted
如果状态为 “Invalid”,请获取详细日志:
xcrun notarytool log SUBMISSION_ID \
--apple-id [email protected] \
--team-id YOUR_TEAM_ID \
--password YOUR_APP_SPECIFIC_PASSWORD
公证问题排查请参阅 NOTARIZATION.md。
第 7 步:附加公证票据
将公证票据附加到 DMG:
xcrun stapler staple ~/Desktop/APP-VERSION.dmg
预期输出:
The staple and validate action worked!
验证公证:
spctl -a -vvv ~/Desktop/APP-VERSION-Export/APP.app
应显示:
accepted
source=Notarized Developer ID
第 8 步:更新 appcast.xml
使用第 4 步获取的新版本、签名和文件大小更新 Sparkle appcast 文件:
<item>
<title>Version X.X.X</title>
<link>https://github.com/USER/REPO</link>
<sparkle:version>X.X.X</sparkle:version>
<sparkle:channel>stable</sparkle:channel>
<description><![CDATA[
Release version X.X.X
]]></description>
<pubDate>DAY, DD MMM YYYY HH:MM:SS -0700</pubDate>
<enclosure
url="https://github.com/USER/REPO/releases/download/vX.X.X/APP.app.zip"
sparkle:version="X.X.X"
sparkle:edSignature="SIGNATURE_FROM_STEP_4"
length="FILE_SIZE_FROM_STEP_4"
type="application/octet-stream" />
</item>
注意: gitleaks 提交前钩子可能会将 Sparkle 签名标记为潜在密钥。这是误报——EdDSA 签名是公开的,可以安全提交。如有需要,请使用 git commit --no-verify。
第 9 步:提交并推送更改
提交版本更新和 appcast 更改:
git add PROJECT.xcconfig appcast.xml
git commit --no-verify -m "Bump version to X.X.X
Update appcast.xml with new version, Sparkle signature, and file size.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>"
git push
第 10 步:更新 GitHub 发布
创建或更新 GitHub 发布并添加新资源:
对于新发布:
gh release create vX.X.X \
--title "APP vX.X.X" \
--notes "Release version X.X.X" \
~/Desktop/APP-VERSION.dmg \
~/Desktop/APP-VERSION-Export/APP.app.zip
对于更新现有发布:
# Upload new assets (overwrites existing with --clobber)
gh release upload vX.X.X \
~/Desktop/APP-VERSION.dmg \
~/Desktop/APP-VERSION-Export/APP.app.zip \
--clobber
关于资源命名的说明: 上传的文件名将成为资源名称。若要使用指定名称上传:
# Copy to desired name first
cp ~/Desktop/APP-1.0.9.dmg /tmp/APP.dmg
gh release upload vX.X.X /tmp/APP.dmg
验证发布资源:
gh release view vX.X.X --json assets -q '.assets[] | "\(.name) - \(.size) bytes"'
第 11 步:最终验证
确认发布正常运行:
检查应用中的版本:
defaults read /Applications/APP.app/Contents/Info.plist CFBundleShortVersionString
应显示:X.X.X
测试 DMG:
- 从 GitHub 发布下载 DMG
- 打开 DMG
- 确认其中有 Applications 文件夹,可用于拖放安装
- 将应用拖到 Applications 并启动
- 应能正常打开,不出现任何“恶意软件”或安全警告
测试 Sparkle 更新:
- 使用旧版本的用户应收到自动更新通知
- 更新应能顺利下载并安装
常见问题
如果遇到问题,请参阅 TROUBLESHOOTING.md 查找以下问题的解决方案:
- 重建后版本未更新
- DMG 缺少 Applications 文件夹
- 公证失败
- “恶意应用”警告
- Sparkle 签名问题
- CI/CD 失败
快速参考
检查版本:
defaults read /path/to/APP.app/Contents/Info.plist CFBundleShortVersionString
检查代码签名:
codesign -dvvv /path/to/APP.app
检查公证:
spctl -a -vvv /path/to/APP.app
获取 Sparkle sign_update 路径:
find ~/Library/Developer/Xcode/DerivedData -name sign_update -type f