Skip to content

Codemagic Integration

This guide will help you integrate Shorebird into your Codemagic workflows.

Codemagic runs Shorebird from either of its two ways of configuring a build:

  • Workflow Editor. Codemagic’s Flutter Workflow Editor has a Shorebird section for Android and iOS. Under Publish updates to user devices using Shorebird, choose Release or Patch, and paste a key (see Authentication) into its Shorebird token field. Codemagic’s Shorebird guide walks through each field.
  • codemagic.yaml. Write the shorebird release and shorebird patch steps yourself, which works for every platform Shorebird supports and lets you run other Shorebird commands. The rest of this page covers this route. If you’re new to the file, see the Codemagic YAML documentation.

This guide assumes that:

  1. Your app has been initialized with shorebird init, and shorebird.yaml is committed to your repository.
  2. Codemagic is connected to your repository (guide).

Creating releases and patches needs a signed-in Shorebird CLI. In CI, the CLI reads an API key from the SHOREBIRD_TOKEN environment variable, so nobody has to run shorebird login on the builder.

Use a key that belongs to a service account. A service account belongs to your organization rather than to a person, so its key keeps working when whoever set up CI leaves or changes roles, and the audit log shows the job’s actions under the service account’s name. Service accounts are available on every plan. To create one, you need the Admin or Owner role in the organization:

  1. In the Shorebird Console, open your organization’s Settings and select Service accounts.
  2. Click Create service account, name it after the CI system that will use it (such as GitHub Actions), and click Create.
  3. Keep the Developer role, which can create releases and patches. Choose App Manager instead if the job also creates apps, for example by running shorebird init.
  4. Under API keys, click Create key, enter a name, and choose an expiration.
  5. Copy the key. It is shown only once.

Store the key as SHOREBIRD_TOKEN in your CI platform’s secrets manager, as the steps below show.

If you can’t create a service account, a personal API key from Account → API Keys goes in SHOREBIRD_TOKEN the same way. It acts as you, can do at most what your own role allows, and stops working if your account is deleted. See API Keys.

Next, with the key copied, navigate to your Codemagic secrets:

  1. Select the “teams” tab on the left sidebar.
  2. Select the team you want to add the secret to.
  3. Select the “Global Variables and Secrets” tab.
  4. Enter SHOREBIRD_TOKEN as variable name.
  5. Paste the token into the variable value field.
  6. Add it to a group named shorebird.
  7. Ensure “Secure” is checked.

Screenshot of the "Environment Variables" tab in
Codemagic

This section shows you how to set up a Codemagic workflow to create Android releases, distribute them to the Play Store, and patch them once they’ve been distributed, using codemagic.yaml. To use the Workflow Editor instead, see Choose how to configure Codemagic.

As a preview, the finished codemagic.yaml file will look like this:

definitions:
  environment:
    shared_env: &shared_env
      flutter: 3.47.9
      groups:
        - shorebird
        - play_store
      vars:
        FLUTTER_VERSION: 3.47.9
  scripts:
    - &shorebird_install
      name: Install Shorebird
      script: |
        # Install Shorebird
        curl -fsSL https://shorebird.dev/install.sh | bash

        # Add Shorebird to PATH
        echo PATH="$HOME/.shorebird/bin:$PATH" >> $CM_ENV
    - &fetch_dependencies
      name: Fetch Dependencies
      script: |
        flutter pub get

workflows:
  release-android-workflow:
    name: Release Android
    instance_type: mac_mini_m2
    environment:
      <<: *shared_env
      android_signing:
        - android_keystore
    scripts:
      - *shorebird_install
      - *fetch_dependencies
      - name: Shorebird Release
        script: |
          shorebird release android \
            --flutter-version="$FLUTTER_VERSION"
    artifacts:
      - build/**/outputs/**/*.aab
      - build/**/outputs/**/mapping.txt
      - flutter_drive.log
    publishing:
      google_play:
        credentials: $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS
        track: internal
  patch-android-workflow:
    name: Patch Android
    instance_type: mac_mini_m2
    environment:
      <<: *shared_env
      android_signing:
        - android_keystore
    inputs:
      release_version:
        description: The release version to patch
    scripts:
      - *shorebird_install
      - *fetch_dependencies
      - name: Shorebird Patch
        script: |
          shorebird patch android \
            --release-version=${{ inputs.release_version }} \
            --track=stable

