Loading...
Loading...
Create notarized macOS app releases with Sparkle auto-updates, DMG installers, and GitHub releases. Use when releasing macOS apps, creating DMG files, notarizing apps, or setting up Sparkle updates. Handles version updates, code signing, notarization, and distribution.
npx skill4agent add jamesrochabrun/skills releasing-macos-appsRelease 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 numbergh.xcconfigsecurity find-identity -v -p codesigning | grep "Developer ID Application"ProjectName.xcconfigproject.pbxproj# Edit the APP_VERSION line
# Example: APP_VERSION = 1.0.9xcodebuild -project PROJECT.xcodeproj -showBuildSettings | grep MARKETING_VERSIONxcodebuild -project PROJECT.xcodeproj \
-scheme SCHEME_NAME \
-configuration Release \
-archivePath ~/Desktop/APP-VERSION.xcarchive \
archivels -la ~/Desktop/APP-VERSION.xcarchivecat > /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>
EOFYOUR_TEAM_IDxcodebuild -exportArchive \
-archivePath ~/Desktop/APP-VERSION.xcarchive \
-exportPath ~/Desktop/APP-VERSION-Export \
-exportOptionsPlist /tmp/ExportOptions.plistdefaults read ~/Desktop/APP-VERSION-Export/APP.app/Contents/Info.plist CFBundleShortVersionStringcodesign -dvvv ~/Desktop/APP-VERSION-Export/APP.appcd ~/Desktop/APP-VERSION-Export
ditto -c -k --keepParent APP.app APP.app.zipecho "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"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}"hdiutil attach ~/Desktop/APP-VERSION.dmg -readonly -nobrowse -mountpoint /tmp/verify_dmg && \
ls -la /tmp/verify_dmg && \
hdiutil detach /tmp/verify_dmgAPP.appApplicationsxcrun notarytool submit ~/Desktop/APP-VERSION.dmg \
--apple-id YOUR_APPLE_ID@gmail.com \
--team-id YOUR_TEAM_ID \
--password YOUR_APP_SPECIFIC_PASSWORD \
--wait--waitProcessing complete
id: [submission-id]
status: Acceptedxcrun notarytool log SUBMISSION_ID \
--apple-id YOUR_APPLE_ID@gmail.com \
--team-id YOUR_TEAM_ID \
--password YOUR_APP_SPECIFIC_PASSWORDxcrun stapler staple ~/Desktop/APP-VERSION.dmgThe staple and validate action worked!spctl -a -vvv ~/Desktop/APP-VERSION-Export/APP.appaccepted
source=Notarized Developer ID<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>git commit --no-verifygit 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 <noreply@anthropic.com>"
git pushgh 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.dmggh release view vX.X.X --json assets -q '.assets[] | "\(.name) - \(.size) bytes"'defaults read /Applications/APP.app/Contents/Info.plist CFBundleShortVersionStringX.X.Xdefaults read /path/to/APP.app/Contents/Info.plist CFBundleShortVersionStringcodesign -dvvv /path/to/APP.appspctl -a -vvv /path/to/APP.appfind ~/Library/Developer/Xcode/DerivedData -name sign_update -type f