Uses xcodebuild:
https://developer.apple.com/documentation/xcode
- Artifacts
- Dependencies - CocoaPods
- Metadata
- Build Destinations and Simulators
- Download Simulators
- Copy Profiles to Library
- Load Certificate into Keychain
- Open KeyChain Access
- Build
- IPA Archives
- xcpretty
- xcbeautify
- AGV
- iXGuard
- Switching XCode versions
- Download Alternate XCode Versions
- Apple 2FA
- Troubleshooting
- Memes
MyApp.ipa
Packaged file format used for installing iOS applications on iPhones, iPads etc.
CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects.
It's written in Ruby and can be installed using the system ruby.
Install cocoapods:
sudo gem install cocoapodsInstall project's pod dependencies:
pod installThis uses a Podfile build file that looks like this:
platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
pod 'AFNetworking', '~> 2.6'
pod 'ORStackView', '~> 3.0'
pod 'SwiftyJSON', '~> 2.3'
endCreating a Pod:
pod spec create "$APP"Edit the podspec file:
"$EDITOR" "$APP".podspecLint the podspec file:
pod spec lint "$APP".podspecReinstall dependencies:
pod deintegrate &&
pod installMetadata is found in:
<AppName>.xcodeproj/
and
<AppName>.xcworkspace
You can open XCode like this:
open "$APP".xcodeprojopen "$APP".xcworkspacexcodebuild cleanxcodebuild -workspace "$APP".xcworkspace \
-scheme SIT \
-configuration SIT \
cleanInstall the Platform SDK first, otherwise you'll get an error like this:
Command line invocation:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -workspace MyApp.xcworkspace -scheme SIT -configuration SIT clean
User defaults from command line:
IDEPackageSupportUseBuiltinSCM = YES
2025-01-30 14:18:57.750 xcodebuild[47478:154973817] Writing error result bundle to /var/folders/30/kxjrq3fj5tqdhsvbj3p9m2fh0000gq/T/ResultBundle_2025-30-01_14-18-0057.xcresult
xcodebuild: error: Found no destinations for the scheme 'SIT' and action clean.
Running this:
xcodebuild -workspace "$APP".xcworkspace \
-scheme SIT \
-configuration SIT \
cleanOutput should look something like this:
Command line invocation:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -workspace MyApp.xcworkspace -scheme SIT -configuration SIT clean
User defaults from command line:
IDEPackageSupportUseBuiltinSCM = YES
--- xcodebuild: WARNING: Using the first of multiple matching destinations:
{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device }
{ platform:iOS Simulator, id:dvtdevice-DVTiOSDeviceSimulatorPlaceholder-iphonesimulator:placeholder, name:Any iOS Simulator Device }
{ platform:iOS Simulator, id:FAF9573D-6EFF-4F38-A5D6-E0613D8AD15F, OS:17.5, name:iPad (10th generation) }
{ platform:iOS Simulator, id:FAF9573D-6EFF-4F38-A5D6-E0613D8AD15F, OS:17.5, name:iPad (10th generation) }
{ platform:iOS Simulator, id:D9DEB37D-DB2A-4C70-B12F-758FB2DDEF28, OS:17.5, name:iPad Air 11-inch (M2) }
{ platform:iOS Simulator, id:D9DEB37D-DB2A-4C70-B12F-758FB2DDEF28, OS:17.5, name:iPad Air 11-inch (M2) }
{ platform:iOS Simulator, id:3B3701D6-8908-4C5B-AE9D-28065AAB3361, OS:17.5, name:iPad Air 13-inch (M2) }
{ platform:iOS Simulator, id:3B3701D6-8908-4C5B-AE9D-28065AAB3361, OS:17.5, name:iPad Air 13-inch (M2) }
{ platform:iOS Simulator, id:4AA9C940-8B08-497A-8873-91913B1D8A26, OS:17.5, name:iPad Pro 11-inch (M4) }
{ platform:iOS Simulator, id:4AA9C940-8B08-497A-8873-91913B1D8A26, OS:17.5, name:iPad Pro 11-inch (M4) }
{ platform:iOS Simulator, id:59DA5271-F055-44DA-9266-C545D4308195, OS:17.5, name:iPad Pro 13-inch (M4) }
{ platform:iOS Simulator, id:59DA5271-F055-44DA-9266-C545D4308195, OS:17.5, name:iPad Pro 13-inch (M4) }
{ platform:iOS Simulator, id:5507F622-1A42-4914-AF9A-AA644851A559, OS:17.5, name:iPad mini (6th generation) }
{ platform:iOS Simulator, id:5507F622-1A42-4914-AF9A-AA644851A559, OS:17.5, name:iPad mini (6th generation) }
{ platform:iOS Simulator, id:8359DDF7-572A-4AEA-99B4-689EF151872A, OS:17.5, name:iPhone 15 }
{ platform:iOS Simulator, id:8359DDF7-572A-4AEA-99B4-689EF151872A, OS:17.5, name:iPhone 15 }
{ platform:iOS Simulator, id:10BEF2E3-FEBD-49AD-8A6F-E4F4C559EBF4, OS:17.5, name:iPhone 15 Plus }
{ platform:iOS Simulator, id:10BEF2E3-FEBD-49AD-8A6F-E4F4C559EBF4, OS:17.5, name:iPhone 15 Plus }
{ platform:iOS Simulator, id:2E91DE33-0CAD-4189-BE35-C00ABBA69E19, OS:17.5, name:iPhone 15 Pro }
{ platform:iOS Simulator, id:2E91DE33-0CAD-4189-BE35-C00ABBA69E19, OS:17.5, name:iPhone 15 Pro }
{ platform:iOS Simulator, id:41104926-C610-474A-9846-5C840E36CE82, OS:17.5, name:iPhone 15 Pro Max }
{ platform:iOS Simulator, id:41104926-C610-474A-9846-5C840E36CE82, OS:17.5, name:iPhone 15 Pro Max }
{ platform:iOS Simulator, id:C4EE5DBE-6048-4BCC-BDEA-8EE7E8C400C6, OS:17.5, name:iPhone SE (3rd generation) }
{ platform:iOS Simulator, id:C4EE5DBE-6048-4BCC-BDEA-8EE7E8C400C6, OS:17.5, name:iPhone SE (3rd generation) }
** CLEAN SUCCEEDED **
xcodebuild \
-workspace "$APP".xcworkspace \
-scheme SIT \
-configuration SIT \
-showdestinationsIf you see this output, you have no available destinations:
Command line invocation:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -workspace MyApp.xcworkspace -scheme SIT -configuration SIT -showdestinations
User defaults from command line:
IDEPackageSupportUseBuiltinSCM = YES
Ineligible destinations for the "SIT" scheme:
{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.5 is not installed. To use with Xcode, first download and install the platform }
xcodebuild -workspace MyApp.xcworkspace -scheme SIT -configuration SIT -showdestinations
Command line invocation:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -workspace MyApp.xcworkspace -scheme SIT -configuration SIT -showdestinations
User defaults from command line:
IDEPackageSupportUseBuiltinSCM = YES
Available destinations for the "SIT" scheme:
{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device }
{ platform:iOS Simulator, id:dvtdevice-DVTiOSDeviceSimulatorPlaceholder-iphonesimulator:placeholder, name:Any iOS Simulator Device }
{ platform:iOS Simulator, id:FAF9573D-6EFF-4F38-A5D6-E0613D8AD15F, OS:17.5, name:iPad (10th generation) }
{ platform:iOS Simulator, id:D9DEB37D-DB2A-4C70-B12F-758FB2DDEF28, OS:17.5, name:iPad Air 11-inch (M2) }
{ platform:iOS Simulator, id:3B3701D6-8908-4C5B-AE9D-28065AAB3361, OS:17.5, name:iPad Air 13-inch (M2) }
{ platform:iOS Simulator, id:4AA9C940-8B08-497A-8873-91913B1D8A26, OS:17.5, name:iPad Pro 11-inch (M4) }
{ platform:iOS Simulator, id:59DA5271-F055-44DA-9266-C545D4308195, OS:17.5, name:iPad Pro 13-inch (M4) }
{ platform:iOS Simulator, id:5507F622-1A42-4914-AF9A-AA644851A559, OS:17.5, name:iPad mini (6th generation) }
{ platform:iOS Simulator, id:8359DDF7-572A-4AEA-99B4-689EF151872A, OS:17.5, name:iPhone 15 }
{ platform:iOS Simulator, id:10BEF2E3-FEBD-49AD-8A6F-E4F4C559EBF4, OS:17.5, name:iPhone 15 Plus }
{ platform:iOS Simulator, id:2E91DE33-0CAD-4189-BE35-C00ABBA69E19, OS:17.5, name:iPhone 15 Pro }
{ platform:iOS Simulator, id:41104926-C610-474A-9846-5C840E36CE82, OS:17.5, name:iPhone 15 Pro Max }
{ platform:iOS Simulator, id:C4EE5DBE-6048-4BCC-BDEA-8EE7E8C400C6, OS:17.5, name:iPhone SE (3rd generation) }See available simulators:
xcrun simctl listSee available runtimes:
xcrun simctl list runtimes== Runtimes ==
iOS 17.5 (17.5 - 21F79) - com.apple.CoreSimulator.SimRuntime.iOS-17-5
tvOS 17.5 (17.5 - 21L569) - com.apple.CoreSimulator.SimRuntime.tvOS-17-5
watchOS 10.5 (10.5 - 21T575) - com.apple.CoreSimulator.SimRuntime.watchOS-10-5
visionOS 1.2 (1.2 - 21O5565d) - com.apple.CoreSimulator.SimRuntime.xrOS-1-2
Boot one if necessary:
xcrun simctl boot "iPhone 14"xcrun simctl erase allDelete derived data:
rm -rf ~/Library/Developer/Xcode/DerivedDataor
xcodebuild -workspace "$APP".xcworkspace \
-scheme SIT \
-configuration SIT \
-destination 'platform=iOS,name=iPhone 14,OS=16.4' \
cleanOutput should look like:
xcodebuild -workspace MyApp.xcworkspace -scheme SIT -configuration SIT -showdestinations
Command line invocation:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -workspace MyApp.xcworkspace -scheme SIT -configuration SIT -showdestinations
User defaults from command line:
IDEPackageSupportUseBuiltinSCM = YES
Available destinations for the "SIT" scheme:
{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device }
{ platform:iOS Simulator, id:dvtdevice-DVTiOSDeviceSimulatorPlaceholder-iphonesimulator:placeholder, name:Any iOS Simulator Device }
{ platform:iOS Simulator, id:FAF9573D-6EFF-4F38-A5D6-E0613D8AD15F, OS:17.5, name:iPad (10th generation) }
{ platform:iOS Simulator, id:D9DEB37D-DB2A-4C70-B12F-758FB2DDEF28, OS:17.5, name:iPad Air 11-inch (M2) }
{ platform:iOS Simulator, id:3B3701D6-8908-4C5B-AE9D-28065AAB3361, OS:17.5, name:iPad Air 13-inch (M2) }
{ platform:iOS Simulator, id:4AA9C940-8B08-497A-8873-91913B1D8A26, OS:17.5, name:iPad Pro 11-inch (M4) }
{ platform:iOS Simulator, id:59DA5271-F055-44DA-9266-C545D4308195, OS:17.5, name:iPad Pro 13-inch (M4) }
{ platform:iOS Simulator, id:5507F622-1A42-4914-AF9A-AA644851A559, OS:17.5, name:iPad mini (6th generation) }
{ platform:iOS Simulator, id:8359DDF7-572A-4AEA-99B4-689EF151872A, OS:17.5, name:iPhone 15 }
{ platform:iOS Simulator, id:10BEF2E3-FEBD-49AD-8A6F-E4F4C559EBF4, OS:17.5, name:iPhone 15 Plus }
{ platform:iOS Simulator, id:2E91DE33-0CAD-4189-BE35-C00ABBA69E19, OS:17.5, name:iPhone 15 Pro }
{ platform:iOS Simulator, id:41104926-C610-474A-9846-5C840E36CE82, OS:17.5, name:iPhone 15 Pro Max }
{ platform:iOS Simulator, id:C4EE5DBE-6048-4BCC-BDEA-8EE7E8C400C6, OS:17.5, name:iPhone SE (3rd generation) }
xcodebuild -showsdksRequires newer versions of Xcode and also admin privileges - for CI/CD prefix these download commands with sudo.
If in doubt, just download everything:
xcodebuild -downloadAllPlatformsThe output is the same as below individual platform download commands.
xcodebuild -downloadPlatform iOSDownloading iOS 17.5 Simulator (21F79): 7.5% (551.5 MB of 7.34 GB)
Verify after download:
xcrun simctl list runtimesShould return something like this (instead of being blank like before):
== Runtimes ==
iOS 17.5 (17.5 - 21F79) - com.apple.CoreSimulator.SimRuntime.iOS-17-5
If it's still empty, try to clear state and re-run the download command again:
sudo rm -rf /Library/Developer/Xcode
sudo rm -rf ~/Library/Developer/Xcode
sudo rm -rf ~/Library/Caches/com.apple.dt.Xcodexcodebuild -downloadPlatform watchOSDownloading watchOS 10.5 Simulator (21T575): 10.9% (428.7 MB of 3.95 GB)
xcrun simctl list runtimes== Runtimes ==
iOS 17.5 (17.5 - 21F79) - com.apple.CoreSimulator.SimRuntime.iOS-17-5
watchOS 10.5 (10.5 - 21T575) - com.apple.CoreSimulator.SimRuntime.watchOS-10-5
xcodebuild -downloadPlatform tvOSxcrun simctl list runtimes== Runtimes ==
iOS 17.5 (17.5 - 21F79) - com.apple.CoreSimulator.SimRuntime.iOS-17-5
tvOS 17.5 (17.5 - 21L569) - com.apple.CoreSimulator.SimRuntime.tvOS-17-5
watchOS 10.5 (10.5 - 21T575) - com.apple.CoreSimulator.SimRuntime.watchOS-10-5
xcodebuild -downloadPlatform visionOSxcrun simctl list runtimes== Runtimes ==
iOS 17.5 (17.5 - 21F79) - com.apple.CoreSimulator.SimRuntime.iOS-17-5
tvOS 17.5 (17.5 - 21L569) - com.apple.CoreSimulator.SimRuntime.tvOS-17-5
watchOS 10.5 (10.5 - 21T575) - com.apple.CoreSimulator.SimRuntime.watchOS-10-5
visionOS 1.2 (1.2 - 21O5565d) - com.apple.CoreSimulator.SimRuntime.xrOS-1-2```
open -a XcodeNavigate to Xcode > Settings > Platforms (or Preferences > Components). Look for iOS 17.5 Simulator and install it.
This 3rd party is another alternative way to install XCode SDKs from the command line, but it requires Apple Developer credentials.
sudo gem install xcode-installPrompts for an Apple Developer account username and password (set the $FASTLANE_PASSWORD environment variable).
This costs $79 per year at time of writing.
export XCODE_INSTALL_USER=...export XCODE_INSTALL_PASSWORD=...xcversion updatexcversion listxcversion install 'Xcode 15.0' # Adjust version if neededxcversion simulatorsxcversion install-simulator "iOS 17.5"xcrun simctl create "iPhone 14 (iOS 17.5)" com.apple.CoreSimulator.SimDeviceType.iPhone-14 com.apple.CoreSimulator.SimRuntime.iOS-17-5xcrun simctl boot "iPhone 14 (iOS 17.5)"Verify installation:
xcrun simctl listmkdir -p -v ~/Library/MobileDevice/Provisioning\ Profiles
cp -vi *.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/security list-keychainsBuild will find it there later.
CERT=Certificates-SIT.p12
Import certificate and allow codesign and security to read it:
security import "$CERT" \
-k ~/Library/Keychains/login.keychain-db \
-P "$CERT_PASSWORD" \
-T /usr/bin/codesign \
-T /usr/bin/securityOn your Mac laptop you may need to open keychain access if it's password protected.
In testing this didn't accept my login password, but if I opened it manually first:
open -a "Keychain Access"then the build proceeded using the already opened keychain.
The Fastlane handling of this is better where is creates a new keychain that isn't password protected.
Make sure you've got XCode set to Developer tools and not just CLI tools or you'll get this error.
sudo xcode-select -switch /Applications/Xcode.app/Contents/DeveloperBuild:
xcodebuild -workspace "$APP".xcworkspace \
-scheme SIT \
-configuration SITIf you get this error:
xcodebuild: error: Failed to build workspace MyApp with scheme SIT.: This scheme builds an embedded Apple Watch app. watchOS 10.5 must be installed in order to run the scheme
xcodebuild -downloadPlatform watchOSPrint the build settings:
xcodebuild -showBuildSettings # optionally put your -workspace -scheme -configuration switches ...and destinations:
xcodebuild -workspace "$APP".xcworkspace \
-scheme SIT \
-configuration SIT \
-showdestinationsBuild against a specific destination:
xcodebuild clean build -project "$APP".xcodeproj \
-scheme SIT \
-destination 'platform=iOS Simulator,name=iPhone 15'Run tests:
xcodebuild test -project "$APP".xcodeproj \
-scheme YourScheme \
-destination 'platform=iOS Simulator,name=iPhone 15'xcodebuild / Fastlane builds an IPA file:
IPA="./build/$APP.ipa"This ends up in different paths for different builds, find it like this:
IPA="$(find . -type f -name '*.ipa' | head -n1)"file "$IPA"./build/MyApp.ipa: iOS App Zip archive data, at least v1.0 to extract, compression method=store
unzip -l "$IPA"Archive: ./build/MyApp.ipa
Length Date Time Name
--------- ---------- ----- ----
0 02-11-2025 21:52 Payload/
0 02-11-2025 21:52 Payload/MyApp.app/
6201 02-11-2025 21:52 Payload/MyApp.app/blah.nib
8860 02-11-2025 21:52 Payload/MyApp.app/blah2.nib
12517 02-11-2025 21:52 Payload/MyApp.app/img.jpg
...
...
<rest of files omitted for brevity>Pipe xcodebuild output into it to make it prettier for human readability.
Used by Fastlane.
Faster alternative to xcpretty written in Swift, recommended and used preferentially by Fastlane.
Apple Generic Versioning (AGV) tool for Xcode projects:
agvtool vers # -terseSee iXGuard page.
See GitHub Actions - Mac Runner Versions vs XCode Versions.
brew install xcodesorg/made/xcodesList all possible XCode versions available:
xcodes listList XCode versions installed:
xcodes installed15.4 (15F31d) (Selected) /Applications/Xcode.app
Download and switch to 16.1:
xcodes install 16.1Just download the .xip package (eg. to upload to CI/CD artifacts):
xcodes download 16.1This requires a iCloud account.
export XCODES_USERNAME=...
export XCODES_PASSWORD=...And be prepared for the 2FA prompt if enabled on the account.
Unfortunately Apple doesn't support authenticator apps which can be used to share QR seeds.
Why doesn't Apple support Authenticator Apps for iCloud 2FA?
Apple’s 2FA is device-based, not time-based one-time passwords (TOTP) using number seeds usually shared as a QR code to authenticator apps.
Apple’s 2FA uses trusted Apple devices to receive push notifications or generate verification codes. Apple’s 2FA uses secure push notifications.
When signing in, Apple sends a real-time notification to trusted devices. These notifications display location-based alerts, helping prevent unauthorized access.
Apple controls the authentication flow entirely within its ecosystem to reduce phishing risks. Since TOTP codes can be stolen via phishing, Apple prefers to use its push-based system.
If you don’t have a trusted Apple device, Apple provides an alternative via SMS or phone call, rather than using third-party apps.
If you have Mac you can generate a 2FA code via the CLI:
security find-generic-password -s "iCloud" -wSince this is such a big problem, switched to using a GitHub-Actions runner with the XCode versions already installed.
See GitHub Actions - Mac Runner Versions vs XCode versions.
security import "$cert" \
-k ~/Library/Keychains/login.keychain-db \
-T /usr/bin/codesign \
-T /usr/bin/security \
${CERTIFICATE_PASSWORD:+-P "$CERTIFICATE_PASSWORD"}security: SecKeychainItemImport: Unknown format in import.
Verified the Certificate contains private key using SSL troubleshooting section.
Solution: Ensure $cert is a filename ending in .p12.
You're importing the certificate into one keychain but setting permissions on a different keychain.
Resolved this by adding setup_ci to Fastlane config and then loading the cert to the expected keychain of
fastlane_tmp_keychain-db.
The naming format is "$name"-db.
cert="certificate.p12"
keychain="build.keychain"
KEYCHAIN_PATH="$HOME/Library/Keychains/$keychain-db"
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV"
base64 --decode <<< "$CERTIFICATE" > "$cert"
file "$cert"
md5 "$cert"
security create-keychain -p "" "$keychain"
security default-keychain -s "$keychain"
security unlock-keychain -p "" "$keychain"
security import "$cert" \
-k "$KEYCHAIN_PATH" \
-T /usr/bin/codesign \
${CERTIFICATE_PASSWORD:+-P "$CERTIFICATE_PASSWORD"}
security set-key-partition-list -S apple-tool:,apple: -k "" "$keychain"If after:
xcodebuild -downloadPlatform iOSYou have empty runtimes:
xcrun simctl list runtimes
== Runtimes ==sudo rm -rf /Library/Developer/Xcode
sudo rm -rf ~/Library/Developer/Xcode
sudo rm -rf ~/Library/Caches/com.apple.dt.Xcodexcodebuild -downloadPlatform iOSAfter
Archive Succeeded
Successfully stored the archive. You can find it in the Xcode Organizer.
you then get an error like this:
error: exportArchive: Rsync failed
Error Domain=IDEFoundationErrorDomain Code=1 "Rsync failed"
This is caused by rsync failing during creation of the .ipa archive.
xcodebuild wraps the .xcarchive into a .ipa export based on your ExportOptions.plist using rsync.
Rsync may error out on broken symlinks in the build directory.
Clean out the state:
rm -rf build/ ~/Library/Developer/Xcode/DerivedData/*and then try again.
If it's still breaking this could be caused by use of a toolchain like iXGuard which creates the bitcode but not an export ready archive.
In this case skip the export in Fastlane and do it manually after:
ixguard --config ixguard.yaml -o build/"$NAME"-Guarded.xcarchive build/"$NAME".xcarchiveand then run the export archive:
xcodebuild -exportArchive \
-archivePath "build/"$NAME"-Guarded.xcarchive" \
-exportOptionsPlist "./ExportOptions/Production-ExportOptions.plist" \
-exportPath "."See the equivalent code in fastlane/Fastfile.