Give Codemagic permission to publish to the Play Store

Section titled “Give Codemagic permission to publish to the Play Store”

You can follow the Codemagic guide here to set this up. This example places the GCLOUD_SERVICE_ACCOUNT_CREDENTIALS variable in a group named play_store.

You can follow the Codemagic guide here to create a keystore and upload it to Codemagic. This example uses android_keystore as the name of the uploaded keystore.

You will also also need to update your android/app/build.gradle file to use this keystore in the Codemagic CI environment:

signingConfigs {
  release {
    if (System.getenv()['CI']) { // CI=true is exported by Codemagic
      storeFile file(System.getenv()['CM_KEYSTORE_PATH'])
      storePassword System.getenv()['CM_KEYSTORE_PASSWORD']
      keyAlias System.getenv()['CM_KEY_ALIAS']
      keyPassword System.getenv()['CM_KEY_PASSWORD']
    } else {
      keyAlias keystoreProperties['keyAlias']
      keyPassword keystoreProperties['keyPassword']
      storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
      storePassword keystoreProperties['storePassword']
    }
  }
}

At the top of the codemagic.yaml file, define shared environment variables and scripts that will be used by multiple workflows. This has been annotated to explain what each part does.

definitions:
  environment:
    # Use &shared_env to allow us to reference this environment in other
    #   parts of the file
    shared_env: &shared_env
      flutter: 3.47.9
      groups:
        # Add the shorebird group to make $SHOREBIRD_TOKEN available to
        #   the Shorebird CLI.
        - shorebird
        # Add the play_store group to make $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS
        #   available to the Google Play Publishing step.
        - play_store
      vars:
        FLUTTER_VERSION: 3.47.9
  scripts:
    # A step to install Shorebird and add it to the host machine's PATH
    - &shorebird_install
      name: Install Shorebird
      script: |
        # Install Shorebird
        curl -fsSL https://shorebird.dev/install.sh | bash

        # Add Shorebird to PATH
        echo PATH="$HOME/.shorebird/bin:$PATH" >> $CM_ENV
    - &fetch_dependencies
      name: Fetch Dependencies
      script: |
        flutter pub get

Add the following workflow to your codemagic.yaml file. This has been annotated to explain what each part does.

workflows:
  release-android-workflow:
    name: Release Android
    # This can run on any instance type.
    instance_type: mac_mini_m2
    environment:
      # Add the shared_env we defined in the definitions section.
      <<: *shared_env
      # Make the keystore available so we can use release signing.
      android_signing:
        # "android_keystore" is the name of the keystore we uploaded
        #   to Codemagic.
        - android_keystore
    scripts:
      - *shorebird_install
      - *fetch_dependencies
      # Run `shorebird release android` to create a release.
      # This will upload the release to Shorebird and generate
      #   the artifacts listed below.
      - name: Shorebird Release
        script: |
          shorebird release android \
            --flutter-version="$FLUTTER_VERSION"
    # Tell Codemagic where to find the artifacts to publish.
    artifacts:
      - build/**/outputs/**/*.aab
      - build/**/outputs/**/mapping.txt
      - flutter_drive.log
    publishing:
      # Publish to the Google Play Store on the internal track.
      google_play:
        credentials: $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS
        track: internal

With this, you should be able to create a release in Shorebird and publish it to the Google Play Store via Codemagic.

Add the following workflow to your codemagic.yaml file. This has been annotated to explain what each part does.

workflows:
  patch-android-workflow:
    name: Patch Android
    # As with the release workflow, this can run on any instance type.
    instance_type: mac_mini_m2
    environment:
      # Add the shared_env we defined in the definitions section.
      <<: *shared_env
      # Make the keystore available so we can use release signing.
      android_signing:
        # "android_keystore" is the name of the keystore we uploaded
        #   to Codemagic.
        - android_keystore
    # Add an input to allow us to specify the release version to patch.
    # This will make this workflow reusable across releases.
    inputs:
      release_version:
        description: The release version to patch
    scripts:
      - *shorebird_install
      - *fetch_dependencies
      - name: Shorebird Patch
        # Run `shorebird patch android` to patch the specified release.
        script: |
          shorebird patch android \
            --release-version=${{ inputs.release_version }} \
            --track=stable

With this, you should be able to patch a release in Shorebird via Codemagic.

This section shows you how to set up a Codemagic workflow to create iOS releases, distribute them to TestFlight, and patch them once they’ve been distributed, using codemagic.yaml. To use the Workflow Editor instead, see Choose how to configure Codemagic.

Codemagic has a guide on how to set up code signing for iOS here. This guide will help you generate the necessary keys, certificates, and provisioning profiles and load them into Codemagic.

Once you’ve done that, you will need to make these available to your codemagic.yaml scripts. You will end up with four environment variables to support this:

  • KEY_ID: This will be copied directly from App Store Connect.
  • ISSUER_ID: This will be copied directly from App Store Connect.
  • APP_STORE_CONNECT_PRIVATE_KEY: This will be the contents of the private key file you downloaded from App Store Connect. An easy way to get this into Codemagic is to run cat /path/to/AuthKey_12345678.p8 | pbcopy which will copy the contents of the file to your clipboard. You can then paste this into Codemagic.
  • CERTIFICATE_PRIVATE_KEY: Follow this guide to obtain ios_distribution_private_key file. You can then paste the contents of this file into Codemagic. cat ios_distribution_private_key | pbcopy works well for this.

This example places all of these variables into a group named app_store.

At the top of the codemagic.yaml file, define shared environment variables and scripts that will be used by multiple workflows. This has been annotated to explain what each part does.

definitions:
  environment:
    shared_env: &shared_env
      flutter: 3.47.9
      # Pin Xcode and CocoaPods so the release and its patches build with the
      # same versions.
      xcode: 26.6
      cocoapods: 1.16.2
      groups:
        # Export the shorebird group to make $SHOREBIRD_TOKEN available to
        #   the Shorebird CLI.
        - shorebird
        # Export the app_store group to make the iOS code signing variables
        #   available the scripts below.
        - app_store
      vars:
        # The bundle ID of this example app.
        # Replace this with your app's bundle id.
        BUNDLE_ID: dev.shorebird.codemagic-demo
        FLUTTER_VERSION: 3.47.9
  scripts:
    # Download the Shorebird CLI and add it to the PATH.
    - &shorebird_install
      name: Install Shorebird
      script: |
        # Install Shorebird
        curl -fsSL https://shorebird.dev/install.sh | bash

        # Add Shorebird to PATH
        echo PATH="$HOME/.shorebird/bin:$PATH" >> $CM_ENV
    - &ios_initialize_keychain
      # Set up the keychain to be used for code signing. Create the keychain
      #   at specified path with specified password with given timeout.
      # Make it default and unlock it for upcoming use.
      name:
        Set up keychain to be used for codesigning using Codemagic CLI
        'keychain' command
      script: |
        keychain initialize
    - &fetch_signing_files
      # Fetch provisioning profiles and code signing certificates for
      #   the Bundle ID with given identifier.
      name: Fetch signing files
      script: |
        app-store-connect fetch-signing-files "$BUNDLE_ID" \
          --type IOS_APP_STORE --create \
          --issuer-id "$ISSUER_ID" \
          --key-id "$KEY_ID" \
          --private-key="$APP_STORE_CONNECT_PRIVATE_KEY"
    - &add_certs_to_keychain
      name: Add certs to keychain
      script: |
        keychain add-certificates
    - &use_profiles
      # This generates an export_options.plist file that tells Xcode
      #   how to package the app. This explicitly sets
      #   manageAppVersionAndBuildNumber to control which
      #   version and build number are used for releasing and patching.
      name: Set up code signing settings on Xcode project
      script: |
        xcode-project use-profiles --custom-export-options={\"manageAppVersionAndBuildNumber\":false}
    - &fetch_dependencies
      name: Fetch Dependencies
      script: |
        flutter pub get

Without an xcode: value, Codemagic builds with its default Xcode, which moves to a newer version when Codemagic updates its machines. Build each iOS patch with the same Xcode as the release it patches: a different Xcode can make the patch report asset or Podfile.lock changes you didn’t make, which stops it in CI (see Build patches with the same toolchain as the release).

So the shared configuration above sets xcode: to a version from Codemagic’s macOS machine list, rather than latest or edge. It also sets cocoapods: to a version, since the default is whatever the machine image has when the build runs, and the CocoaPods version is recorded in Podfile.lock. Use the version on the COCOAPODS: line of your Podfile.lock. Keep both while you patch a release, and change them when you create a new one.

Add the following workflow to your codemagic.yaml file. This has been annotated to explain what each part does.

workflows:
  release-ios-workflow:
    name: Release iOS
    # This needs to run on a Mac instance.
    instance_type: mac_mini_m2
    integrations:
      # "Codemagic" is the name of the App Store Connect API key.
      app_store_connect: Codemagic
    environment:
      <<: *shared_env
      # Tell Codemagic that this app is being signed for App Store distribution
      #   and to use the bundle ID we defined above.
      ios_signing:
        distribution_type: app_store
        bundle_identifier: '$BUNDLE_ID'
    scripts:
      # Use the scripts we defined in the definitions section.
      - *shorebird_install
      - *fetch_dependencies
      - *fetch_signing_files
      - *ios_initialize_keychain
      - *add_certs_to_keychain
      - *use_profiles
      - name: Shorebird Release
        # Run `shorebird release ios` to create a release.
        script: |
          shorebird release ios \
            --flutter-version="$FLUTTER_VERSION" \
            --export-options-plist=/Users/builder/export_options.plist
    # Tell Codemagic where to find the artifacts generated by
    #   the `shorebird release ios` command.
    artifacts:
      - build/ios/ipa/*.ipa
    publishing:
      app_store_connect:
        # Use referenced App Store Connect API key to authenticate binary upload.
        auth: integration
        # Submit the release to TestFlight, where it can be downloaded by beta
        #   users and later patched by Shorebird.
        submit_to_testflight: true

With this, you should be able to create a release in Shorebird and publish it to TestFlight via Codemagic.

Add the following workflow to your codemagic.yaml file:

workflows:
  patch-ios-workflow:
    name: Patch iOS
    # This needs to run on a Mac instance.
    instance_type: mac_mini_m2
    environment:
      <<: *shared_env
      # Tell Codemagic that this app is being signed for App Store distribution
      #   and to use the bundle ID defined above.
      ios_signing:
        distribution_type: app_store
        bundle_identifier: '$BUNDLE_ID'
    # Add an input to allow us to specify the release version to patch.
    # This will make this workflow reusable across releases.
    inputs:
      release_version:
        description: The release version to patch
    scripts:
      - *shorebird_install
      - *fetch_dependencies
      - *fetch_signing_files
      - *ios_initialize_keychain
      - *add_certs_to_keychain
      - *use_profiles
      - name: Shorebird Patch
        # Run `shorebird patch ios` to patch the specified release.
        script: |
          shorebird patch ios \
            --release-version=${{ inputs.release_version }} \
            --track=stable \
            --export-options-plist=/Users/builder/export_options.plist

With this, you should be able to patch a release in Shorebird via Codemagic.