Skip to content

Instantly share code, notes, and snippets.

@jyc
Last active November 9, 2023 06:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jyc/edec7dcd14546d12b3ab646575edf643 to your computer and use it in GitHub Desktop.
Save jyc/edec7dcd14546d12b3ab646575edf643 to your computer and use it in GitHub Desktop.
Bash script to build a (macOS) Xcode app and publish an update using Sparkle
#!/bin/bash
set -euo pipefail
# TO CREATE ExportOptions.plist:
# Product > Archive then Window > Organizer > Archives, Distribute App, Distribute Directly doesn’t seem to work!
# Use Archives > Distribute App, Custom, Developer ID, Export seems to work… DO NOT click Upload!
#
# BEFORE RUNNING:
# Create an app-specific password; call it "Foobar Build Scripts": https://support.apple.com/en-us/102654
# Then run:
# xcrun notarytool store-credentials notarytool-foobar-password \
# --apple-id <Apple ID> \
# --team-id Y6RAT2Q4MT \
# --password <app specific password>
rm -rf build/*
build_settings=$(xcodebuild -showBuildSettings 2>/dev/null)
marketing_version=$(grep MARKETING_VERSION <<< "$build_settings" | tr -d 'MARKETING_VERSION =')
current_project_version=$(grep CURRENT_PROJECT_VERSION <<< "$build_settings" | tr -d 'CURRENT_PROJECT_VERSION =')
# Archive
xcodebuild -project Foobar.xcodeproj -scheme Foobar -archivePath build/Foobar.xcarchive archive
# Export
xcodebuild -exportArchive -archivePath build/Foobar.xcarchive -exportPath build/export -exportOptionsPlist share/ExportOptions.plist
# Notarize
mkdir -p build/notarize
ditto -c -k --keepParent build/export/Foobar.app build/notarize/Foobar.zip
xcrun notarytool submit build/notarize/Foobar.zip --keychain-profile notarytool-foobar-password --wait
xcrun stapler staple build/export/Foobar.app
# Package
mkdir -p build/dmg
cp -R build/export/Foobar.app build/dmg/
ln -s /Applications build/dmg/Applications
hdiutil create -volname Foobar -srcfolder build/dmg -ov -format UDZO build/dist/Foobar.dmg
# NOTE: Apple documentation implies otherwise, but if you use ditto to create a
# ZIP of your app, it will not preserve the quarantine xattrs and you'll see a
# warning saying that your app is damaged and can't be opened! Weirdly that
# doesn't occur if you create a ZIP using Finder... This problem doesn't seem to
# occur with DMGs.
# Maybe --sequesterRsrc is necessary?
# Sparkle
dist_dmg_basename=$marketing_version-$current_project_version.dmg
dist_dmg=share/sparkle-updates/Foobar-$dist_dmg_basename
cp build/dist/Foobar.dmg $dist_dmg
bin/sparkle/generate_appcast --account foobar share/sparkle-updates
# foobar.app
cp $dist_dmg ../foobar.app/public/$dist_dmg_basename
cp $dist_dmg ../foobar.app/public/Foobar.dmg
cp share/sparkle-updates/appcast.xml ../foobar.app/public/appcast.xml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment