How to Build and Archive an iOS Project via the Command Line

How to Build and Archive an iOS Project via the Command Line

Written by

in

Quick answer: To build and archive from the terminal, run xcodebuild -workspace YourApp.xcworkspace -scheme YourScheme -configuration Release -archivePath build/YourApp.xcarchive archive. To generate an .ipa file from that archive, run xcodebuild -exportArchive with an ExportOptions.plist defining your distribution method and signing team.

Why this happens

Automating iOS builds in continuous integration (CI) environments requires building and archiving directly from the terminal. Developers coming from the Xcode graphical interface often expect xcodebuild or standard make workflows to produce an .ipa or .xcarchive bundle automatically when running a build command.

However, running xcodebuild build only compiles binaries into the derived data build directory. It does not assemble the structured bundle hierarchy, dSYM symbols, and embedded provisioning profiles required for an Xcode Archive. Early versions of Xcode relied on a Perl script named PackageApplication to package binaries into an .ipa, but Apple deprecated and removed that utility years ago.

Modern automated packaging requires a two-stage process using the native archive action and -exportArchive option built directly into xcodebuild. Failing to supply a shared scheme, omitting the -archivePath flag, or attempting to export without an ExportOptions.plist will cause terminal builds to complete without generating an archive that Xcode Organizer or distribution platforms can recognize.

How to fix it

1. Archive the project using xcodebuild archive

Ensure your target scheme is marked as Shared in Xcode (Product > Scheme > Manage Schemes, then check the Shared box next to your target scheme). Commit this change to your repository so CI runners can discover the scheme.

Navigate to your project root and run xcodebuild with the archive action:

xcodebuild \
  -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  -archivePath ./build/MyApp.xcarchive \
  archive

If you use a standalone .xcodeproj rather than a workspace, substitute -project MyApp.xcodeproj in place of -workspace MyApp.xcworkspace.

Key arguments:
– -scheme: The name of the shared build scheme.
– -configuration: Usually Release for distribution.
– -destination 'generic/platform=iOS': Instructs the compiler to build a generic iOS binary rather than targeting a locally connected device or simulator.
– -archivePath: The directory where xcodebuild generates the .xcarchive package.
– archive: The build action that packages binaries, metadata, and dSYM symbol files together.

Once complete, the directory ./build/MyApp.xcarchive contains your archived application.

2. Export the archive to an IPA using ExportOptions.plist

To convert the .xcarchive into a signed .ipa file for distribution, create a configuration property list named ExportOptions.plist.

For App Store distribution, save the following XML into 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_10_CHAR_TEAM_ID</string>
    <key>signingStyle</key>
    <string>automatic</string>
    <key>uploadSymbols</key>
    <true/>
    <key>compileBitcode</key>
    <false/>
</dict>
</plist>

For Ad Hoc or Enterprise testing, change the method value from app-store to ad-hoc or enterprise.

Next, run the export command:

xcodebuild -exportArchive \
  -archivePath ./build/MyApp.xcarchive \
  -exportPath ./build/ExportedApp \
  -exportOptionsPlist ./ExportOptions.plist \
  -allowProvisioningUpdates

If successful, xcodebuild writes the signed .ipa file into ./build/ExportedApp/MyApp.ipa along with packaging logs and distribution manifests.

3. Handle headless signing on remote CI workers

When executing xcodebuild archive on headless runners (such as GitHub Actions, GitLab CI, or Jenkins), the build may stall or fail with keychain errors because the worker cannot access signing credentials interactively.

Unlock the login keychain before initiating the archive step:

security unlock-keychain -p "$KEYCHAIN_PASSWORD" ~/Library/Keychains/login.keychain-db

To upload directly to TestFlight or App Store Connect from the command line without opening Xcode Organizer, pass your App Store Connect API Key to xcodebuild during the export step:

xcodebuild -exportArchive \
  -archivePath ./build/MyApp.xcarchive \
  -exportPath ./build/ExportedApp \
  -exportOptionsPlist ./ExportOptions.plist \
  -authenticationKeyPath "/path/to/AuthKey_XXXXXXXXXX.p8" \
  -authenticationKeyID "XXXXXXXXXX" \
  -authenticationKeyIssuerID "00000000-0000-0000-0000-000000000000"

Using an App Store Connect API key eliminates interactive two-factor authentication prompts during command-line deployments.

How to prevent it

  • Check scheme sharing in git: Unchecked schemes stay in .xcuserdata directories, which are typically ignored by .gitignore. Always verify that schemes are checked as Shared in the Scheme Manager.
  • Keep ExportOptions up to date: Store your ExportOptions.plist template in source control alongside your build scripts so export configuration stays synchronized across machines.
  • Target generic destinations: Always pass -destination 'generic/platform=iOS' in CLI build tasks to avoid compiler errors caused by missing physical hardware.
  • Verify keychain timeouts: Configure CI build agents with extended keychain lock timeouts (security set-keychain-settings -t 3600) so long-running compilation tasks do not trigger keychain prompts midway through code signing.

FAQ

Where did PackageApplication go?

Apple deprecated PackageApplication in Xcode 7 and permanently removed it in Xcode 8.3. Modern CLI workflows must use xcodebuild -exportArchive to sign and assemble .ipa packages.

Can I view CLI-created archives in Xcode Organizer?

Yes. If you specify an archive path inside ~/Library/Developer/Xcode/Archives/YYYY-MM-DD/YourApp.xcarchive, Xcode Organizer automatically detects and displays the archive alongside GUI-created builds.

How do I check available schemes from the terminal?

Run xcodebuild -list in your project root. The output lists all targets, build configurations, and discoverable shared schemes available for building and archiving.

Sources & credits

Parts of this guide are adapted from content licensed under CC BY-SA 2.5; this article is shared under the same license.