Loading...
Loading...
Compare original and translation side by side
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 numberRelease 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"gh.xcconfigsecurity find-identity -v -p codesigning | grep "Developer ID Application"ProjectName.xcconfigproject.pbxprojundefinedProjectName.xcconfigproject.pbxprojundefined
**Verify the update:**
```bash
xcodebuild -project PROJECT.xcodeproj -showBuildSettings | grep MARKETING_VERSION
**验证版本更新:**
```bash
xcodebuild -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.xcarchivexcodebuild -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.appcat > /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"cd ~/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.appApplicationsTEMP_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 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 IDxcrun 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-verify<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 pushgit 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.zipundefinedgh 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.zipundefined
**Note on asset naming:**
The uploaded filename becomes the asset name. To upload with a specific name:
```bash
**资产命名注意事项:**
上传的文件名会成为资产名称。如需使用特定名称上传:
```bash
**Verify release assets:**
```bash
gh release view vX.X.X --json assets -q '.assets[] | "\(.name) - \(.size) bytes"'
**验证发布资产:**
```bash
gh release view vX.X.X --json assets -q '.assets[] | "\(.name) - \(.size) bytes"'defaults read /Applications/APP.app/Contents/Info.plist CFBundleShortVersionStringX.X.Xdefaults 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 fdefaults 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