skip to content

In codemagic.yaml, how does ios_signing, backed by an App Store Connect API key, let Codemagic sign a Flutter iOS build automatically?

level: middleimportance: must knowfreq 52%

answer

  1. Issuer ID, Key ID, .p8
  2. Code signing identities by reference name
  3. distribution_type plus bundle_identifier
  4. app_store for TestFlight, ad_hoc for testers
  5. xcode-project use-profiles before building

basics

~20 s

An App Store Connect API key (Issuer ID, Key ID, .p8 file) lets Codemagic create certificates and fetch provisioning profiles into Code signing identities. ios_signing with distribution_type and bundle_identifier installs the matching files at build time, and xcode-project use-profiles applies them.

solid answer

~40 s

You create an App Store Connect API key (App Manager access is recommended and needed for publishing), note its **Issuer ID** and **Key ID**, and upload the `.p8` under Team integrations, Developer Portal. With that key Codemagic's **Code signing identities** can generate an Apple Distribution certificate and fetch provisioning profiles from the Developer Portal, or you upload a `.p12` and `.mobileprovision` yourself, each with a reference name. In the workflow, `environment.ios_signing` takes either `distribution_type` (`app_store`, `ad_hoc`, `development`, `enterprise`) plus `bundle_identifier`, both required, or explicit `certificates` and `provisioning_profiles` reference lists; the two forms cannot be mixed. Codemagic installs the files, including profiles for extensions such as `com.example.id.NotificationService`, and a `xcode-project use-profiles` script applies them before `flutter build ipa`. Use `app_store` for TestFlight and the App Store, `ad_hoc` for services like Firebase App Distribution.

code

