skip to content

Xcode Archive & Upload

Getting a Flutter app onto App Store Connect: flutter build ipa, automatic or manual Xcode signing with certificates and profiles, and the plist keys that review checks. Interviewers probe signing.

part ofFlutteroverview, primer and where to startread it →
on this pageshow

explore

questions

5

In Flutter, what does flutter build ipa produce, and how does that output reach App Store Connect?

level: juniorimportance: must knowfreq 55%

answer

  1. archive first, then export
  2. build/ios/archive holds the .xcarchive
  3. build/ios/ipa holds the .ipa
  4. --export-method defaults to app-store
  5. Transporter, xcrun altool or Xcode

basics

~10 s

flutter build ipa archives the app in release mode into an .xcarchive under build/ios/archive, then exports a signed App Store .ipa into build/ios/ipa; you upload that .ipa with Transporter, xcrun altool or Xcode.

solid answer

~30 s

`flutter build ipa` (alias `xcarchive`) runs only on macOS. It builds in release mode by default and does two things: an Xcode **archive** into `build/ios/archive/Runner.xcarchive`, then `xcodebuild -exportArchive` into `build/ios/ipa`. The export method defaults to `app-store`, which the tool passes to Xcode 15.4+ as `app-store-connect`; `--export-method ad-hoc|development|enterprise` picks another channel, and `--export-options-plist` hands Xcode a full `ExportOptions.plist` instead. The command does not upload anything: you drag the `.ipa` into Apple's Transporter app, run `xcrun altool --upload-app`, or open the archive in Xcode and use Distribute App.

code

bash · 9 lines
bash
flutter build ipa
ls build/ios/archive build/ios/ipa

flutter build ipa --export-method ad-hoc

flutter build ipa --export-options-plist=ios/ExportOptions.plist

xcrun altool --upload-app --type ios -f build/ios/ipa/*.ipa \
  --apiKey "$ASC_KEY_ID" --apiIssuer "$ASC_ISSUER_ID"

go deeper

for a junior

Recall the two outputs and their folders: the .xcarchive under build/ios/archive and the .ipa under build/ios/ipa, and that uploading is a separate step.

for a middle

Explain the archive, validate and export stages, the default app-store method, the Xcode 15.4 renaming, and why --export-options-plist and --export-method cannot be combined.

for a senior

Show you know a failed export still exits zero, so a pipeline must check for the .ipa, and that --no-codesign stops at the archive.

for a principal

Discuss where the IPA should be produced and signed in a release process, and what a local archive, a CI archive and an Xcode Organizer export each trade in reproducibility.

## What the command is `flutter build ipa` is the Flutter CLI's release path for iOS. Its source describes it as building "an iOS archive bundle and IPA for distribution", it accepts `xcarchive` as an alias, and it can only run on a **macOS host** because it drives `xcodebuild`. Like the other `flutter build` subcommands it defaults to **release mode**; `--profile` and `--debug` exist but are not what you ship. Two artefact types matter: - **`.xcarchive`** — an Xcode archive: the compiled, signed `.app` plus its debug symbols and metadata. Xcode's Organizer can open it, validate it and distribute it. - **`.ipa`** — the iOS App Store Package, a zip of the `.app` re-signed for one distribution method. This is the file App Store Connect accepts. ## The two stages 1. **Archive.** The tool compiles the Dart code ahead of time, builds the Runner Xcode project with the Release configuration and archives it into `build/ios/archive/Runner.xcarchive` (the name follows the product name). Signing happens here with whatever the Runner target's Signing & Capabilities settings say. 2. **Validate.** It reads the archived `Info.plist` and prints an **App Settings Validation** summary: version number, build number, display name, deployment target and bundle identifier, flagging a missing value, a leftover `com.example` bundle ID, and placeholder app icons or launch images. 3. **Export.** It runs `xcrun xcodebuild -exportArchive` with `-allowProvisioningUpdates` and `-allowProvisioningDeviceRegistration`, writing the `.ipa` into `build/ios/ipa`. Unless you pass a plist, it writes a temporary `ExportOptions.plist` containing the export method. With `--no-codesign` the tool stops after the archive and prints that it is skipping the IPA: useful when a later step signs, useless for an upload. ## Export methods | `--export-method` | Meant for | Name sent to Xcode 15.4+ | |---|---|---| | `app-store` (default) | App Store Connect and TestFlight | `app-store-connect` | | `ad-hoc` | a limited set of test devices; needs a distribution certificate | `release-testing` | | `development` | devices registered on the developer account | `debugging` | | `enterprise` | Apple Developer Enterprise Program apps | `enterprise` | Xcode 15.4 renamed the first three methods, and the Flutter tool translates the old names when it detects that Xcode (a fix that shipped in Flutter 3.24). `--export-options-plist path/to/ExportOptions.plist` replaces the whole generated file; it is **rejected together with `--export-method`**, and the method is then read from the plist's `method` key. A common way to get such a plist is to distribute once from Xcode, which saves an `ExportOptions.plist` next to the exported IPA. ## Uploading to App Store Connect The command ends at a file; after an App Store export it prints the two upload routes: - **Transporter** — drag `build/ios/ipa/*.ipa` into Apple's Transporter macOS app. - **`xcrun altool --upload-app --type ios -f build/ios/ipa/*.ipa --apiKey … --apiIssuer …`** — the scriptable route, authenticated with an App Store Connect API key. - **Xcode** — open the `.xcarchive`, click Validate App, then Distribute App. App Store Connect then processes the build; once it finishes, the build can go to TestFlight or to review. ## When the export step fails If `-exportArchive` fails (a missing distribution profile is the usual cause), the tool prints only the `error:` lines from Xcode, tells you to open the archive in Xcode, and **still exits successfully**, because the archive itself succeeded. A CI job that only checks the exit code will therefore report green with no `.ipa`; checking that `build/ios/ipa` contains a file is the safer gate. ## A typical release sequence Putting the pieces together, a first App Store release of a Flutter app usually runs in this order: 1. Set the bundle identifier, display name, team and signing in Xcode on the Runner target, and replace the placeholder icon and launch image. 2. Run `flutter build ipa` and read the App Settings Validation summary; fix anything reported as missing or still set to a template value. 3. Confirm that `build/ios/ipa` contains an `.ipa`, not just that the command exited. 4. Upload with Transporter, `xcrun altool` or Xcode, then wait for App Store Connect to finish processing before choosing TestFlight or review. Re-running the command overwrites both folders, so keep a copy of any archive you uploaded if you want its symbols and exact binary later. Building from Xcode's own Product > Archive menu produces an equivalent archive, but going through the Flutter tool keeps the Dart build settings, the version from `pubspec.yaml` and the validation summary in one reproducible command. ## Common misconceptions - The command does **not** upload; it only produces files. - The outputs live under `build/ios/`, not under the Android `build/app/outputs` tree. - The default is an **App Store** export in release mode, not a development build. - The validation summary is a sanity check of a few `Info.plist` values and assets, not App Review: it does not look at purpose strings or the privacy manifest.

  • Can flutter build ipa run on a Linux or Windows CI runner?
    No. The command is documented in its source as macOS-only because both stages shell out to `xcodebuild`: the archive and the `-exportArchive` step. A Linux runner can run tests and build Android; the iOS archive needs a Mac with Xcode installed.
  • The export step failed but the CI job is green; how can that happen?
    When `xcodebuild -exportArchive` fails, `flutter build ipa` prints the `error:` lines, points you at the archive to distribute from Xcode, and returns success because the `.xcarchive` was produced. Add a step that fails when `build/ios/ipa` holds no `.ipa`.
  • Does the App Settings Validation summary mean the build will pass review?
    No. It only reports version, build number, display name, deployment target and bundle ID, warns on a `com.example` bundle ID, and flags placeholder icons and launch images. Purpose strings, the privacy manifest and review guidelines are not checked there.

saying these in an interview costs you the question

  • flutter build ipa uploads the build to App Store Connect by itself.
  • The .ipa is written to build/app/outputs next to the Android bundle.
  • flutter build ipa can run on a Linux runner if Xcode is not needed.
  • With no flags it produces a debug, development-signed IPA.
  • A failed IPA export makes the whole command exit with an error.
  • You can pass --export-method and --export-options-plist together to override one key.
open as a page

For a Flutter iOS release, how do a distribution certificate and a provisioning profile differ, and when would you switch Xcode to manual signing?

level: middleimportance: must knowfreq 50%

basics

~20 s

A distribution certificate is the signing identity, usable only with its private key in the Mac's keychain; a provisioning profile is Apple's file binding an App ID, team, certificate and entitlements. Manual signing fits machines without an Apple account session.

open as a page

A Flutter church-events app's App Store build is rejected for a missing purpose string; what is a purpose string, and where do you add it?

level: juniorimportance: should knowfreq 45%

basics

~20 s

A purpose string is an NS...UsageDescription key, such as NSCameraUsageDescription, in ios/Runner/Info.plist whose text iOS shows in the permission prompt; each protected resource the app uses needs one, and Flutter plugins never add it for you.

open as a page

In a Flutter iOS app, what is PrivacyInfo.xcprivacy, and which parts of the app are expected to ship one?

level: middleimportance: should knowfreq 30%

basics

~10 s

PrivacyInfo.xcprivacy is Apple's privacy manifest, a plist declaring tracking, collected data types and required-reason API use; Flutter's engine framework ships one, plugins ship their own, and the app adds one for its own code.

open as a page

Why would a Flutter iOS app built with the Xcode 27 SDK crash at launch, and what does the UIScene migration change in its iOS project?

level: seniorimportance: should knowfreq 22%

basics

~20 s

Apple requires the UIScene lifecycle for UIKit apps built with the iOS 27 SDK, and a Flutter app that has not adopted it crashes at launch; migration adds a scene manifest to Info.plist and moves plugin registration out of didFinishLaunching.

open as a page