For a Flutter iOS release, how do a distribution certificate and a provisioning profile differ, and when would you switch Xcode to manual signing?
answer
- identity versus permission slip
- private key lives in the keychain
- profile binds App ID, team, certificate
- Automatically manage signing is on by default
- CODE_SIGN_STYLE Manual plus a profile specifier
basics
~20 sA 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.
solid answer
~50 sA **distribution certificate** proves who signed the app; it only signs if its **private key** is in the build Mac's keychain. A **provisioning profile** (`.mobileprovision`) is issued by Apple and says what may be signed: it ties the App ID (bundle identifier), the team, the allowed certificates and the entitlements, plus device UDIDs for development and ad-hoc builds. In a Flutter project these settings live on the Runner target in Xcode, where **Automatically manage signing** is on by default and Xcode fetches or renews both through the signed-in account. You switch the Release configuration to `CODE_SIGN_STYLE = Manual` with `DEVELOPMENT_TEAM` and `PROVISIONING_PROFILE_SPECIFIER` when the machine has no Apple account session, such as a CI Mac, or when a team must use one shared certificate. Since Flutter 3.41, `flutter build ipa` then generates a manual `ExportOptions.plist` for the main bundle.
go deeper
Recall the split: certificate is who signed and needs its private key; profile is what may be signed and with which capabilities.
Explain what a profile binds, why App Store profiles have no devices, and the three build settings that make the Runner target manually signed.
Diagnose export failures: missing private key, profile not matching the bundle ID, and extensions left out of the plist Flutter generates for manual signing.
Weigh automatic signing on each developer Mac against one shared, manually managed distribution identity, and who owns renewals and revocations.
## Why iOS needs two artefacts iOS runs only code signed in a way Apple can trace, so an App Store build needs two different things: - **Who signed it** — the **certificate**. - **What that signer may sign, and with which capabilities** — the **provisioning profile**. A Flutter app is no exception: the Dart code is compiled into the Runner app, and Xcode signs that bundle like any other iOS app. All signing settings live on the **Runner** target in `ios/Runner.xcworkspace`. ## The certificate A certificate is issued by Apple for a public key whose **private key** stays on the machine that created the signing request, in its **keychain**. Two kinds matter: - **Development** — signs builds you run on your own registered devices. - **Distribution** — signs App Store, ad-hoc and TestFlight builds. A `.cer` file alone cannot sign anything. The classic failure on a new Mac is a certificate that shows up in the developer account but has no matching private key locally; exporting it with its key (a `.p12`) is how it moves between machines. ## The provisioning profile A profile is an Apple-signed file that binds together: 1. the **App ID**, which must match the Runner target's `PRODUCT_BUNDLE_IDENTIFIER`; 2. the **team**; 3. the **certificates** allowed to sign; 4. the **entitlements** the app may use, such as push notifications or associated domains; 5. for development and ad-hoc profiles only, the **device UDIDs** allowed to install the build. An App Store profile carries no device list. Each app extension (a share extension or a widget) has its own bundle ID and so needs its own profile. | | Certificate | Provisioning profile | |---|---|---| | Answers | who signed | what may be signed, where, with which capabilities | | Secret part | the private key in the keychain | none; it is not secret | | Scope | one team, many apps | one App ID (or a wildcard) | | Typical file | `.cer`, `.p12` with the key | `.mobileprovision` | ## Automatic versus manual signing **Automatic signing** is Xcode's *Automatically manage signing* checkbox, which the Flutter deployment guide notes is on by default and sufficient for most apps. Xcode uses the signed-in account to create and renew certificates and profiles. `flutter build ipa` also passes `-allowProvisioningUpdates` and `-allowProvisioningDeviceRegistration` to `xcodebuild -exportArchive`, so Xcode may fetch what the export needs. **Manual signing** means the Release configuration names exactly what to use: - `CODE_SIGN_STYLE = Manual` - `DEVELOPMENT_TEAM = <team id>` - `PROVISIONING_PROFILE_SPECIFIER = <profile name or UUID>` Reasons to choose it: - a build machine, typically CI, with no interactive Apple account session; - a team that must sign with one shared distribution certificate instead of letting each Xcode create its own; - extensions or entitlements that need specific, pre-made profiles. ## What flutter build ipa does with manual signing Since **Flutter 3.41**, when the Release or Profile build uses `CODE_SIGN_STYLE=Manual` and the tool finds the named profile in `~/Library/Developer/Xcode/UserData/Provisioning Profiles`, it generates an `ExportOptions.plist` with `method`, `teamID`, `signingStyle` set to `manual` and a `provisioningProfiles` entry mapping the bundle ID to the profile's UUID. Its own source lists the limit: **only the main bundle ID** is mapped. An app with extensions, or a profile the tool cannot find, falls back to a plist with just the method, and the fix is to pass `--export-options-plist` with every bundle ID mapped. ## Reading a signing failure Most signing errors name one of the pieces above, so the diagnosis follows the same order: 1. **No signing identity** — the keychain has no certificate with its private key for this team. Import the `.p12` or create a certificate from this Mac. 2. **No matching profile** — the profile's App ID does not match `PRODUCT_BUNDLE_IDENTIFIER`, it is the wrong type (development instead of App Store), or it is not installed. The Flutter tool prints its own hint when Xcode reports that a target requires a provisioning profile. 3. **Profile does not include the certificate** — the profile was generated before the current certificate existed; regenerate it. 4. **Missing entitlement** — a capability such as push notifications is enabled in Xcode but not in the profile. On a CI Mac the same checks apply, with the extra step of getting the certificate and profile onto a machine that is wiped between jobs; how those secrets are stored and synced is a pipeline concern rather than a signing concept. ## Common misconceptions - The profile does not contain the private key; the keychain does. - Automatic signing can produce App Store builds; manual signing is a choice for control, not a requirement for release. - A development certificate cannot export an App Store IPA.
- Why can a Flutter app with a share extension still fail export after switching to manual signing?The ExportOptions.plist that `flutter build ipa` generates for manual signing maps only the main bundle ID to its profile. The extension has its own bundle ID and needs its own profile, so pass `--export-options-plist` with a `provisioningProfiles` entry for every bundle ID.
- A certificate appears in the developer account but signing fails on a new Mac; what is missing?Its private key. A certificate signs only when the keychain holds the key created with its signing request. Import the `.p12` exported from the original machine, or create a new certificate from this Mac.
- Which Flutter-project file records the signing style?The Runner target's build settings in `ios/Runner.xcodeproj/project.pbxproj`, edited through Xcode's Signing & Capabilities tab. Nothing about signing lives in `pubspec.yaml`.
The certificate is a notary's seal, useless without the notary's own hand (the private key); the provisioning profile is the signed engagement letter saying which client, which documents and which extra powers that notary may use.
saying these in an interview costs you the question
- The provisioning profile contains the private key used to sign.
- An App Store provisioning profile lists every tester's device UDID.
- Automatic signing cannot produce App Store builds; release needs manual signing.
- One provisioning profile covers the app and all of its extensions.
- A development certificate is enough to export an App Store IPA.
- Signing settings for a Flutter iOS app are configured in pubspec.yaml.