yaml · 23 lines
yaml
workflows:
  ios-release:
    name: Scooter iOS release
    instance_type: mac_mini_m2
    integrations:
      app_store_connect: scooter_asc_key
    environment:
      flutter: stable
      xcode: latest
      ios_signing:
        distribution_type: app_store
        bundle_identifier: com.example.scooter
    scripts:
      - name: Apply provisioning profiles
        script: xcode-project use-profiles
      - name: Get packages
        script: flutter pub get
      - name: Build signed IPA
        script: |
          flutter build ipa --release \
            --export-options-plist=/Users/builder/export_options.plist
    artifacts:
      - build/ios/ipa/*.ipa

go deeper

for a junior

Recall that iOS builds need a certificate and a profile, and that Codemagic gets them through an App Store Connect API key.

for a middle

Walk through the key, Code signing identities, the two ios_signing forms and why use-profiles runs before flutter build ipa.

for a senior

Diagnose signing failures from the distribution type, bundle ID and certificate-profile pairing, and plan for the one-time .p8 download.

for a principal

Decide whether signing assets live in Codemagic, in a match repository or in scripts, weighing vendor lock-in against setup cost.

## What iOS signing needs Every iOS build installed on a real device must be signed with a **certificate** (the identity, stored with its private key as a `.p12`) and a **provisioning profile** (which app, which devices or which distribution channel). On a CI machine these files have to arrive without a person clicking in Xcode. Codemagic's answer is to hold them centrally and install them per build. ## Step 1: the App Store Connect API key An **App Store Connect API key** lets Codemagic talk to Apple on your behalf: 1. In App Store Connect, open Users and Access, Integrations, App Store Connect API, and generate a key. Codemagic recommends **App Manager** access; publishing to App Store Connect requires it. 2. Download the `.p8` file. Apple lets you download it **only once**. 3. Note the **Issuer ID** (above the key table) and the key's **Key ID**. 4. In Codemagic, Team settings, Team integrations, Developer Portal, **Manage keys**, add the key under a human-readable name. ## Step 2: Code signing identities Under Team settings, codemagic.yaml settings, **Code signing identities** (team admins upload and edit; everyone can view): - **iOS certificates**: upload a `.p12` or `.pem` with its password and a **reference name**, or click **Generate certificate** to create an Apple Development or Apple Distribution certificate through the API key. A generated certificate can be downloaded once, right after creation. - **iOS provisioning profiles**: upload a `.mobileprovision`, or **Fetch profiles** from the Developer Portal through the API key, giving each a reference name. Codemagic shows whether a matching certificate exists. ## Step 3: ios_signing in the workflow | Form | Keys | When to use | |---|---|---| | By type and bundle ID | `distribution_type`, `bundle_identifier` (both required) | Most apps; also picks up extension profiles like `com.example.id.*` | | By reference | `certificates`, `provisioning_profiles` lists, optional `environment_variable` per file | Several apps or unusual combinations | The two forms are **mutually exclusive**. Files land in `~/Library/MobileDevice/Provisioning Profiles` and `~/Library/MobileDevice/Certificates`, and the keychain steps are handled for you. `distribution_type` values are `app_store`, `ad_hoc`, `development` and `enterprise`. TestFlight and App Store uploads need `app_store`; a third-party tester service such as Firebase App Distribution needs `ad_hoc`. ## Step 4: apply and build Before the Flutter build, a script runs **`xcode-project use-profiles`**, Codemagic's CLI command that sets the Xcode project's signing settings to the installed profiles. Then `flutter build ipa` produces a signed `.ipa`. Passing `--custom-export-options='{"testFlightInternalTestingOnly": true}'` to `use-profiles` marks a build for internal TestFlight testers only. ## Other jobs the same key does The API key is not only for signing. Referenced from a workflow as `integrations: app_store_connect: <key name>`, it also authenticates: - **publishing**, through `publishing.app_store_connect` with `auth: integration`; - Codemagic's **CLI tools** in scripts, for example `app-store-connect get-latest-testflight-build-number` to compute the next build number. If you prefer not to use the integration, the same three values can live in a Secret variable group and be passed to publishing as `api_key`, `key_id` and `issuer_id`. Codemagic's docs note that publishing with an Apple ID and app-specific password is deprecated and does not trigger post-processing actions. To publish apps under different Apple Developer accounts, set up separate workflows, each naming its own key. ## The CLI alternative Codemagic also documents a script-only route: `keychain initialize`, then `app-store-connect fetch-signing-files "$BUNDLE_ID" --type IOS_APP_STORE --create` using a `CERTIFICATE_PRIVATE_KEY` variable, then `keychain add-certificates` and `xcode-project use-profiles`. It fetches or creates matching files at build time. Teams already on fastlane match use a different mechanism entirely; that is its own topic. ## Common failures - `development` or `ad_hoc` chosen for a TestFlight upload. - The bundle ID in `ios_signing` differs from the Runner target's bundle ID. - A certificate uploaded without its private key, or a profile whose certificate is missing (Codemagic's checkmark shows this). - An iOS workflow on a Linux or Windows instance; signing and `flutter build ipa` need a macOS machine such as `mac_mini_m2`.

  • Why does a Codemagic ios_signing bundle_identifier also fetch profiles for com.example.scooter.NotificationService?
    Codemagic matches the given bundle identifier and any identifier beneath it, so app extensions such as a notification service get their own profiles installed. Each extension still needs its own provisioning profile uploaded or fetched in Code signing identities.
  • When would you use ios_signing's certificates and provisioning_profiles lists instead of distribution_type?
    When the type-and-bundle match is too coarse: several apps sharing a workflow, a specific certificate among many, or a script needing the file path. Each entry names a reference and can export an `environment_variable` pointing at the file on disk. You cannot combine these lists with `distribution_type`.
  • What can go wrong with the App Store Connect API key itself?
    The `.p8` can be downloaded only once, so losing it means creating a new key and updating Codemagic. A key with too little access can sign but fail to publish; App Store Connect publishing needs App Manager permission.

saying these in an interview costs you the question

  • distribution_type development is right for a TestFlight upload
  • distribution_type can be combined with a provisioning_profiles list
  • The .p8 API key can be downloaded again from App Store Connect
  • bundle_identifier matches only the main app, never its extensions
  • An iOS signing workflow can run on a linux_x2 instance