Skip to content
Latchkey

CI/CD for an iOS SwiftUI App with XCTest and GitHub Actions

Build with xcodebuild, run XCTest on a simulator, and archive your SwiftUI app on a macOS runner.

This recipe builds an iOS SwiftUI app on a macOS runner. CI selects an Xcode version, runs unit and UI XCTest suites on a simulator with xcodebuild, then archives the app for distribution.

What the pipeline does

  • run on a macos runner
  • select an Xcode version
  • build and test with xcodebuild on a simulator
  • archive the app
  • upload the archive artifact

The workflow

xcodebuild test runs the XCTest suites on a named simulator destination. The -resultBundlePath captures results; archiving produces an .xcarchive for export.

.github/workflows/ci.yml
name: CI
on:
  push:
    branches: [main]
  pull_request:
jobs:
  test:
    runs-on: macos-14
    steps:
      - uses: actions/checkout@v4
      - run: sudo xcode-select -s /Applications/Xcode_16.app
      - run: |
          xcodebuild test \
            -scheme App \
            -destination "platform=iOS Simulator,name=iPhone 15,OS=latest" \
            -resultBundlePath TestResults.xcresult
      - run: |
          xcodebuild archive \
            -scheme App \
            -archivePath build/App.xcarchive \
            -destination "generic/platform=iOS" \
            CODE_SIGNING_ALLOWED=NO
      - uses: actions/upload-artifact@v4
        with:
          name: app-archive
          path: build/App.xcarchive

Caching and speed

Cache SwiftPM dependencies (~/Library/Developer/Xcode/DerivedData and the SPM cache) with actions/cache. macOS runners are the most expensive minutes on GitHub; cheaper managed runners such as Latchkey (around 69% cheaper than GitHub-hosted) cut iOS build cost sharply and auto-retry a flaky simulator boot.

Deploying

For real distribution, import a signing certificate and provisioning profile into the keychain, then xcodebuild -exportArchive with an export options plist. Pair with fastlane to upload the resulting IPA to TestFlight.

Key takeaways

  • Pin the Xcode version with xcode-select for reproducible builds.
  • Run XCTest on a named simulator destination via xcodebuild test.
  • macOS minutes are pricey, so managed runners cut iOS CI cost the most.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →