Files
gh-glittercowboy-taches-cc-…/skills/expertise/iphone-apps/references/cli-workflow.md
2025-11-29 18:28:37 +08:00

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

  1. Connect device via USB once
  2. In Xcode: Window > Devices and Simulators > Connect via network
  3. 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

  1. App Store Connect > Users and Access > Keys
  2. Generate API Key
  3. 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/