7.9 KiB
7.9 KiB
CLI Workflow
Build, run, test, and deploy iOS apps entirely from the terminal.
Prerequisites
# Ensure Xcode is installed and selected
xcode-select -p
# Should show: /Applications/Xcode.app/Contents/Developer
# If not, run:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
# Install XcodeGen for project creation
brew install xcodegen
# Optional: prettier build output
brew install xcbeautify
# Optional: device deployment
brew install ios-deploy
Create Project (XcodeGen)
Create a new iOS project entirely from CLI:
# Create directory structure
mkdir MyApp && cd MyApp
mkdir -p MyApp/{App,Models,Views,Services,Resources} MyAppTests MyAppUITests
# Create project.yml (Claude generates this - see project-scaffolding.md for full template)
cat > project.yml << 'EOF'
name: MyApp
options:
bundleIdPrefix: com.yourcompany
deploymentTarget:
iOS: "18.0"
targets:
MyApp:
type: application
platform: iOS
sources: [MyApp]
settings:
PRODUCT_BUNDLE_IDENTIFIER: com.yourcompany.myapp
DEVELOPMENT_TEAM: YOURTEAMID
EOF
# Create app entry point
cat > MyApp/App/MyApp.swift << 'EOF'
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
Text("Hello, World!")
}
}
}
EOF
# Generate .xcodeproj
xcodegen generate
# Verify
xcodebuild -list -project MyApp.xcodeproj
# Build
xcodebuild -project MyApp.xcodeproj -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 16' build
See project-scaffolding.md for complete project.yml templates.
Building
Basic Build
# Build for simulator
xcodebuild -project MyApp.xcodeproj \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16' \
build
# Build for device
xcodebuild -project MyApp.xcodeproj \
-scheme MyApp \
-destination 'generic/platform=iOS' \
build
Clean Build
xcodebuild -project MyApp.xcodeproj \
-scheme MyApp \
clean build
Build with Specific SDK
# List available SDKs
xcodebuild -showsdks
# Build with specific SDK
xcodebuild -project MyApp.xcodeproj \
-scheme MyApp \
-sdk iphonesimulator17.0 \
build
Running on Simulator
Boot and Launch
# List available simulators
xcrun simctl list devices
# Boot simulator
xcrun simctl boot "iPhone 16"
# Open Simulator app
open -a Simulator
# Install app
xcrun simctl install booted ~/Library/Developer/Xcode/DerivedData/MyApp-xxx/Build/Products/Debug-iphonesimulator/MyApp.app
# Launch app
xcrun simctl launch booted com.yourcompany.MyApp
# Or install and launch in one step
xcrun simctl install booted MyApp.app && xcrun simctl launch booted com.yourcompany.MyApp
Simulator Management
# Create simulator
xcrun simctl create "My iPhone 16" "iPhone 16" iOS17.0
# Delete simulator
xcrun simctl delete "My iPhone 16"
# Reset simulator
xcrun simctl erase booted
# Screenshot
xcrun simctl io booted screenshot ~/Desktop/screenshot.png
# Record video
xcrun simctl io booted recordVideo ~/Desktop/recording.mov
Simulate Conditions
# Set location
xcrun simctl location booted set 37.7749,-122.4194
# Send push notification
xcrun simctl push booted com.yourcompany.MyApp notification.apns
# Set status bar (time, battery, etc.)
xcrun simctl status_bar booted override --time "9:41" --batteryLevel 100
Running on Device
List Connected Devices
# List devices
xcrun xctrace list devices
# Or using ios-deploy
ios-deploy --detect
Deploy to Device
# Install ios-deploy
brew install ios-deploy
# Deploy and run
ios-deploy --bundle MyApp.app --debug
# Just install without launching
ios-deploy --bundle MyApp.app --no-wifi
# Deploy with app data
ios-deploy --bundle MyApp.app --bundle_id com.yourcompany.MyApp
Wireless Debugging
- Connect device via USB once
- In Xcode: Window > Devices and Simulators > Connect via network
- Deploy wirelessly:
ios-deploy --bundle MyApp.app --wifi
Testing
Run Unit Tests
xcodebuild test \
-project MyApp.xcodeproj \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-resultBundlePath TestResults.xcresult
Run UI Tests
xcodebuild test \
-project MyApp.xcodeproj \
-scheme MyAppUITests \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-resultBundlePath UITestResults.xcresult
Run Specific Tests
# Single test
xcodebuild test \
-project MyApp.xcodeproj \
-scheme MyApp \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:MyAppTests/NetworkServiceTests/testFetchItems
# Test class
xcodebuild test \
... \
-only-testing:MyAppTests/NetworkServiceTests
View Test Results
# Open results in Xcode
open TestResults.xcresult
# Export to JSON (for CI)
xcrun xcresulttool get --path TestResults.xcresult --format json
Debugging
Console Logs
# Stream logs from simulator
xcrun simctl spawn booted log stream --predicate 'subsystem == "com.yourcompany.MyApp"'
# Stream logs from device
idevicesyslog | grep MyApp
LLDB
# Attach to running process
lldb -n MyApp
# Debug app on launch
ios-deploy --bundle MyApp.app --debug
Crash Logs
# Simulator crash logs
ls ~/Library/Logs/DiagnosticReports/
# Device crash logs (via Xcode)
# Window > Devices and Simulators > View Device Logs
Archiving and Export
Create Archive
xcodebuild archive \
-project MyApp.xcodeproj \
-scheme MyApp \
-archivePath build/MyApp.xcarchive \
-destination 'generic/platform=iOS'
Export IPA
Create ExportOptions.plist:
<?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>method</key>
<string>app-store</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>uploadSymbols</key>
<true/>
<key>uploadBitcode</key>
<false/>
</dict>
</plist>
Export:
xcodebuild -exportArchive \
-archivePath build/MyApp.xcarchive \
-exportOptionsPlist ExportOptions.plist \
-exportPath build/
App Store Connect
Upload to TestFlight
xcrun altool --upload-app \
--type ios \
--file build/MyApp.ipa \
--apiKey YOUR_KEY_ID \
--apiIssuer YOUR_ISSUER_ID
Or use xcrun notarytool for newer workflows:
xcrun notarytool submit build/MyApp.ipa \
--key ~/.appstoreconnect/AuthKey_XXXXX.p8 \
--key-id YOUR_KEY_ID \
--issuer YOUR_ISSUER_ID \
--wait
App Store Connect API Key
- App Store Connect > Users and Access > Keys
- Generate API Key
- Download and store securely
Useful Aliases
Add to .zshrc:
# iOS development
alias ios-build="xcodebuild -project *.xcodeproj -scheme \$(basename *.xcodeproj .xcodeproj) -destination 'platform=iOS Simulator,name=iPhone 16' build"
alias ios-test="xcodebuild test -project *.xcodeproj -scheme \$(basename *.xcodeproj .xcodeproj) -destination 'platform=iOS Simulator,name=iPhone 16'"
alias ios-run="xcrun simctl launch booted"
alias ios-log="xcrun simctl spawn booted log stream --level debug"
alias sim-boot="xcrun simctl boot 'iPhone 16' && open -a Simulator"
alias sim-screenshot="xcrun simctl io booted screenshot ~/Desktop/sim-\$(date +%Y%m%d-%H%M%S).png"
Troubleshooting
Build Failures
# Clear derived data
rm -rf ~/Library/Developer/Xcode/DerivedData
# Reset package caches
rm -rf ~/Library/Caches/org.swift.swiftpm
# Resolve packages
xcodebuild -resolvePackageDependencies
Simulator Issues
# Kill all simulators
killall Simulator
# Reset all simulators
xcrun simctl shutdown all && xcrun simctl erase all
Code Signing
# List identities
security find-identity -v -p codesigning
# Check provisioning profiles
ls ~/Library/MobileDevice/Provisioning\ Profiles/