5.6 KiB
Gaze Distribution Guide
This guide explains how to build and distribute Gaze for both the Mac App Store and direct distribution with auto-updates.
Distribution Methods
Gaze supports two distribution methods:
- Self-Distribution (Direct Download) - Includes Sparkle for automatic updates
- Mac App Store - Uses Apple's update mechanism, no Sparkle
Quick Start
Switching Between Distributions
Use the switch_to script to configure the project for each distribution method:
# For self-distribution with Sparkle auto-updates
./switch_to self
# For Mac App Store submission
./switch_to appstore
# Check current configuration
./switch_to status
What Gets Changed
The switch_to script automatically manages:
Self-Distribution Mode:
- ✅ Adds Sparkle keys to
Info.plist(SUPublicEDKey, SUFeedURL, etc.) - ✅ Adds Sparkle entitlements for XPC services
- ✅ Removes
APPSTOREcompiler flag - ✅ Enables UpdateManager with Sparkle framework
App Store Mode:
- ✅ Removes all Sparkle keys from
Info.plist - ✅ Removes Sparkle entitlements
- ✅ Adds
-D APPSTOREcompiler flag - ✅ Disables Sparkle code at compile time
Building for Self-Distribution
# 1. Switch to self-distribution mode
./switch_to self
The script will:
- Prompt for version bump (major/minor/patch)
- Build and code sign with Developer ID
- Notarize the app with Apple
- Create a signed DMG
- Generate Sparkle appcast with EdDSA signature
- (Optional) Upload to S3 if credentials are configured
Building for Mac App Store
# 1. Switch to App Store mode
./switch_to appstore
# 2. Add Run Script Phase in Xcode (one-time setup)
# See section below
# 3. Archive and distribute via Xcode
# Product → Archive
# Window → Organizer → Distribute App → App Store Connect
Required: Run Script Phase
For App Store builds, you must add this Run Script phase in Xcode:
- Open Gaze.xcodeproj in Xcode
- Select the Gaze target → Build Phases
- Click + → New Run Script Phase
- Name it: "Remove Sparkle for App Store"
- Place it after "Embed Frameworks"
- Add this script:
#!/bin/bash
if [[ "${OTHER_SWIFT_FLAGS}" == *"APPSTORE"* ]]; then
echo "Removing Sparkle framework for App Store build..."
rm -rf "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sparkle.framework"
echo "Sparkle framework removed successfully"
fi
This ensures Sparkle.framework is removed from the app bundle before submission.
Configuration Files
Configuration backups are stored in .distribution_configs/:
.distribution_configs/appstore/- App Store configuration.distribution_configs/self/- Self-distribution configuration
These backups are created automatically and used when switching between modes.
Validation
Before submitting to App Store Connect, verify your configuration:
./switch_to status
Expected output for App Store:
Info.plist: App Store (no Sparkle keys)
Entitlements: App Store (no Sparkle exceptions)
Build Settings: App Store (has APPSTORE flag)
Expected output for Self-Distribution:
Info.plist: Self-Distribution (has Sparkle keys)
Entitlements: Self-Distribution (has Sparkle exceptions)
Build Settings: Self-Distribution (no APPSTORE flag)
Troubleshooting
App Store Validation Fails
Error: "App sandbox not enabled" with Sparkle executables
- Solution: Make sure you ran
./switch_to appstoreand added the Run Script phase
Error: "Bad Bundle Executable" or "CFBundlePackageType"
- Solution: These are now fixed in the Info.plist
Error: Still seeing Sparkle in the build
- Solution: Clean build folder (⌘⇧K) and rebuild
Self-Distribution Issues
Sparkle updates not working
- Verify:
./switch_to statusshows "Self-Distribution" mode - Check: Info.plist contains SUPublicEDKey and SUFeedURL
- Verify: Appcast is accessible at the SUFeedURL
Code signing issues
- Check
.envfile has correct credentials - Verify Developer ID certificate:
security find-identity -v -p codesigning
Environment Variables
For self-distribution, create a .env file with:
# Required for code signing
DEVELOPER_ID_APPLICATION="Developer ID Application: Your Name (TEAM_ID)"
APPLE_TEAM_ID="XXXXXXXXXX"
# Required for notarization
NOTARY_KEYCHAIN_PROFILE="notary-profile"
# Optional for S3 upload
AWS_ACCESS_KEY_ID="your-key"
AWS_SECRET_ACCESS_KEY="your-secret"
AWS_BUCKET_NAME="your-bucket"
AWS_REGION="us-east-1"
Setup notarization profile (one-time):
xcrun notarytool store-credentials "notary-profile" \
--apple-id "your@email.com" \
--team-id "TEAM_ID"
Version Management
The self_distribute script handles version bumping:
- Major (X.0.0) - Breaking changes
- Minor (x.X.0) - New features
- Patch (x.x.X) - Bug fixes
- Custom - Any version string
- Keep - Increment build number only
Git tags are created automatically for new versions.
Testing
Test Self-Distribution Build
./switch_to self
# Test the DMG on a clean macOS system
Test App Store Build
./switch_to appstore
# Archive in Xcode
# Use TestFlight for testing before release
Best Practices
- Always use
switch_to- Don't manually edit configuration files - Check status before building - Use
./switch_to status - Clean builds - Run Clean Build Folder when switching modes
- Test thoroughly - Test both distribution methods separately
- Commit before switching - Use git to track configuration changes
Support
For issues or questions:
- GitHub Issues: https://github.com/mikefreno/Gaze/issues
- Check AGENTS.md for development guidelines