releasing-macos-apps

安装量: 64
排名: #11815

安装

npx skills add https://github.com/jamesrochabrun/skills --skill releasing-macos-apps

Releasing macOS Apps

Complete workflow for creating notarized macOS app releases with Sparkle auto-updates, DMG installers, and GitHub releases.

Release Checklist

Copy this checklist and track progress:

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

Prerequisites

Before starting a release, verify:

Apple Developer ID Application certificate installed and valid Apple ID credentials for notarization: Apple ID email App-specific password (generate at appleid.apple.com) Team ID Sparkle private key for signing updates GitHub CLI (gh) installed and authenticated Version configuration location identified (usually .xcconfig file)

Check certificate:

security find-identity -v -p codesigning | grep "Developer ID Application"

Step 1: Update Version

Locate your version configuration file (commonly ProjectName.xcconfig or project.pbxproj).

For .xcconfig files:

Edit the APP_VERSION line

Example: APP_VERSION = 1.0.9

Verify the update:

xcodebuild -project PROJECT.xcodeproj -showBuildSettings | grep MARKETING_VERSION

Step 2: Build and Archive

Archive the app with the new version:

xcodebuild -project PROJECT.xcodeproj \ -scheme SCHEME_NAME \ -configuration Release \ -archivePath ~/Desktop/APP-VERSION.xcarchive \ archive

Verify archive was created:

ls -la ~/Desktop/APP-VERSION.xcarchive

Step 3: Export with Code Signing

Create export options file:

cat > /tmp/ExportOptions.plist << 'EOF'

destination export method developer-id signingStyle automatic teamID YOUR_TEAM_ID signingCertificate Developer ID Application EOF

Replace YOUR_TEAM_ID with your actual team ID.

Export the archive:

xcodebuild -exportArchive \ -archivePath ~/Desktop/APP-VERSION.xcarchive \ -exportPath ~/Desktop/APP-VERSION-Export \ -exportOptionsPlist /tmp/ExportOptions.plist

Verify the exported app version:

defaults read ~/Desktop/APP-VERSION-Export/APP.app/Contents/Info.plist CFBundleShortVersionString

This should show the new version number.

Verify code signing:

codesign -dvvv ~/Desktop/APP-VERSION-Export/APP.app

Look for "Developer ID Application" in the Authority lines.

Step 4: Create Zip and Generate Sparkle Signature

Create zip file for Sparkle auto-updates:

cd ~/Desktop/APP-VERSION-Export ditto -c -k --keepParent APP.app APP.app.zip

Generate Sparkle EdDSA signature (you'll be prompted for the private key):

echo "YOUR_SPARKLE_PRIVATE_KEY" | \ ~/Library/Developer/Xcode/DerivedData/PROJECT-HASH/SourcePackages/artifacts/sparkle/Sparkle/bin/sign_update \ APP.app.zip --ed-key-file -

Output format:

sparkle:edSignature="BASE64_SIGNATURE" length="FILE_SIZE"

Save both the signature and length for updating appcast.xml.

For more details, see SPARKLE.md.

Step 5: Create DMG with Applications Folder

Create DMG installer with Applications folder symlink for drag-and-drop installation:

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}"

Verify DMG contents:

hdiutil attach ~/Desktop/APP-VERSION.dmg -readonly -nobrowse -mountpoint /tmp/verify_dmg && \ ls -la /tmp/verify_dmg && \ hdiutil detach /tmp/verify_dmg

You should see both APP.app and Applications (symlink).

Step 6: Submit for Notarization

Submit the DMG to Apple for notarization (you'll be prompted for credentials):

xcrun notarytool submit ~/Desktop/APP-VERSION.dmg \ --apple-id YOUR_APPLE_ID@gmail.com \ --team-id YOUR_TEAM_ID \ --password YOUR_APP_SPECIFIC_PASSWORD \ --wait

The --wait flag makes the command wait for processing to complete (typically 1-2 minutes).

Expected output:

Processing complete id: [submission-id] status: Accepted

If status is "Invalid", get detailed logs:

xcrun notarytool log SUBMISSION_ID \ --apple-id YOUR_APPLE_ID@gmail.com \ --team-id YOUR_TEAM_ID \ --password YOUR_APP_SPECIFIC_PASSWORD

For notarization troubleshooting, see NOTARIZATION.md.

Step 7: Staple Notarization Ticket

Staple the notarization ticket to the DMG:

xcrun stapler staple ~/Desktop/APP-VERSION.dmg

Expected output:

The staple and validate action worked!

Verify notarization:

spctl -a -vvv ~/Desktop/APP-VERSION-Export/APP.app

Should show:

accepted source=Notarized Developer ID

Step 8: Update appcast.xml

Update the Sparkle appcast file with the new version, signature, and file size from Step 4:

<title>Version X.X.X</title> <link>https://github.com/USER/REPO</link> X.X.X stable DAY, DD MMM YYYY HH:MM:SS -0700

Note: The gitleaks pre-commit hook may flag the Sparkle signature as a potential secret. This is a false positive - the EdDSA signature is public and safe to commit. Use git commit --no-verify if needed.

Step 9: Commit and Push Changes

Commit the version update and appcast changes:

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

Co-Authored-By: Claude noreply@anthropic.com"

git push

Step 10: Update GitHub Release

Create or update the GitHub release with new assets:

For new releases:

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

For updating existing releases:

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

Note on asset naming: The uploaded filename becomes the asset name. To upload with a specific name:

Copy to desired name first

cp ~/Desktop/APP-1.0.9.dmg /tmp/APP.dmg gh release upload vX.X.X /tmp/APP.dmg

Verify release assets:

gh release view vX.X.X --json assets -q '.assets[] | "(.name) - (.size) bytes"'

Step 11: Final Verification

Verify the release is working correctly:

Check version in app:

defaults read /Applications/APP.app/Contents/Info.plist CFBundleShortVersionString

Should show: X.X.X

Test DMG:

Download the DMG from GitHub release Open the DMG Verify Applications folder is present for drag-and-drop Drag app to Applications and launch Should open without any "malicious" or security warnings

Test Sparkle updates:

Users with previous versions should receive automatic update notifications The update should download and install smoothly Common Issues

If you encounter problems, see TROUBLESHOOTING.md for solutions to:

Version not updating after rebuild DMG missing Applications folder Notarization failures "Malicious app" warnings Sparkle signature issues CI/CD failures Quick Reference

Check version:

defaults read /path/to/APP.app/Contents/Info.plist CFBundleShortVersionString

Check code signing:

codesign -dvvv /path/to/APP.app

Check notarization:

spctl -a -vvv /path/to/APP.app

Get Sparkle sign_update path:

find ~/Library/Developer/Xcode/DerivedData -name sign_update -type f

返回排行榜