================================================================================ source: https://docs.codemagic.io/rest-api/codemagic-rest-api/ title: API Overview description: REST API enabling programmatic access to Codemagic service last_modified: 2026-05-29 ================================================================================ # API Overview > REST API enabling programmatic access to Codemagic service The Codemagic REST API provides numerous possibilities for integrating your CI/CD builds with other tools or for managing advanced workflow chains. > > ⚠️ Note: We are transitioning to our new API. For up-to-date information, please refer to the [Codemagic REST API documentation](https://codemagic.io/api/v3/schema). > ## Authentication Authentication with Codemagic APIs is performed using a **Codemagic API token**. The Codemagic API token is a personal token that is unique to each Codemagic user. The actions permitted by the token are determined by the user’s role within the team. To find your API token, navigate to **Account settings > API token**. When making API calls, include the API token in the `x-auth-token` request header. For security reasons, we recommend storing the token as an environment variable and referencing it in your requests, rather than embedding the token value directly in your code or workflows. For example: ```bash x-auth-token: $CM_API_TOKEN ``` ### Regenerating an API token If you need to rotate your Codemagic API token, click **Revoke** next to the token in your account settings. This will disable the existing API token. Clicking **Show** afterward will automatically generate a new token. ================================================================================ source: https://docs.codemagic.io/flutter-publishing/publishing-to-app-store/ title: App Store Connect publishing using Flutter workflow editor description: How to deploy a Flutter app to App Store and TestFlight using the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # App Store Connect publishing using Flutter workflow editor > How to deploy a Flutter app to App Store and TestFlight using the Flutter workflow editor Codemagic enables you to automatically publish your app to App Store Connect for beta testing with TestFlight or distributing the app to users via App Store. To do so, you must first set up [iOS code signing](../code-signing/ios-code-signing/) using a distribution code signing [certificate](https://developer.apple.com/support/certificates/) and then configure publishing to App Store Connect. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured with **codemagic.yaml** please go to [Publishing to App Store Connect using codemagic.yaml](../yaml-publishing/app-store-connect). > ## Requirements Codemagic needs your **[App Store Connect API key](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api)** to perform publishing to App Store Connect on your behalf. Publishing to App Store Connect requires that the app is code signed with a [distribution certificate](https://developer.apple.com/support/certificates/). In addition, the application must be **App Store ready** for build distribution, meaning that it must have all the correct icons and icon sizes. Otherwise, App Store Connect will tag the binary as invalid, and you will not be able to distribute it at all. It is also worth pointing out the necessity for each uploaded binary to have a **different version**; otherwise, it will be refused by App Store Connect. See the [Build versioning](../building/build-versioning/) article for instructions on incrementing app version with Codemagic. > **Note:** You will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. > In order to be able to test iOS apps on Apple devices, manual device UDID registration in the Apple Developer Program account is required. Alternatively, Codemagic's automatic device registration can be used to register devices as explained [here](https://docs.codemagic.io/testing/ios-provisioning/). ## Setting up publishing to App Store Connect on Codemagic This section gives step-by-step instructions on how to configure publishing to App Store Connect using Flutter workflow editor. ### Step 1. Creating an App Store API key for Codemagic > > **Tip:** You may also reuse any of the keys you've already set up for automatic [iOS](../code-signing/ios-code-signing/#automatic-code-signing) or [macOS](../code-signing/macos-code-signing/#automatic-code-signing) code signing. > %!s()The Apple Developer Portal integration can be enabled in the **Team integrations** section in your team settings (if you're a team admin). This allows you to conveniently use the same access credentials for automatic code signing and publishing across different apps and workflows. 1. In the list of available integrations, click the **Connect** button for **Developer Portal**. 2. In the **App Store Connect API key name**, provide a name for the key you are going to set up the integration with. This is for identifying the key in Codemagic. 3. Enter the **Issuer ID** related to your Apple Developer account. You can find it above the table of active keys on the Integrations tab of the [Users and Access](https://appstoreconnect.apple.com/access/integrations/api) page. 4. Enter the **Key ID** of the key to be used for code signing. 5. In the **API key** field, upload the private API key downloaded from App Store Connect. 6. Click **Save** to finish the setup. If you work with multiple Apple Developer teams, you can add additional keys by clicking **Add another key** right after adding the first key and repeating the steps described above. You can delete existing keys or add new ones when you click **Manage keys** next to the Developer Portal integration in personal account or team settings. ### Step 3. Enabling App Store Connect publishing for workflow Once the Apple Developer Portal has been enabled for the account or team the app belongs to, you can easily enable App Store Connect publishing per workflow. 1. Navigate to **App settings > Distribution**. 2. Click **App Store Connect**. 3. If you have several keys available, select the right key in the **App Store Connect API key** field. 4. Mark the **Publish even if tests fail** checkbox to continue uploading the app artifact even when the tests failed. 5. Select **Enable App Store Connect publishing** at the top of the section to enable publishing. Your app will be now published to App Store Connect. However, you can select additional options to submit the build to TestFlight internal testing, TestFlight beta review or App Store review. #### Submitting an app to TestFlight internal testing In order to distribute your application to internal testers only, without requiring Apple's beta review: 1. Create a group and add internal testers (App Store Connect users with access to your content) to test your app using TestFlight in your App Store Connect portal. 2. In Codemagic workflow editor, create a new environment variable `XCODE_PROJECT_CUSTOM_EXPORT_OPTIONS` and assign the value `{"testFlightInternalTestingOnly": true}`. > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > #### Submitting an app to TestFlight beta review 1. Mark the **Submit to TestFlight beta review** checkbox to submit the build for beta review and prepare it for distributing to beta testers. Note: This action is performed during [post-processing](#post-processing-of-app-store-connect-distribution). 2. Mark the **Distribute to beta groups** checkbox and enter the names of the beta groups to automatically distribute the build to the testers in those groups once the build has passed beta review. Note: This action is performed during [post-processing](#post-processing-of-app-store-connect-distribution). #### Submitting an app to App Store review In order to submit your application to App Store review, mark the **Submit to App Store review** checkbox. Note: This action is performed during [post-processing](#post-processing-of-app-store-connect-distribution). Alternatively, if you wish to submit an already uploaded build for review in App Store Connect, follow the steps below: 1. Log in to [App Store Connect](https://appstoreconnect.apple.com/). 2. Navigate to **My Apps** and identify the app you would like to publish to App Store. 3. To start the submission process, click **Prepare for Submission**. 4. Check that your app metadata is up to date, and once everything is ready, click the **Submit for Review** button. When using the workflow editor, developers have a few different methods to choose from for publishing their app on Apple's App Store once it has been approved by Apple. Each method caters to different strategies and needs. By default, the release method is set to Manual Release. Here’s a breakdown of the release options available and how you can configure them in App Store Connect: **Release Methods** 1. **Manual Release**: Once your app is approved by Apple, you can choose when to release it on the App Store manually. This gives you complete control over the timing of the release. 2. **Automatic Release**: By selecting this option, your application will be automatically released on the App Store once it is approved by Apple. This feature is useful if you wish to make your app available to users as soon as possible without any manual intervention required. 3. **Scheduled Release**: You have the option to schedule a specific date and time for your app to be published on the App Store. This feature is useful if you want your app to be launched at a particular moment, such as the beginning of a business day or a particular event, but only after it has been approved by Apple. Configuration in App Store Connect To configure these release options, you need to navigate to App Store Connect. Here’s how you can set it up: 1. Log in to your Apple Developer account and access App Store Connect. 2. Select your app from the list of your applications. 3. Navigate to the 'App Store' tab, and then go to the **Distribution settings** section. 4. Scroll to the 'Version Release' section: Here, you will find options to manage how your app is released: * Choose "Manually release this version" if you want to manually push your app live after Apple's approval. * Select "Automatically release this version" to have the app go live as soon as Apple approves it. * Opt for "Automatically release this version after App Review, but no earlier than..." to set up a scheduled release. You can specify the date and time when the app should go live. These settings must be specified before you submit your app for review by Apple. Changing these settings after submission or post-approval might require another submission or at least an update in your App Store Connect configuration. ## Submitting release notes To add localized release notes that will appear in the Test Details (What to test?) section, include a `release_notes.json` with the following content: ```json [ { "language": "en-GB", "text": "British English release notes text" }, { "language": "en-US", "text": "The US English release notes text" } ] ``` Supported languages could be found [here](https://developer.apple.com/documentation/appstoreconnectapi/betabuildlocalizationcreaterequest/data/attributes). > > **Note:** Uploading release notes takes place in the [post-processing](#post-processing-of-app-store-connect-distribution) step. > ## Post-processing of App Store Connect distribution Some App Store Connect actions, like submitting the build to TestFlight beta review, distributing the build to beta groups and uploading release notes take place asynchronously in the post-processing step after the app artifact has been successfully published to App Store Connect and the main workflow has completed running in Codemagic. This avoids using the macOS build machine while we are waiting for Apple to complete processing the build and it becomes available for further actions. Post-processing has a two-step timeout. If the uploaded build cannot be found in App Store Connect in 15 minutes, the step times out. This may happen if there are issues with the uploaded artifact, in which case the build does not become available in App Store Connect at all and you'll receive an email from App Store Connect. The overall timeout for post-processing is 120 minutes. If the uploaded build has not exited the processing status by then, post-processing is cancelled. You will still be able to manually submit the build to beta review, upload release notes and distribute the app to beta groups once the build becomes available in App Store Connect. Note that Codemagic does not send status updates on the post-processing step. You can check the build log for the status of post-processing or check your email for updates from App Store Connect. Post-processing does not consume any build minutes. ================================================================================ source: https://docs.codemagic.io/yaml-publishing/app-store-connect/ title: App Store Connect publishing using codemagic.yaml description: How to deploy an app to App Store and TestFlight using codemagic.yaml last_modified: 2026-03-24 ================================================================================ # App Store Connect publishing using codemagic.yaml > How to deploy an app to App Store and TestFlight using codemagic.yaml Codemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). > > **Note:** This guide only applies to workflows configured with **codemagic.yaml**. If your workflow is configured with the **Flutter workflow editor** please go to [Publishing to App Store Connect using Flutter workflow editor](../publishing/publishing-to-app-store). > {{< youtube hDXfKccLMjI >}} ### Requirements Please note that 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). ### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > ### Setting up publishing to App Store Connect There are two options for setting up publishing to App Store Connect. You can either connect the Apple Developer Portal integration in the UI and reference the API key name in `codemagic.yaml`, or add the API key along with the required metadata as environment variables and reference them in your configuration file. ### Option: Using Apple Developer Portal integration#### Connect the Apple Developer Portal integration for your team/account The Apple Developer Portal integration can be enabled in the **Team integrations** section in your team settings (if you're a team admin). This allows you to conveniently use the same access credentials for automatic code signing and publishing across different apps and workflows. 1. In the list of available integrations, click the **Connect** button for **Developer Portal**. 2. In the **App Store Connect API key name**, provide a name for the key you are going to set up the integration with. This is for identifying the key in Codemagic. 3. Enter the **Issuer ID** related to your Apple Developer account. You can find it above the table of active keys on the Integrations tab of the [Users and Access](https://appstoreconnect.apple.com/access/integrations/api) page. 4. Enter the **Key ID** of the key to be used for code signing. 5. In the **API key** field, upload the private API key downloaded from App Store Connect. 6. Click **Save** to finish the setup. If you work with multiple Apple Developer teams, you can add additional keys by clicking **Add another key** right after adding the first key and repeating the steps described above. You can delete existing keys or add new ones when you click **Manage keys** next to the Developer Portal integration in personal account or team settings. #### Distribution to App Store Connect The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). To submit solely to internal testers without requiring Apple's beta review (TestFlight Internal Testing Only), add the `--custom-export-options='{"testFlightInternalTestingOnly": true}'` argument to `use-profiles` during iOS code signing as detailed [here](https://docs.codemagic.io/yaml-code-signing/signing-ios/#using-provisioning-profiles). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. workflows: ios-workflow: name: iOS Workflow integrations: app_store_connect: environment: # ... scripts: # ... publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` > > **Note:** To use different Apple Developer Portal accounts for publishing your iOS apps, set up separate workflows. > %!s() ### Option: Using environment variables#### Configuring environment variables 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter `APP_STORE_CONNECT_PRIVATE_KEY` as the **_Variable name_**. 3. Run the following command on the **App Store Connect API key** file that you downloaded earlier (in our example saved as `codemagic_api_key.p8`) to copy its content to clipboard: ```bash cat codemagic_api_key.p8 | pbcopy ``` 4. Paste into the **_Variable value_** field. 5. Enter a variable group name, e.g. **_appstore_credentials_**. Click the button to create the group. 6. Make sure the **Secret** option is selected so that the variable can be protected by encryption. 7. Click the **Add** button to add the variable. 8. Create variable `APP_STORE_CONNECT_KEY_IDENTIFIER`. The value is the **Key ID** field from **App Store Connect > Users and Access > Keys**. 9. Create variable `APP_STORE_CONNECT_ISSUER_ID`. The value is the **Issuer ID** field from **App Store Connect > Users and Access > Keys**. > > **Tip**: Store all of these variables in the same group so they can be imported to codemagic.yaml workflow at once. > Environment variables have to be added to the workflow either individually or as a group. Modify your `codemagic.yaml` file by adding the following: ```yaml workflows: ios-workflow: name: iOS Workflow environment: groups: - appstore_credentials ``` #### Distribution to App Store Connect The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). To submit solely to internal testers without requiring Apple's beta review (TestFlight Internal Testing Only), add the `--custom-export-options='{"testFlightInternalTestingOnly": true}'` argument to `use-profiles` during iOS code signing as detailed [here](https://docs.codemagic.io/yaml-code-signing/signing-ios/#using-provisioning-profiles). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml publishing: app_store_connect: # Contents of the API key saved as a secret environment variable: api_key: $APP_STORE_CONNECT_PRIVATE_KEY # Alphanumeric value that identifies the API key, # can also reference environment variable such as $APP_STORE_CONNECT_KEY_IDENTIFIER key_id: 3MD9688D9K # Alphanumeric value that identifies who created the API key, # can also reference environment variable such as $APP_STORE_CONNECT_ISSUER_ID issuer_id: 21d78e2f-b8ad-... # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` > > **Note:** To use different Apple Developer Portal accounts for publishing your iOS apps, set up separate workflows. > ### Post-processing of App Store Connect distribution (Magic Actions) > > Please note that publishing to App Store Connect through **app_specific_password** has been deprecated and post-processing actions will not be triggered unless using the new way of publishing as explained above. > Some App Store Connect actions, like `submit_to_testflight`, `beta_groups`, `cancel_previous_submissions`, `expire_build_submitted_for_review`, and uploading release notes take place asynchronously in the post-processing step after the app artifact has been successfully published to App Store Connect and the main workflow has completed running in Codemagic. This avoids using the macOS build machine while we are waiting for Apple to complete processing the build and it becomes available for further actions. Post-processing of App Store Distribution jobs, or Magic Actions in short, has a two-step timeout. If the uploaded build cannot be found in App Store Connect in 15 minutes, the step times out. This may happen if there are issues with the uploaded artifact, in which case the build does not become available in App Store Connect at all and you'll receive an email from App Store Connect. The overall timeout for post-processing is 120 minutes. If the uploaded build has not exited the processing status by then, post-processing is cancelled. You will still be able to manually submit the build to beta review, upload release notes and distribute the app to beta groups once the build becomes available in App Store Connect. Note that Codemagic does not send status updates on the post-processing step. You can check the build log for the status of post-processing or check your email for updates from App Store Connect. Post-processing does not consume any build minutes. %!s() ================================================================================ source: https://docs.codemagic.io/integrations/appdome-integration/ title: AppDome integration description: How to integrate your workflows with AppDome using codemagic.yaml last_modified: 2026-06-18 ================================================================================ # AppDome integration > How to integrate your workflows with AppDome using codemagic.yaml [Appdome](https://www.appdome.com/) is a no-code mobile app security platform used by enterprise banking, fintech, and government teams to harden Android and iOS apps post-build — injecting RASP, obfuscation, certificate pinning, root/jailbreak detection, anti-tampering, and dozens of other defences without touching source code. You upload a finished APK, AAB, or IPA; Appdome returns a hardened, signed binary along with a tamper-proof Certified Secure™ audit certificate. This guide shows how to integrate Appdome as a post-build step in Codemagic using [Appdome's official Python client library](https://github.com/Appdome/appdome-api-python). The full pipeline looks like this: ```python Build app → Install Appdome client → Fuse (harden) → Sign → Download → Publish ``` {{< spacer >}} --- ## Prerequisites | **Requirement** | **Notes** | |---|---| | Appdome account (IDEAL DEV tier) | Must have DEV-API access enabled — verify with `support@appdome.com` | | Appdome API token | Found under **Account & API** in the Appdome platform sidebar | | Fusion Set ID | A *shared* (non-playground) Fusion Set configured with your required defences | | Team ID *(optional)* | Required when working in a Team workspace — found under **Team Management** | | Python 3.6+ | Pre-installed on all Codemagic macOS and Linux instances | | Android keystore | Added via **Codemagic UI → Code signing identities → Android keystores** | | iOS distribution certificate | Added via **Codemagic UI → Code signing identities → iOS certificates** | | iOS provisioning profile | Added via **Codemagic UI → Code signing identities → iOS provisioning profiles** | {{< spacer >}} > > **What is a Fusion Set?** A Fusion Set is a saved template of all the security features you want Appdome to inject — code obfuscation, root/jailbreak detection, MitM prevention, and so on. You configure it once in the Appdome UI and reference its ID in every CI run. Lock the set after configuration to prevent accidental changes. The ID must come from a *shared* Fusion Set, not a personal playground set — the API will return an error if you provide a playground ID. > > --- ## Step 1 — Store credentials as Codemagic environment variables Create an environment variable group named `appdome_credentials` in the Codemagic UI under **Teams → Environment variable groups**. Code signing assets are handled separately by Codemagic's native signing integrations and do not belong here. | **Variable name** | **Value** | |---|---| | `APPDOME_API_TOKEN` | Your Appdome API token | | `APPDOME_FUSION_SET_ID` | The ID of your Android Fusion Set | | `APPDOME_FUSION_SET_ID_IOS` | The ID of your iOS Fusion Set | | `APPDOME_TEAM_ID` | Your Appdome Team ID (omit or leave blank for a personal account) | | `IOS_P12_PASSWORD` | Password for your iOS distribution certificate | {{< spacer >}} > **Why is `IOS_P12_PASSWORD` here and not managed by Codemagic?** Codemagic uses the certificate password internally when installing to the system keychain for Xcode signing. Appdome reads the raw `.p12` file directly and needs the password supplied explicitly. Everything else — the certificate file itself, the provisioning profile — is fetched and placed on disk by Codemagic's native `ios_signing` integration. > > --- ## Step 2 — Add signing assets via the Codemagic UI ### Option: Android #### Android keystore 1. Go to **Team settings → codemagic.yaml settings → Code signing identities → Android keystores**. 2. Upload your `.jks` or `.keystore` file and give it a **Reference name** (e.g. `production_keystore`). 3. Codemagic will automatically populate `CM_KEYSTORE_PATH`, `CM_KEYSTORE_PASSWORD`, `CM_KEY_ALIAS`, and `CM_KEY_PASSWORD` at build time when this keystore is referenced in the workflow. ### Option: iOS #### iOS certificate 1. Go to **Team settings → codemagic.yaml settings → Code signing identities → iOS certificates**. 2. Upload your distribution `.p12` file or generate/fetch one using your App Store Connect API key. 3. Give it a **Reference name** (e.g. `distribution_cert`). #### iOS provisioning profile 1. Go to **Team settings → codemagic.yaml settings → Code signing identities → iOS provisioning profiles**. 2. Upload a `.mobileprovision` file or fetch one from the Apple Developer Portal using your App Store Connect API key. 3. Give it a **Reference name** (e.g. `distribution_profile`). For apps with extensions (Share Extension, Notification Service, etc.), upload a separate profile for each target and give each its own reference name. --- ## Step 3 — create `codemagic.yaml` ### Option: Android ```yaml # ───────────────────────────────────────────────────────────────────────────── # Android: build → Appdome harden & sign → publish to Google Play # ───────────────────────────────────────────────────────────────────────────── workflows: android-appdome-release: name: Android — Appdome Release max_build_duration: 90 instance_type: mac_mini_m2 # or linux_x2 environment: groups: - appdome_credentials # APPDOME_API_TOKEN, APPDOME_FUSION_SET_ID, APPDOME_TEAM_ID android_signing: - production_keystore # reference name set in Codemagic UI # populates CM_KEYSTORE_PATH, CM_KEYSTORE_PASSWORD, # CM_KEY_ALIAS, CM_KEY_PASSWORD vars: APP_MODULE: app BUILD_FLAVOR: production APPDOME_CLIENT_VERSION: "1.5.0" # pin to a specific release tag java: 17 # required by Gradle/AGP 8.x — not an Appdome dependency scripts: # ── 1. Set version from Git tag ────────────────────────────────────────── - name: Set version from tag script: | TAG="${CM_TAG:-$(git describe --tags --abbrev=0)}" echo "VERSION_NAME=${TAG#release-}" >> "$CM_ENV" echo "VERSION_CODE=$BUILD_NUMBER" >> "$CM_ENV" # ── 2. Build the release AAB ───────────────────────────────────────────── - name: Build release AAB script: | ./gradlew ":${APP_MODULE}:bundle${BUILD_FLAVOR^}Release" \ -PversionName="$VERSION_NAME" \ -PversionCode="$VERSION_CODE" # ── 3. Install the Appdome Python client ───────────────────────────────── - name: Install Appdome client library script: | pip3 install requests --quiet git clone --depth 1 --branch "$APPDOME_CLIENT_VERSION" \ https://github.com/Appdome/appdome-api-python \ "$CM_BUILD_DIR/appdome-client" # ── 4. Appdome: fuse → sign → download ─────────────────────────────────── # # Gradle writes the AAB to a predictable path inside the module's build # directory. The hardened output is written directly to CM_BUILD_OUTPUT_DIR # so it is immediately available as a build artifact without additional # glob patterns. # # CM_KEYSTORE_PATH, CM_KEYSTORE_PASSWORD, CM_KEY_ALIAS, and CM_KEY_PASSWORD # are populated automatically by Codemagic from the android_signing block. # - name: Appdome — harden and sign script: | AAB_INPUT="$CM_BUILD_DIR/$APP_MODULE/build/outputs/bundle/${BUILD_FLAVOR}Release/app-${BUILD_FLAVOR}-release.aab" python3 "$CM_BUILD_DIR/appdome-client/appdome-api-python/appdome_api.py" \ --api_key "$APPDOME_API_TOKEN" \ --fusion_set_id "$APPDOME_FUSION_SET_ID" \ --team_id "$APPDOME_TEAM_ID" \ --app "$AAB_INPUT" \ --sign_on_appdome \ --keystore "$CM_KEYSTORE_PATH" \ --keystore_pass "$CM_KEYSTORE_PASSWORD" \ --keystore_alias "$CM_KEY_ALIAS" \ --key_pass "$CM_KEY_PASSWORD" \ --output "$CM_BUILD_OUTPUT_DIR/app-hardened.aab" \ --certificate_output "$CM_BUILD_OUTPUT_DIR/certified_secure.pdf" artifacts: - $CM_BUILD_OUTPUT_DIR/app-hardened.aab - $CM_BUILD_OUTPUT_DIR/certified_secure.pdf publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true email: recipients: - mobile-security@yourbank.com notify: success: true failure: true ``` ### Option: iOS ```yaml # ───────────────────────────────────────────────────────────────────────────── # iOS: build → Appdome harden & sign → publish to TestFlight # ───────────────────────────────────────────────────────────────────────────── workflows: ios-appdome-release: name: iOS — Appdome Release max_build_duration: 120 instance_type: mac_mini_m2 environment: groups: - appdome_credentials # APPDOME_API_TOKEN, APPDOME_FUSION_SET_ID_IOS, # APPDOME_TEAM_ID, IOS_P12_PASSWORD ios_signing: provisioning_profiles: - profile: distribution_profile # reference name set in Codemagic UI environment_variable: PROVISIONING_PROFILE_PATH certificates: - certificate: distribution_cert # reference name set in Codemagic UI environment_variable: CERTIFICATE_PATH vars: XCODE_WORKSPACE: YourApp.xcworkspace XCODE_SCHEME: YourApp APPDOME_CLIENT_VERSION: "1.5.0" xcode: latest cocoapods: default scripts: # ── 1. Set version from tag ────────────────────────────────────────────── - name: Set version from tag script: | TAG="${CM_TAG:-$(git describe --tags --abbrev=0)}" agvtool new-marketing-version "${TAG#release-}" agvtool new-version -all "$BUILD_NUMBER" # ── 2. Install CocoaPods dependencies ──────────────────────────────────── - name: Install CocoaPods script: pod install # ── 3. Build and export unsigned IPA ───────────────────────────────────── # # Appdome handles re-signing, so the Xcode archive is built without # code signing. The ios_signing block above places the certificate and # profile on disk solely for the Appdome step — they are not used by # Xcode here, and xcode-project use-profiles is not needed. # - name: Build unsigned IPA script: | xcodebuild archive \ -workspace "$XCODE_WORKSPACE" \ -scheme "$XCODE_SCHEME" \ -configuration Release \ -archivePath "$CM_BUILD_DIR/build/YourApp.xcarchive" \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO \ DEVELOPMENT_TEAM="" \ -destination "generic/platform=iOS" xcodebuild -exportArchive \ -archivePath "$CM_BUILD_DIR/build/YourApp.xcarchive" \ -exportOptionsPlist ios/ExportOptions.plist \ -exportPath "$CM_BUILD_DIR/build/output/" # ── 4. Install the Appdome Python client ───────────────────────────────── - name: Install Appdome client library script: | pip3 install requests --quiet git clone --depth 1 --branch "$APPDOME_CLIENT_VERSION" \ https://github.com/Appdome/appdome-api-python \ "$CM_BUILD_DIR/appdome-client" # ── 5. Appdome: fuse → sign → download ─────────────────────────────────── # # xcodebuild -exportArchive writes the IPA to the exportPath specified # above. The hardened output is written directly to CM_BUILD_OUTPUT_DIR. # # CERTIFICATE_PATH and PROVISIONING_PROFILE_PATH are populated by # Codemagic from the ios_signing block. IOS_P12_PASSWORD is the only # credential stored manually, as Codemagic does not expose the certificate # password for use outside its own keychain. # - name: Appdome — harden and sign script: | IPA_INPUT="$CM_BUILD_DIR/build/output/YourApp.ipa" python3 "$CM_BUILD_DIR/appdome-client/appdome-api-python/appdome_api.py" \ --api_key "$APPDOME_API_TOKEN" \ --fusion_set_id "$APPDOME_FUSION_SET_ID_IOS" \ --team_id "$APPDOME_TEAM_ID" \ --app "$IPA_INPUT" \ --sign_on_appdome \ --keystore "$CERTIFICATE_PATH" \ --keystore_pass "$IOS_P12_PASSWORD" \ --provisioning_profiles "$PROVISIONING_PROFILE_PATH" \ --output "$CM_BUILD_OUTPUT_DIR/app-hardened.ipa" \ --certificate_output "$CM_BUILD_OUTPUT_DIR/certified_secure.pdf" artifacts: - $CM_BUILD_OUTPUT_DIR/app-hardened.ipa - $CM_BUILD_OUTPUT_DIR/certified_secure.pdf publishing: app_store_connect: api_key: $APP_STORE_CONNECT_PRIVATE_KEY key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER issuer_id: $APP_STORE_CONNECT_ISSUER_ID submit_to_testflight: true email: recipients: - mobile-security@yourbank.com ``` --- ## Post-publish notifications ### Slack Codemagic has a native Slack integration that automatically posts build status and artifact download links (valid 24 hours by default) to a channel when a build completes. Connect your workspace once under **Team integrations → Slack**, then add the channel to each workflow's `publishing` block: ```yaml publishing: google_play: # or app_store_connect for iOS # ... store config slack: channel: '#mobile-security' notify_on_build_start: true notify: success: true failure: true ``` The hardened binary and the Certified Secure™ PDF will appear as download links in the Slack message automatically, because they are declared in the workflow's `artifacts:` section. ### Custom webhooks and other destinations For destinations other than Slack, or when you need a fully custom message format, use `$CM_ARTIFACT_LINKS` in a post-publish script. It is a JSON array available only after publishing completes, containing the name, type, download URL, MD5, version name, and bundle ID for every published artifact. ```yaml publishing: scripts: - name: Notify security team via webhook script: | ARTIFACT_TYPE=".aab" # or ".ipa" for iOS ARTIFACT_URL=$(echo $CM_ARTIFACT_LINKS | jq -r \ '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .url') ARTIFACT_NAME=$(echo $CM_ARTIFACT_LINKS | jq -r \ '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .name') curl -s -X POST "$SECURITY_WEBHOOK_URL" \ -H "Content-Type: application/json" \ -d "{ \"text\": \"Hardened build ready — v${CM_TAG}\", \"attachments\": [{ \"text\": \"<${ARTIFACT_URL}|${ARTIFACT_NAME}>\", \"color\": \"good\" }] }" ``` {{< spacer >}} --- ## Signing modes The Python client supports three signing modes. For most Codemagic workflows, `--sign_on_appdome` is the correct choice. | **Flag** | **Mode** | **How it works** | |---|---|---| | `--sign_on_appdome` | Automatic | Your keystore is managed by Codemagic (`CM_KEYSTORE_PATH`). Credentials are passed to Appdome, which returns a signed, ready-to-install binary. | | `--private_sign` | Private signing | Your signing key lives in an on-premises HSM or internal signing service and must never be transmitted to any external platform — including Codemagic. Appdome returns an unsigned hardened binary for you to sign within your own infrastructure. | | `--auto_dev_sign` | Auto-DEV private | Same key-custody intent as private signing, but Appdome wraps a signing script in the output package which can be run locally against your key. | If your workflow uses the `android_signing` block to store the keystore in Codemagic, use `--sign_on_appdome`. Combining `--private_sign` with `CM_KEYSTORE_PATH` adds no security benefit — the key is already held by a third party. {{< spacer >}} --- ## Advanced options ### Apps with multiple targets (iOS) Apps that include extensions — Share Extension, Notification Service Extension, and so on — require a separate provisioning profile for each target. Upload each profile in the Codemagic UI with its own reference name, assign a distinct environment variable to each, and list all paths on the `--provisioning_profiles` flag: ```yaml ios_signing: provisioning_profiles: - profile: main_app_profile environment_variable: PROFILE_MAIN - profile: share_ext_profile environment_variable: PROFILE_SHARE_EXT - profile: notification_ext_profile environment_variable: PROFILE_NOTIFICATION_EXT certificates: - certificate: distribution_cert environment_variable: CERTIFICATE_PATH # .... scripts: # .... - name: Appdome — harden and sign script: | python3 "$CM_BUILD_DIR/appdome-client/appdome-api-python/appdome_api.py" \ --provisioning_profiles "$PROFILE_MAIN" \ "$PROFILE_SHARE_EXT" \ "$PROFILE_NOTIFICATION_EXT" \ # ... other flags ``` ### Build overrides Override individual Fusion Set parameters on a per-build basis — without editing the saved set — by passing a JSON file to `--build_overrides`. Useful for stamping the build version, environment name, or backend URL at CI time: ```json // overrides/build_overrides.json { "plugin_good_app_version": "2.4.1", "user_agent_value": "BankApp/2.4.1 (prod)" } ``` ```yaml - name: Appdome — harden with overrides script: | AAB_INPUT="$CM_BUILD_DIR/$APP_MODULE/build/outputs/bundle/${BUILD_FLAVOR}Release/app-${BUILD_FLAVOR}-release.aab" python3 "$CM_BUILD_DIR/appdome-client/appdome-api-python/appdome_api.py" \ --api_key "$APPDOME_API_TOKEN" \ --fusion_set_id "$APPDOME_FUSION_SET_ID" \ --team_id "$APPDOME_TEAM_ID" \ --app "$AAB_INPUT" \ --sign_on_appdome \ --keystore "$CM_KEYSTORE_PATH" \ --keystore_pass "$CM_KEYSTORE_PASSWORD" \ --keystore_alias "$CM_KEY_ALIAS" \ --key_pass "$CM_KEY_PASSWORD" \ --build_overrides overrides/build_overrides.json \ --output "$CM_BUILD_OUTPUT_DIR/app-hardened.aab" \ --certificate_output "$CM_BUILD_OUTPUT_DIR/certified_secure.pdf" ``` ### Dynamic certificate pinning When pinned certificates rotate independently of the Fusion Set, bundle them into a ZIP and pass it via `--cert_pinning_zip`. The ZIP must contain a `pinning.json` mapping file alongside the certificate files: ```json // certs/pinning.json { "api.yourbank.com": "api_cert.pem", "auth.yourbank.com": "auth_cert.crt" } ``` ```yaml - name: Assemble the bundle — in a CI step or as part of your certificate rotation process script: zip -j certs/pinning_bundle.zip \ certs/pinning.json \ certs/api_cert.pem \ certs/auth_cert.crt - name: Appdome — harden with dynamic cert pinning script: | AAB_INPUT="$CM_BUILD_DIR/$APP_MODULE/build/outputs/bundle/${BUILD_FLAVOR}Release/app-${BUILD_FLAVOR}-release.aab" python3 "$CM_BUILD_DIR/appdome-client/appdome-api-python/appdome_api.py" \ --api_key "$APPDOME_API_TOKEN" \ --fusion_set_id "$APPDOME_FUSION_SET_ID" \ --team_id "$APPDOME_TEAM_ID" \ --app "$AAB_INPUT" \ --sign_on_appdome \ --keystore "$CM_KEYSTORE_PATH" \ --keystore_pass "$CM_KEYSTORE_PASSWORD" \ --keystore_alias "$CM_KEY_ALIAS" \ --key_pass "$CM_KEY_PASSWORD" \ --cert_pinning_zip certs/pinning_bundle.zip \ --output "$CM_BUILD_OUTPUT_DIR/app-hardened.aab" \ --certificate_output "$CM_BUILD_OUTPUT_DIR/certified_secure.pdf" ``` ### Deobfuscation mapping for crash reporting If your Fusion Set includes code obfuscation, download the mapping bundle and forward it to your crash reporting provider. The Python client handles both in one command: ```yaml # Firebase Crashlytics - name: Appdome — harden, sign, and upload mapping to Firebase script: | AAB_INPUT="$CM_BUILD_DIR/$APP_MODULE/build/outputs/bundle/${BUILD_FLAVOR}Release/app-${BUILD_FLAVOR}-release.aab" python3 "$CM_BUILD_DIR/appdome-client/appdome-api-python/appdome_api.py" \ --api_key "$APPDOME_API_TOKEN" \ --fusion_set_id "$APPDOME_FUSION_SET_ID" \ --team_id "$APPDOME_TEAM_ID" \ --app "$AAB_INPUT" \ --sign_on_appdome \ --keystore "$CM_KEYSTORE_PATH" \ --keystore_pass "$CM_KEYSTORE_PASSWORD" \ --keystore_alias "$CM_KEY_ALIAS" \ --key_pass "$CM_KEY_PASSWORD" \ --output "$CM_BUILD_OUTPUT_DIR/app-hardened.aab" \ --certificate_output "$CM_BUILD_OUTPUT_DIR/certified_secure.pdf" \ --deobfuscation_script_output "$CM_BUILD_OUTPUT_DIR/deobfuscation.zip" \ --firebase_app_id "$FIREBASE_APP_ID" ``` Replace `--firebase_app_id "$FIREBASE_APP_ID"` with `--datadog_api_key "$DATADOG_API_KEY"` to forward the mapping to Datadog instead. --- ## Pinning the client version Always pin `APPDOME_CLIENT_VERSION` to a specific release tag rather than pulling from `main`. This ensures deterministic builds and prevents unexpected behaviour if Appdome ships a breaking change. ```yaml vars: APPDOME_CLIENT_VERSION: "1.5.0" # check github.com/Appdome/appdome-api-python/releases ``` To upgrade, change the version string, test in a feature branch, then merge to your release workflow once verified. --- ## Troubleshooting | **Symptom** | **Likely cause** | **Fix** | |---|---|---| | `401 Unauthorized` | Invalid or expired API token | Re-copy the token from **Account & API** in the Appdome platform | | `Invalid fusion set ID` | Using a playground (non-shared) Fusion Set | In the Appdome UI, click **Copy** on any playground set to create a shared set, then use that ID | | Fuse task ends in an `error` state | App framework incompatibility or unsupported entitlement | Check the error message printed by the client; contact `support@appdome.com` with the task ID | | Sign task fails with a certificate error | Wrong alias, bad password, or profile/bundle ID mismatch | Verify that the provisioning profile's bundle ID matches the app and that `IOS_P12_PASSWORD` is correct | | `CM_KEYSTORE_PATH` is empty | Keystore reference name in `android_signing` doesn't match the Codemagic UI | Confirm the reference name under **Code signing identities → Android keystores** matches exactly | | `CERTIFICATE_PATH` or `PROVISIONING_PROFILE_PATH` is empty | Profile or certificate reference name in `ios_signing` doesn't match the Codemagic UI | Confirm the reference names under **Code signing identities** match exactly | | AAB not found at expected path | Module name or flavor differs from the `vars` values | Check the actual Gradle output path in the build log and adjust `APP_MODULE` and `BUILD_FLAVOR` accordingly | | `ModuleNotFoundError: No module named 'requests'` | `pip3 install requests` step was skipped or failed | Confirm the install step runs before the Appdome step and that `pip3` resolves to Python 3 | | Git clone fails at build time | Outbound access to `github.com` is restricted | Contact your Codemagic organisation owner to review network settings, or vendor the library into your own repository | --- ## Further reading - [Appdome Python client library — GitHub](https://github.com/Appdome/appdome-api-python) - [Appdome DEV-API documentation](https://apis.appdome.com/docs/introduction) - [Appdome Fusion Sets — getting started](https://apis.appdome.com/docs/getting-started) - [Codemagic — Built-in environment variables](https://docs.codemagic.io/yaml-basic-configuration/environment-variables/) - [Codemagic — Signing iOS apps](https://docs.codemagic.io/yaml-code-signing/signing-ios/) - [Codemagic — Signing Android apps](https://docs.codemagic.io/yaml-code-signing/signing-android/) - [Codemagic — Environment variable groups](https://docs.codemagic.io/yaml-basic-configuration/configuring-environment-variables/) - [Codemagic — Publishing to Google Play](https://docs.codemagic.io/yaml-publishing/google-play/) - [Codemagic — Publishing to App Store Connect](https://docs.codemagic.io/yaml-publishing/app-store-connect/) ================================================================================ source: https://docs.codemagic.io/integrations/appetize-integration/ title: Appetize integration description: How to integrate your workflows with Appetize using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Appetize integration > How to integrate your workflows with Appetize using codemagic.yaml [**Appetize**](https://appetize.io/) enables you to run native iOS and Android mobile apps directly in your browser. No downloads, plugins, or extra permissions needed. A sample project that shows how to configure Appetize integration is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/appetize_integration_demo_project). ## Configure Appetize access Before getting started you will need to generate an **Appetize API token** and a **public key** for your app. #### Get Appetize token All users with admin or developer roles may request an **API token** after logging in to your Appetize [account](https://appetize.io/account) page. After getting your **API_TOKEN** you need to add it to your [environment variables](/variables/environment-variable-groups/#storing-sensitive-valuesfiles) in a group named **appetize** for example. #### Get the public key for your app To get a **public key** for your app, **you first have to upload your app manually** at least once to [Appetize](https://appetize.io/upload). After that, you can get the app **publicKey** and add it as an environment variable. #### Configure environment variables 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `APPETIZE_API_TOKEN`. 3. Enter the desired variable value as **_Variable value_**. 4. Enter the variable group name, e.g. **_appetize_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to add the `APPETIZE_APP_PUBLIC_KEY`. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - appetize_credentials ``` ## Uploading to Appetize After you have uploaded your app to Appetize manually once and configured the app public key, you can configure automatic publishing in your `codemagic.yaml`. ### Option: Android Add the following script to your `publishing` section: ```yaml publishing: scripts: - name: Publish APK to Appetize script: | apkPath="/build/app/outputs/flutter-apk/app-release.apk" echo $(curl --location --request POST 'https://'$API_TOKEN'@api.appetize.io/v1/apps/'$APP_PUBLIC_KEY'' --form 'file=@"'$apkPath'"') ``` Don't forget to change the value of the `apkPath` to your actual apk path. ### Option: iOS For iOS, you need to upload a `.zip` or `.tar.gz` file containing your compressed `.app` bundle. The whole process will consist of: - building the app - creating a `.zip` archive - publishing to Appetize ```yaml scripts: - name: Build unsigned .app script: | xcodebuild -workspace "ios/Runner.xcworkspace" \ -scheme "$XCODE_SCHEME" \ -configuration "Debug" \ -sdk iphonesimulator \ -derivedDataPath ios/output # If you are building a project instead of a workspace: # xcodebuild -project "ios/Runner.xcodeproj" \ # -scheme "$XCODE_SCHEME" \ # -configuration "Debug" \ # -sdk iphonesimulator \ # -derivedDataPath ios/output - name: Create a .zip archive script: | cd ios/output/Build/Products/Debug-iphonesimulator zip -r ios_app.zip $XCODE_SCHEME.app artifacts: - ios/output/Build/Products/Debug-iphonesimulator/*.zip publishing: scripts: - name: Publish App to Appetize script: | zipPath="ios/output/Build/Products/Debug-iphonesimulator/ios_app.zip" echo $(curl --location --request POST "https://$API_TOKEN@api.appetize.io/v1/apps/$APP_PUBLIC_KEY" --form "file=@$zipPath") ``` Don't forget to change the value of the `zipPath` to your actual zip path. ================================================================================ source: https://docs.codemagic.io/billing/billing/ title: Billing description: How to enable billing and manage your payments last_modified: 2026-03-17 ================================================================================ # Billing > How to enable billing and manage your payments In order to use the paid features of Codemagic (see our pricing [here](https://codemagic.io/pricing/)), you must enable billing. Note that: * Build time usage is counted separately for your personal account and each team. * Billing is managed separately for your personal account and each [team](../teams/teams). ## Enabling billing Billing can be enabled for your personal account or team on the **Billing** page that is accessible from the left navigation bar. On clicking **Enable billing**, you will be asked to enter credit card information or offered the option to select an existing credit card if you have had billing enabled previously. To finish, click **Confirm and enable billing**. When billing is enabled, you will be charged monthly based on usage. ## Managing billing and updating billing details To manage billing for the currently selected team or personal account, navigate to the **Billing** page. When billing is enabled, you will see the current usage, the due amount and the next payment date. This is also where you can download the invoices for previous billing periods. ### Updating billing details Click on **Update billing details** to change the billing information or add additional details, such as company name, billing email, address and tax ID. Tax ID is only available for team accounts and not personal teams. ### Changing card To change the card used for payments, click **Edit** in the credit card section under the billing details. You can then click **New card** to register a new card or select a different card from already registered cards. ### Disabling billing To disable billing, click **Disable billing** in the Billing details section. On disabling billing, you will be immediately charged for the used paid features. Note that you may only disable billing if there are no unpaid invoices. In case you have unpaid invoices, please verify or update your card information. Then navigate to Billing history and find any invoice that is not in paid status. Finally, open up each unpaid invoice and click **Pay invoice** to retry the payment. ## Billing per build minute For pay-as-you-go team and user plans, each build minute is billed at the rate on our [pricing page](https://codemagic.io/pricing/) based on the build [machine type](../specs/machine-type) used for the build. Builds that time out or fail because of a Codemagic service error will not count towards billing usage. Builds that fail for any other reason will count towards billing usage. ## Overdue and failed invoice payments Invoices that have not been paid on the due date are shown as "Overdue" or "Failed" on the billing page. This usually happens when there are problems with charging the card, of which team admins or account owners are notified by email. Codemagic will then attempt to retry the payment in 3, 5 or 7 days. As soon as there is a failed invoice payment, your subscription will be put on hold and running builds will be disabled. In order to continue building, all invoices should be paid. Team admins or account owners can manually retry the payment by clicking the **Pay invoice** button on the overdue/pending invoice in **Billing history**. This will redirect you to the Stripe-based payment website where you are required to add your credit card details and click **Make Payment**. > > **Pending invoices**: Some invoices may remain pending due to issues with the payment. This can happen when international payments on your card are disabled or when automatic payments are not allowed in which case the first payment has to be made manually to comply with the new RBI regulations for Indian cardholders. Team admins or account owners can then manually retry the payment as described above. > Note that overdue invoices should be paid before the subscription can be disabled. Please refer to the [Disable billing](/billing/billing/#disabling-billing) section for further info. ## Tax information Codemagic is registered to collect taxes on transactions with customers in the following locations. * **European Union** Codemagic (Nevercode Ltd) is registered for the EU OSS VAT under `EU233019224`. * **United Kingdom** Codemagic (Nevercode Ltd) is registered for the GB VAT under `GB347624190`. * **India** Codemagic (Nevercode Ltd) is registered for Indian GST under GSTIN `9925GBR29027OS2`. * **Philippines** Codemagic (Nevercode Ltd) is registered for Philippine VAT as a non-resident digital services provider under TIN `691133439`. The following documents are available for download: * [Tax residency certificate](https://drive.google.com/file/d/1w1miL-CL6h7soE1mHIGVY79iuBA9AIca/view?usp=drive_link) * [W-8BEN-E certificate](https://drive.google.com/file/d/1ZqDXcorGbkZ1jPbbaoAXjSFSLzktGHY1/view?usp=sharing) * [Form GST REG-06](https://drive.google.com/file/d/1ZYLvXImNuZdc7EOibkPLFdPo-l6k332y/view) * [Philippines Certificate of Registration (COR)](https://drive.google.com/file/d/1TqOAzjDlwuvyizLf4VMzr9OmZsEc5Qxk/view?usp=drive_link) ================================================================================ source: https://docs.codemagic.io/yaml-distributing/build-dashboards/ title: Build dashboards description: Use public links to distribute builds and artifacts in codemagic.yaml last_modified: 2026-04-01 ================================================================================ # Build dashboards > Use public links to distribute builds and artifacts in codemagic.yaml Build dashboards make it possible for teams to share the list of team's builds, release notes (if passed) and build artifacts with people outside Codemagic using a public link (build logs will not be exposed). This is a convenient option for distributing builds to testers or sharing build artifacts with stakeholders. The artifact download links in build dashboards are valid for 24 hours. Download links are recreated on each dashboard refresh. > > **Note:** The build dashboards feature is available for teams only. It is not possible to create build dashboards for apps on personal accounts. > ## Enabling build dashboards To use build dashboards, team admins will have to enable the feature in team settings. In team settings, expand the **Build dashboards** section and click **Enable sharing**. This will allow any team member to create dashboards and generate public links to share them. Build dashboards can be disabled anytime by clicking **Disable sharing**. ## Creating and sharing a build dashboard 1. Open the **Builds** page via the left navigation bar. 2. Click the **Share dashboard** button at the top right of the page and use the **application**, **workflow**, **build status**, **labels**, **branch** and **tag** filters to configure a build dashboard. 3. Then click **Create dashboard** at the bottom of the right configuration sidebar to generate a public link. A generated link will appear, and you can copy the link to the clipboard. The generated link will be also saved to the **Build dashboards** section in team settings. > > **Note:** **Share dashboard** will be available only when the currently selected team has build dashboards enabled. > > > **Note:** Please note that anyone with the public link can access the build dashboard and download build artifacts. > ## Managing links All generated links to build dashboards are listed in the **Build dashboards** section in team settings. Links can be revoked by deleting them or when a team admin disables sharing by clicking **Disable sharing**. When sharing is re-enabled, the available links become active again. ================================================================================ source: https://docs.codemagic.io/knowledge-codemagic/machine-type/ title: Build machine type description: How to configure build machine type last_modified: 2025-12-05 ================================================================================ # Build machine type > How to configure build machine type ## Configuring build machine types To switch between build machines, **instance_type** needs to be configured when working with **codemagic.yaml**: ``` workflows: default-workflow: name: Default Workflow instance_type: mac_mini_m2 ``` > > If builds are triggered through Codemagic REST API and **instance_type** parameter is specified in the cURL request, it will override **instance_type** value in **codemagic.yaml** > Keywords for instance types can be found [here](https://docs.codemagic.io/yaml-basic-configuration/yaml-getting-started/#instance-type). For Flutter projects configured via the Flutter workflow editor, the build machine type can be selected in Workflow settings > Change instance. The following build machine types are provided by Codemagic: 1. macOS with Apple M2, M4 and Studio M4 Max 2. Linux (x64 and arm64) 3. Windows > > Contact us [here](https://codemagic.io/pricing/#enterprise) to have access to macOS with Apple M4, M4 Max and Linux with arm64. > For more information about the machine specifications, please check [this page](https://docs.codemagic.io/specs/versions-macos/). ================================================================================ source: https://docs.codemagic.io/flutter-configuration/flutter-projects/ title: Building Flutter projects description: How to configure Flutter app builds using the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # Building Flutter projects > How to configure Flutter app builds using the Flutter workflow editor With Codemagic, you can build and test Flutter apps for Android, iOS, web, macOS and Linux as well as [test widgets](../testing/testing-widgets). It is also possible to set up a [workflow](../flutter/creating-workflows) that runs tests only. > > **Tip:** If you're interested in building Flutter/Dart packages and publishing them to [pub.dev](https://pub.dev/), you can do so with [`codemagic.yaml`](../getting-started/yaml), see an example [here](../yaml-distributing/pub.dev). > ## Selecting build platforms and build machines At the beginning of the workflow, first select the platforms to build and then specify a build machine type to run the build on. While Android, iOS and web builds can be run in the same workflow, macOS and Linux platforms are each built in a separate workflow and on different build instances. Note that the availability of build machine instances depends on the selected build platforms and whether you have billing enabled or not. - iOS and macOS builds can be run on macOS build machines - Android and Web builds can be run on macOS, Linux or Windows build machines - Linux builds can be run on Linux build machines - Windows builds can be run on Windows build machines - a Run tests only workflow can be run on macOS or Linux build machines ## Building Android apps In your app settings, select **Android** under **Build for platforms** and an available build machine type. Then scroll down to the **Build** section to specify the **Flutter** version, select the build **Mode** (**Debug**, **Release** or **Profile**) or add additional build arguments, e.g. for [build versioning](../building/build-versioning) or verbose logging. Make sure to also select the **Android build format** to determine which build artifacts to generate. When you're building for release, you will need to build the app in Release mode and set up [code signing](../code-signing/android-code-signing/). ### Building Android app bundles You can build your app in [Android App Bundle](https://developer.android.com/guide/app-bundle) (`.aab`) format for publishing to Google Play. When you upload your app in `.aab` format, app .apk(s) will be dynamically created and optimized for the user's device configuration when the app is installed from Google Play Store. In order to upload your Android App Bundle to Google Play, you will need to: 1. Build the app in **Release** mode. 2. Set up [Android code signing](../code-signing/android-code-signing/) in Codemagic to sign the app bundle. 3. Set up [publishing to Google Play](../publishing/publishing-to-google-play/) in Codemagic to upload your app bundle to one of the Google Play tracks. 4. [Enroll your app into app signing by Google Play](https://support.google.com/googleplay/android-developer/answer/7384423) to have Google sign the .apk(s) that are generated from the app bundle during installation. When you enroll an app into app signing by Google Play, Google will manage your app's signing key for you and use it to sign the .apk for distribution. Note that the app must be signed with the same key throughout its lifecycle, so if the app has already been uploaded to Google Play, make sure to export and upload your original key to Google Play for app signing. It is then recommended to create a new key ("upload key") for signing your app updates and uploading them to Google Play. ## Building iOS apps > > **Tip:** If you are new to building Flutter apps for iOS, you can start by working through the beginner friendly, [step by step tutorial we have that shows you how to build your first Flutter app for iOS](https://labs.codemagic.io/your-first-flutter-app-to-appstore?utm_source=codemagic&utm_medium=docs&utm_campaign=flutter-projects&utm_id=codelab). > In your app settings, select **iOS** under **Build for platforms** and an available build machine type. Then scroll down to the **Build** section to specify the **Flutter**, **Xcode** and **Cocoapods** versions, select the build **Mode** (**Debug**, **Release** or **Profile**) or add additional build arguments, e.g. for [build versioning](../building/build-versioning) or verbose logging. When you're building for release, you will need to build the app in Release mode and set up [code signing](../code-signing/ios-code-signing/). > > **Using `flutter build ipa`** > > The `flutter build ipa` command is available as of Flutter version 1.24.0-6.0 and is the recommended option to build an .ipa archive. To use this build command, > enable code signing. > ## Building web apps Codemagic can detect your Flutter web project if it contains a `web` folder. Then scroll down to the **Build** section to specify the **Flutter** version, select the build **Mode** (**Debug**, **Release** or **Profile**) or add additional build arguments, e.g. for [build versioning](../building/build-versioning) or verbose logging. At the end of a successful build, Codemagic outputs a `.zip` file of the contents of `$CM_BUILD_DIR/build` and exports this as an artifact. You can either download it or set up publishing to [Codemagic Static Pages](../publishing/publishing-to-codemagic-static-pages/). You can also use custom scripts to publish to third-party hosting sites. ## Building macOS apps Codemagic can detect your Flutter macOS project if it contains a `macos` folder for the macOS application. In your app settings, select **macOS** under **Build for platforms** and an available build machine type. Then scroll down to the **Build** section to specify the **Flutter**, **Xcode** and **CocoaPods** version, select the build **Mode** (**Debug**, **Release** or **Profile**) or add additional build arguments, e.g. for [build versioning](../building/build-versioning) or verbose logging. At the end of a successful build, Codemagic outputs a downloadable `.zip` file containing an `.app` archive. If you build for release to the App Store, you need to also set up [code signing](../code-signing/macos-code-signing/) to receive a `.pkg` file. ## Building Linux apps Codemagic can detect your Flutter Linux project if it contains a `linux` folder for the Linux application. In your app settings, select **Linux** under **Build for platforms** and an available build machine type. Then scroll down to the **Build** section to specify the **Flutter** version, select the build **Mode** (**Debug**, **Release** or **Profile**) or add additional build arguments, e.g. for [build versioning](../building/build-versioning) or verbose logging. At the end of a successful build, Codemagic outputs a downloadable `.zip` file. ### Building snap packages Snaps are packaged apps that can be published to and installed from the [Snapcraft Snap Store](https://snapcraft.io/store). Building a snap package requires having a `snapcraft.yaml` configuration file in the root of the repository, read more about how to [create a `snapcraft.yaml` file for a Flutter app](https://snapcraft.io/docs/flutter-applications). To build a snap package, select the **Build Snap package** checkbox in the **Build** section of your Linux workflow. When building a snap, the build configuration comes from the `snapcraft.yaml` file and the Flutter version, build mode and build arguments selected in Codemagic have no effect. To publish the snap to the Snap Store, set up [publishing to the Snap Store](../flutter-publishing/snap-store). Additionally, you may want to install the generated `.snap` package onto your machine. The package will not be code signed unless you publish it to Snapcraft. You would need to use the `--dangerous` flag to install the package without code signing: snap install your-package.snap --dangerous ## Building Windows apps Codemagic can detect your Flutter Windows project if it contains a `windows` folder for the Windows application. In your app settings, select **Windows** under **Build for platforms** and an available build machine type. Then scroll down to the **Build** section to specify the **Flutter** version, select the build **Mode** (**Debug**, **Release** or **Profile**) or add additional build arguments, e.g. for verbose logging. At the end of a successful build, Codemagic outputs a downloadable `.zip` file, which contains a folder with the Windows executable. ### Building MSIX packages MSIX is a Windows app package format that provides a modern packaging experience to all Windows apps and can be published to the [Microsoft Store](https://www.microsoft.com/en-us/store/apps). To build a MSIX package, select the **Create a Windows MSIX package** checkbox in the **Build** section of your Windows workflow. Codemagic uses the [Flutter msix package](https://pub.dev/packages/msix) for packaging the application. Note that when packaging the application for release to Microsoft Store and publishing through Codemagic, you will be asked to provide the necessary `msix` configuration fields (`publisher_display_name`, `identity_name`, `msix_version`, `publisher`) under publishing settings. However, in order to configure any other package attributes, install the package to your project and add a [msix_config](https://pub.dev/packages/msix#gear-configuration-optional) to your `pubspec.yaml`. The aforementioned attributes do not have to be separately configured in the `pubspec.yaml`. > > To use a specific [Flutter msix package](https://pub.dev/packages/msix) version, make sure to add it as a dev dependency. The newest version will be installed during build time if the package is added as a regular dependency. > ## Running tests only In some cases, you may want to run only tests and not build the entire project, e.g. when you're triggering a build on pull request update. To do so, [enable testing](../testing/running-automated-tests), and then in **App settings > Build > Build for platforms**, select **Run tests only**. Codemagic will then build the workflow until the testing step and skip building the app. If tests fail, the status of the build will be “failed” and you'll receive an email about failing tests. If you have publishing to Slack configured, you'll receive notifications on build status updates. ## Starting builds Builds can be started manually from Codemagic or automatically in response to events in the repository, see more about [automatic build triggering](./automatic-build-triggering) here. You can start builds manually by clicking **Start new build** in app settings or build overview. On clicking the button, the **Specify build configuration** popup is displayed where you can select the branch and the [workflow](./creating-workflows) to build. For information about using API calls to trigger builds, look [here](../rest-api/overview/). ## Multiple Flutter projects in one repository Codemagic supports monorepos and can detect multiple Flutter projects in a repository or projects not in the repository root provided that each project has its `pubspec.yaml` file with `flutter` dependency. Initially, the only project path for every application is `.` — the root of the repository. The repository is scanned for Flutter projects during the first build, and if multiple projects are found, the first build is run for the project with the highest number of platforms available (presence of `android`, `ios` etc. directories). After the first build, you can select the project for building in **App settings > Build > Project path** dropdown. If you have changed the location of the project in the repository, renamed its parent directory or added new projects, you may have to rescan project paths by clicking the icon next to the **Project path** dropdown field. Then select the branch you want to search for projects and click **Rescan**, which will update the project paths for the chosen branch. > > Rescanning is not available for repositories added from self-hosted and repos added via SSH. Instead, project paths are scanned on each new build and are updated on change. > ## Setting the Flutter version When building a Flutter application with Codemagic, you can customize your build environment by configuring various settings. One such setting is the option to choose the Flutter version or channel for the build process. Codemagic provides several options: `channel Stable`, `channel Beta`, `channel Master`, or a specific version. Setting the Flutter version in workflow editor is possible in the build section of your workflow editor. Alternatively, you can leverage [Flutter Version Management (FVM)](https://fvm.app/documentation/getting-started) by selecting the `from FVM configuration` option. This automatically sets the Flutter version from your project's `fvm_config.json` file, located at the root of your project in the `.fvm` directory. If this file does not exist, the build will fail. Moreover, when using FVM, Codemagic allows you to set the specific FVM flavor in the UI to provide all the needed flexibility when managing the Flutter version. ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/codemagic-sample-projects/ title: Codemagic sample projects description: Sample projects using codemagic.yaml last_modified: 2025-06-30 ================================================================================ # Codemagic sample projects > Sample projects using codemagic.yaml The [codemagic-sample-projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects) repository on the Codemagic GitHub page contains a collection of sample projects which show how to configure your workflows using the **codemagic.yaml** configuration file. You can use the **codemagic.yaml** from these projects as a template for your workflow configuration. For further information on how to configure the **codemagic.yaml** for your projects, please refer to our [getting started guide](https://docs.codemagic.io/getting-started/yaml/). ### Flutter Sample Projects - [Android and iOS](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter/flutter-android-and-ios-yaml-demo-project) - [Integration tests](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter/flutter-integration-tests-demo-project) - [Flavors](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter/flutter-flavors-demo-project) - [macOS](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter/flutter-macos-demo-project) - [Windows](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter/flutter-windows-demo-project) ### iOS (Native) Samples - [iOS sample project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-native-quick-start) - [Automatic code signing](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-automatic-code-signing-demo-project) - [Manual code signing](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-manual-code-signing-demo-project) - [White label single scheme](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-white-label-single-scheme-demo-project) - [Automatic screenshots with Fastlane](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-fastlane-screenshots-demo-project) - [Codemagic Magic Actions](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-magic-actions-demo-project) - post-processing of App Store Distribution jobs - [SonarCloud](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-sonarcloud-demo-project) - [XCRemoteCache](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-xcremotecache-demo-project) ### Android (Native) Samples - [Android sample project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/android/android-native-quick-start) ### React Native Samples - [React Native Android and iOS](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/react-native/react-native-demo-project) - [React Native using Expo without ejecting](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/react-native/expo-react-native-not-ejected) - [iOS Simulator](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/react-native/react-native-ios-simulator-build) ### Unity - [Unity Android, iOS, Windows and macOS sample](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/unity/unity-demo-project) - [Steam Publishing sample](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/unity/unity-deploy-steam) ### Kotlin Multiplatform Mobile - [KMM sample project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/kotlin-multiplatform-mobile) ### Ionic Samples - [Ionic + Capacitor sample](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ionic/ionic-capacitor-demo-project) - [Ionic + Cordova sample](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ionic/ionic-cordova-demo-project) ### Integrations - [Appetize](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/appetize_integration_demo_project) - [BrowserStack App Automate](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/browserstack_app_automate_demo_project) - [BrowserStack App Live](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/browserstack_app_live_demo_project) - [Capawesome Cloud](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/capawesome_cloud_demo_project) - [Capgo](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/capgo_integration_demo_project) - [Codecov](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/codecov_integration_demo_project) - [Discord](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/discord_integration_demo_project) - [Emerge Tools](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/emerge-tools-integration-demo-project) - [emulator.wtf](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/emulatorwtf-android-demo-project) - [Fastlane Android](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/fastlane-android-integration-demo-project) - [Fastlane](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/fastlane-integration-demo-project) - [Firebase Crashlytics](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/firebase_crashlytics_demo_project) - [Jira](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/jira_integration_demo_project) - [Katalon](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/katalon_integration_demo_project) - [Kobiton](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/kobiton_integration_demo_project) - [LambdaTest](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/lambdatest_integration_demo_project) - [pCloudy](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/pcloudy_integration_demo_project) - [Patrol](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/patrol-demo-project) - [Perfecto](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/perfecto_flutter_sample_project) - [Sentry](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/sentry_integration_demo_project) - [Sofy](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/sofy_integration_demo_project) - [SonarQube](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/sonarqube_integration_demo_project) ### Publishing and Distribution - [Firebase App Distribution](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/firebase-app-distribution) - [App Store Connect](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-automatic-code-signing-demo-project) - [Google Play](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/android/android-espresso-demo-project) ### YAML Samples - [YAML anchors and aliases sample](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/yaml/yaml_anchors_aliases_sample) ================================================================================ source: https://docs.codemagic.io/rn-codepush/concepts/ title: Concepts description: Core concepts behind CodePush and OTA updates last_modified: 2026-05-11 ================================================================================ # Concepts > Core concepts behind CodePush and OTA updates This section explains how CodePush works at a conceptual level before any setup or commands. Understanding the update model makes the configuration and release workflow easier to follow. --- ### The Problem: Slow App Store Updates By default, shipping a mobile app update looks like this: ```text Developer makes a change → Build a new app binary → Submit to App Store / Play Store → Wait for review → Users download the update ``` This process is slow and rigid: * Reviews can take hours or days * Urgent fixes are delayed * Users must manually update ### The Idea: Over-the-Air (OTA) Updates with CodePush CodePush enables OTA updates for React Native apps. Instead of distributing a new binary, the app downloads an updated JavaScript bundle from a server: ```text Developer releases JS update → CodePush server stores update → App checks server for updates → New bundle downloaded → Update applied on restart/resume/immediately ``` Typical OTA use cases: * Hotfixes for production bugs * UI tweaks or styling updates * Feature flag changes * Configuration or content updates * Experimentation or staged feature rollouts Benefits: Faster releases, reduced dependency on app store reviews, and quicker fixes for users. ## JavaScript layer vs Native layer React Native apps contain two layers. The **Native layer** is the compiled platform code, such as: - Swift / Objective-C for iOS - Java / Kotlin for Android This includes platform integrations, native modules, permissions, OS APIs, and the compiled app binary. Changes to this layer require rebuilding the app and publishing through the app stores. The **JavaScript layer** contains the React Native application logic: - UI components - business logic - navigation - state management - bundled static assets CodePush updates this **JavaScript bundle and its assets**. As long as JS remains compatible with the already-installed native binary, it can be delivered as an OTA update. ## What can and cannot be updated Can Be Updated via CodePush (OTA-safe): * Fixing JavaScript bugs * UI or layout adjustments * Styling changes * Updating bundled images or static assets * Feature flags or configuration logic * JavaScript performance improvements These updates modify only the JavaScript bundle, so they can be safely delivered over the air. Require a New App Release * Adding or modifying native modules * Upgrading React Native or native dependencies * Editing native configuration files (build.gradle, Info.plist, etc.) * Changing app permissions (camera, location, etc.) * Adding platform-specific features or integrations These changes affect compiled native code, so they must go through the App Store or Play Store. ### Delta updates CodePush uses delta updates (file-level diffs) for each release and delivers only the JavaScript files and assets that changed. Instead of redownloading a complete bundle and all static assets on every update, users receive a smaller delta package. This keeps OTA updates faster and reduces bandwidth usage. ## How the update flow works A CodePush-enabled app includes a client SDK that communicates with the update server: ```text app launch * CodePush SDK checks for updates (based on configuration) * update available? * download JavaScript bundle + assets * store update locally * apply update (typically on next restart) ``` The update replaces the previously installed JavaScript bundle while keeping the native application unchanged. If an update fails or causes the app to crash on startup before it is marked as successful, the client can automatically revert to the previous working bundle. ### Prerequisite: a native build with the SDK Because CodePush relies on the client SDK to check the server, download bundles, and swap the JS layer at launch, **the SDK must already be present in the native binary running on each user's device**. A store build that does not include the SDK cannot install OTA updates — `release-react` will still publish the bundle, but no client will pick it up. The first time you add CodePush to an existing app, you therefore need to: 1. Integrate the SDK in your React Native project (see [Setup](/rn-codepush/setup/)). 2. Produce a native build that includes the SDK and the deployment key you want to target. 3. Install that build on the devices you expect to receive updates — local dev machines or QA devices for **Staging**, App Store / Google Play for **Production**. 4. Only then start shipping JS changes to that deployment as OTA updates. For Staging validation this usually just means running a fresh debug build on a test device; no store release is required. For Production, end users must actually update to the new store binary before they can receive anything CodePush publishes. After that, the usual pattern — occasional native releases for native changes, OTA releases for everything else — applies. ## Deployment model CodePush organizes updates using **apps** and **deployments**. Each mobile application registered with CodePush is called an **app**. A project may contain multiple apps, such as: - `MyApp-Android` - `MyApp-iOS` Separating apps by platform is recommended because React Native bundles differ between platforms. Each app contains one or more **deployments**. Deployments represent release channels. Default deployments include **Staging** and **Production**. ```text release update → Staging internal testing promote update → Production ``` This workflow lets teams validate OTA updates before exposing them to all users. Creating, promoting, and changing those releases is done with the **CodePush CLI**, not from a web upload UI—see [Releasing updates](/rn-codepush/releasing-updates/). ### Deployment keys Each deployment has a **deployment key**. The deployment key is embedded in the mobile app and tells the CodePush SDK which deployment to check for updates. Example usage: - development builds use the **Staging** key - production builds use the **Production** key This separation ensures test updates do not reach production users. ## Where CodePush fits in the release process Traditional mobile release: ```text commit → CI build → store submission → user installs update ``` Release workflow with CodePush: ```text commit → CI build → store release (initial binary) → OTA updates via CodePush → occasional store releases for native changes ``` This lets teams ship small fixes and improvements between full app store releases. ================================================================================ source: https://docs.codemagic.io/yaml-notification/email/ title: Email description: How to send build status updates to email with links to artifacts in codemagic.yaml last_modified: 2026-03-17 ================================================================================ # Email > How to send build status updates to email with links to artifacts in codemagic.yaml If the build finishes successfully, release notes (if passed) and the generated artifacts will be published to the provided email address(es). The artifact download links in email are, by default, valid for 24 hours. You can configure the lifetime of publicly accessible artifact download links by selecting your personal account or team and navigating to **Settings > Artifact download links**. If the build fails, an email with a link to build logs will be sent. If you don't want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml publishing: email: recipients: - name@example.com notify: success: false # To not receive a notification when a build succeeds failure: false # To not receive a notification when a build fails ``` When you set up email publishing, Codemagic publishes the following artifacts: - `app` - `ipa` - `apk` - the archive with Flutter web build directory - Linux application bundle files - Windows MSIX packages - .exe **Important:** Email notifications are only sent when artifacts are available for Codemagic to collect. If your build scripts include cleanup steps (such as `flutter clean` or Fastlane's `clean_build_artifacts`) that run *before* Codemagic collects artifacts, the binaries will be deleted and **no email will be sent**—even if the build itself succeeded. ================================================================================ source: https://docs.codemagic.io/knowledge-git/generating-an-ssh-key/ title: Generating an SSH key description: How to create a secure SSH key pair in terminal last_modified: 2022-10-12 ================================================================================ # Generating an SSH key > How to create a secure SSH key pair in terminal Different repository hosting services have different minimum requirements for their SSH keys. We recommend using a widely supported and secure algorithm such as `ECDSA` or `Ed25519` when generating your key pair. ```bash ssh-keygen -t ed25519 -f ~/Desktop/codemagic_ssh_key -q -N "" ``` This will create two new files on your desktop: `codemagic_ssh_key` (private key) and `codemagic_ssh_key.pub` (public key). > > **Note:** Some issues may arise when using the `RSA SHA-1` hash algorithm for generating the key pair as it is being quickly deprecated across operating systems and SSH clients due to various vulnerabilities. > ================================================================================ source: https://docs.codemagic.io/troubleshooting/help-and-support/ title: Getting help and support description: How to find answers to your questions and resolve issues last_modified: 2025-05-13 ================================================================================ # Getting help and support > How to find answers to your questions and resolve issues ## Documentation If you need help in setting up your project or would like to know more about Codemagic features, the first source of information to consult should certainly be these documentation pages. Make sure to use the search bar to its full potential as it may help you discover the answers you are looking for. We are constantly updating and improving our documentation so it might be helpful to revisit the old topics from time to time to catch up with the new features. If you find any errors or issues in any of the documentation pages, please report them and/or suggest improvements [here](https://github.com/codemagic-ci-cd/codemagic-docs/issues/new?assignees=&labels=&template=documentation-update-request.md&title=). ## Blog and Sample projects Another great source of knowledge is our [blog](https://blog.codemagic.io/). It is filled with articles, guides, and deep dives on a variety of topics that can simultaneously serve as an inspiration and as teaching material. Paired with ready-to-use [sample projects](https://docs.codemagic.io/yaml-quick-start/codemagic-sample-projects/) in our repository, they are a valuable resource both for beginners and for more advanced users. ## Community support with GHD Sometimes, things will go wrong despite following the exact steps outlined in the documentation. Should you encounter such an issue, a great place to search for answers is in our [GitHub discussions](https://github.com/codemagic-ci-cd/codemagic-docs/discussions). Chances are, someone else has already encountered a similar error and a quick search might unblock your project in no time. If searching the discussions does not give any results and you are convinced you are the first person to encounter the issue, feel free to start a new topic. Please follow the standard best practices for bug reporting: - Keep the title short and specific - If the title isn’t enough, add a short summary explaining the issue - For build-related issues, please include your build ID. This will help our support to compare Codemagic internal logs for the event. Build ID cannot be used by third parties to compromise your account or get to your data in any way. - Where applicable, add a screenshot or other visual explanation - Clearly explain the expected behavior vs. the actual results - Describe your project, environment, and other settings in as much detail as you can Please don’t forget to mark the issue as resolved once the correct answer has been found as this will greatly help others. ## Codemagic Community Discord Server You can join the Codemagic Community Discord Server to connect with the Codemagic Team and chat with other Codemagic users. You can join the Discord server [here](https://discord.gg/pefznye93R). ## Billing enabled customers - Chat Widget (live support) In addition to the above, customers on paid plans can contact our support team directly using the chat widget available in their Codemagic UI. To guarantee the best experience and speed up issue resolution time, please follow the same error reporting guidelines as for the GitHub discussions. Our support engineers are available during office hours, Mon - Fri 9:00 - 18:00 EEST (UTC+3), excluding Estonian [public holidays](https://www.eesti.ee/en/republic-of-estonia/republic-of-estonia/national-public-and-school-holidays). ================================================================================ source: https://docs.codemagic.io/flutter-code-signing/ios-code-signing/ title: iOS code signing description: How to set up iOS code signing in the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # iOS code signing > How to set up iOS code signing in the Flutter workflow editor Code signing is required by Apple for integrating app services, installing your iOS app on real devices, and for uploading it to App Store Connect so that it can be distributed through TestFlight or App Store. It enables you to identify who developed the app and ensure that all the changes to the app come from you or your team. To receive a signed `.ipa` file of your app on Codemagic, you need to set up code signing. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured with **codemagic.yaml** please go to [Signing iOS apps using codemagic.yaml](../code-signing-yaml/signing-ios). > ## Introduction Before you can start signing or distributing your app, you must have an [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. The signing certificates — development or distribution — help to identify who built the code. A provisioning profile — development or distribution — contains information about the app ID, the devices on which the app can be installed and the certificates that can be used for signing the app. Note that if your app contains app extensions, you need an additional provisioning profile for each app extension. > > **Note:** With **automatic code signing**, Codemagic will create both the certificate and the provisioning profile on your behalf without requiring a Mac. > > With **manual code signing**, you need to upload the signing files manually. > For successful signing, the certificate and the provisioning profile must match in the following way: {{< figure size="medium" src="../uploads/2019/03/CM-codesigning.jpg" caption="Matching the signing certificate and the provisioning profile" >}} In short, the purpose of the different provisioning profiles is the following: - **Development**: for testing the app on a real device while developing. - **Ad Hoc:** for distributing the app to non-TestFlight testers. The app must be built in **release** mode. - **App Store**: for distributing the app via TestFlight or the App Store. The app must be built in **release** mode. ## Automatic code signing {{< youtube aBDx6BKFXIA >}} Codemagic makes automatic code signing possible by connecting to [App Store Connect via its API](https://developer.apple.com/app-store-connect/api/) for creating and managing your code signing certificates and provisioning profiles. It is possible to set up several code signing identities and use different code signing settings per workflow. The following sections describe how to set up automatic code signing for builds configured in the UI. If you're building with `codemagic.yaml`, please refer [here](../code-signing-yaml/signing-ios). ### Step 1. Creating an App Store API key for Codemagic %!s()The Apple Developer Portal integration can be enabled in the **Team integrations** section in your team settings (if you're a team admin). This allows you to conveniently use the same access credentials for automatic code signing and publishing across different apps and workflows. 1. In the list of available integrations, click the **Connect** button for **Developer Portal**. 2. In the **App Store Connect API key name**, provide a name for the key you are going to set up the integration with. This is for identifying the key in Codemagic. 3. Enter the **Issuer ID** related to your Apple Developer account. You can find it above the table of active keys on the Integrations tab of the [Users and Access](https://appstoreconnect.apple.com/access/integrations/api) page. 4. Enter the **Key ID** of the key to be used for code signing. 5. In the **API key** field, upload the private API key downloaded from App Store Connect. 6. Click **Save** to finish the setup. If you work with multiple Apple Developer teams, you can add additional keys by clicking **Add another key** right after adding the first key and repeating the steps described above. You can delete existing keys or add new ones when you click **Manage keys** next to the Developer Portal integration in personal account or team settings. ### Step 3. Enabling automatic code signing for workflow Once the Apple Developer Portal has been enabled for the account or team the app belongs to, you can easily enable automatic code signing per workflow. 1. Go to **App settings > Distribution > iOS code signing**. 2. Select **Automatic** as the code signing method. If you haven't enabled the Apple Developer Portal integration yet, you will be asked to enable it before you can continue configuration. 3. If you have several keys available, select the right key in the **App Store Connect API key** field. 4. Select the **provisioning profile type** used for provisioning the build. Codemagic will automatically select or generate a matching certificate for code signing. The provisioning profiles (except for Distribution) will include all the devices you have registered on your Apple Developer account at the time of creating the profile. 7. Select your app's **bundle identifier**. Codemagic lists all the bundle IDs available for the selected App Store Connect API key. If you can't see your app's bundle identifier listed, create one in [Apple Developer Portal](https://developer.apple.com/account/resources/identifiers/add/bundleId). > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > As the next step, you can [configure publishing to App Store Connect](../publishing/publishing-to-app-store) to distribute the app via TestFlight or submit it to the App Store. ## Manual code signing With the manual code signing method, you are required to upload the signing certificate and the matching provisioning profile(s) to Codemagic in order to receive signed builds. This is required when distributing your app via Apple Developer Enterprise Program or Apple Business Manager. >See how to [export certificates and provisioning profiles](#exporting-certificates-and-provisioning-profiles). ### Setting up manual code signing 1. Go to **App settings > Distribution > iOS code signing**. 2. Select **Manual** as the code signing method. 3. Upload your signing certificate (in `.p12` format). If your certificate is password-protected, enter the **Certificate password**. 4. Upload your provisioning profile (`.mobileprovision`). Note that if your app contains app extensions, you are required to upload an additional provisioning profile for each extension. {{< figure size="medium" src="../uploads/manual_code_signing.png" caption="Manual code signing setup ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/migrating-from-app-center/ title: Migrating from App Center description: How to ship your workflows to Codemagic last_modified: 2026-06-26 ================================================================================ # Migrating from App Center > How to ship your workflows to Codemagic

> > Join 1,500+ mobile experts in our [Discord community](https://discord.com/invite/ZJsYR6JCBD) to share knowledge and experiences of migrating from App Center and getting started with Codemagic. > ## Quick comparison | **Features** | **App Center** | **Codemagic** | |-----------------------------| ---------------|----------------| | `Over-the-air (OTA) updates (CodePush)`| ☑️| ✅ | | `Swift/Objective-C iOS` | ☑️ | ✅ | | `Android apps` | ☑️ | ✅ | | `React Native CLI apps` | ☑️ | ✅ | | `Expo React Native apps` | ❌ | ✅ | | `Flutter apps` | ❌ | ✅ | | `Unity apps` | ☑️ | ✅ | | `Ionic apps` | ☑️ | ✅ | | `White-labeling solution` | ❌ | ✅ | | `Automatic iOS code signing`| ❌ | ✅ | | `Manual iOS code signing` | ☑️ | ✅ | | `Android code signing` | ☑️ | ✅ | | `Automatic build versioning`| ☑️ | ✅ | | `Running integration tests`| ☑️ | ✅ | | `Running unit tests` | ☑️ | ✅ | | `App Store publishing` | ☑️ | ✅ | | `Play Store publishing` | ☑️ | ✅ | | `Firebase App Distribution `| ❌ | ✅ | | `Slack integration` | ❌ | ✅ | | `Email notifications` | ☑️ | ✅ | | `macOS M2 support` | ❌ | ✅ | | `Linux machines support` | ❌ | ✅ | | `Windows machines support` | ☑️ | ✅ | | `Over-the-air (OTA) updates`| ☑️ | ✔️* | | `Analytics` | ☑️ | ✔️* | | `Apple device registration` | ❌ | ✅ | | `Remote access to build machines`| ❌ | ✅ | | `Global environment variables`| ❌ | ✅ | | `Install apps from QR code` | ❌ | ✅ | | `Gitlab self-hosted repositories`| ☑️ | ✅ | | `Github self-hosted repositories`| ❌ | ✅ | | `Bitbucket self-hosted repositories`| ❌ | ✅ | | `Enabling iOS app capability`| ❌ | ✅ | | `Building iOS and Android together`| ❌ | ✅ | | `Inter-connected workflow support`| ❌ | ✅ | | `Build logs for each build step`| ❌ | ✅ | | `Dependency caching` | ❌ | ✅ | * Codemagic allows you to integrate with Sentry and Firebase Crashlytics for analytics and uploading debug symbols > > **Note:** When adding React Native projects to App Center, iOS and Android platforms are added separately like two different projects. This behavior does not allow you to build and publish iOS and Android within the same workflow. With Codemagic, React Native repositories are added only once which prevents iOS and Android from being added separately. Besides, both platforms can be built and published within the same workflow. > ### Performance overview **Test name** | **Codemagic (Mac Studio M2 Max)** | **Codemagic (M2)** | **App Center** --- | --- | --- | --- Building Project | [**4m 36s**](https://codemagic.io/app/660936c197f2bee5b7353663/build/67365494bdb50729da7ac73a) | [6m 29s](https://codemagic.io/app/660936c197f2bee5b7353663/build/673654731bd5c81d4bac8598) | [39m 27s](https://appcenter.ms/orgs/Nevercode_Codemagic/apps/Benchmark_iOS/build/branches/main/builds/9) Overall improvement | 758% | 508% | 1 As it can be seen, building the benchmark project took around 2-4 minutes with Codemagic macOS M2 and Max Studio machines while the build was completed in 39 minutes 24 seconds with App Center. Worth pointing out that App Center limits free tier users to 30 minutes build duration per build and based on the performance rate above, the 30 minute build duration range will not allow you to complete your builds due to the fact that they will timeout. ### Support options Besides having an opportunity for premium support through a dedicated MS Teams/Slack/Discord channel, your team will have access to the chat widget in the Codemagic web app. Worth mentioning that Codemagic offers community support in [GitHub Discussions](https://github.com/orgs/codemagic-ci-cd/discussions) and [Discord Community Server](https://discord.com/invite/pefznye93R) as well. ### Debugging options Unlike App Center, Codemagic allows you to have straightforward debugging sessions: 1. Each build step has its own logs printed out which help you understand where issues could stem from. However, App Center presents all the build logs in one output which makes it extra challenging. 2. When building with Codemagic, you can enable remote access to builder machines through SSH and VNC sessions which means that you can access Xcode and Mac machines without quitting your ongoing build while debugging issues. Once you confirmed that your solution works, then you can either directly push these changes from Codemagic machines or do it manually. ## Step-by-Step transitioning guide 1. Sign up with Codemagic by clicking the link [here](https://codemagic.io/signup), or if you have already registered, then login to your account [here](https://codemagic.io/login) 2. Complete the onboarding process by either getting started with a personal account or by creating a team where you and your colleagues can contribute to your app building and publishing process. You will be guided through once signed up. 3. Add your repository to Codemagic by either connecting your Git cloud provider account or by entering the clone URL manually. 4. Add **codemagic.yaml** in the root directory of the repository and check the file content below: ### Option: iOS with React Native CLI ```yaml workflows: react-native-ios: name: React Native iOS max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: codemagic environment: ios_signing: distribution_type: app_store bundle_identifier: io.codemagic.sample.reactnative vars: XCODE_WORKSPACE: "CodemagicSample.xcworkspace" # <-- Put the name of your Xcode workspace here XCODE_SCHEME: "CodemagicSample" # <-- Put the name of your Xcode scheme here APP_ID: 1555555551 # <-- Put the app id number here. This is found in App Store Connect > App > General > App Information node: v19.7.0 xcode: latest cocoapods: default scripts: - name: Install npm dependencies script: | npm install - name: Install CocoaPods dependencies script: | cd ios && pod install - name: Set Info.plist values script: | # This allows publishing without manually answering the question about encryption PLIST=$CM_BUILD_DIR/$XCODE_SCHEME/Info.plist PLIST_BUDDY=/usr/libexec/PlistBuddy $PLIST_BUDDY -c "Add :ITSAppUsesNonExemptEncryption bool false" $PLIST - name: Set up code signing settings on Xcode project script: | xcode-project use-profiles --warn-only - name: Increment build number script: | cd $CM_BUILD_DIR/ios LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number "$APP_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "$CM_BUILD_DIR/ios/$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false app_store_connect: auth: integration submit_to_testflight: true beta_groups: # Specify the names of beta tester groups that will get access to the build once it has passed beta review. - group name 1 - group name 2 submit_to_app_store: false ``` ### Option: Android with React Native CLI ```yaml workflows: react-native-android: name: React Native Android max_build_duration: 120 instance_type: mac_mini_m2 environment: android_signing: - keystore_reference groups: - google_play # <-- (Includes GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS <-- Put your google-services.json) vars: PACKAGE_NAME: "io.codemagic.sample.reactnative" # <-- Put your package name here e.g. com.domain.myapp node: v19.7.0 scripts: - name: Install npm dependencies script: | npm install - name: Set Android SDK location script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/android/local.properties" - name: Build Android release script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z LATEST_BUILD_NUMBER ]; then # fallback in case no build number was found from google play. Alternatively, you can `exit 1` to fail the build UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi cd android ./gradlew bundleRelease \ -PversionCode=$UPDATED_BUILD_NUMBER \ -PversionName=1.0.$UPDATED_BUILD_NUMBER artifacts: - android/app/build/outputs/**/*.aab publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true # To not receive a notification when a build succeeds failure: false # To not receive a notification when a build fails google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: alpha # Any default or custom track that is not in ‘draft’ status ``` Once **codemagic.yaml** is configured, Codemagic automatically detects it and by clicking the **Start new build** button, your app is built and published to the stores. ## Automatic build triggering without manual intervention Codemagic allows you to trigger builds on **pull_request**, **pull_request_labeled**, **push** and **tag** events. - **push** - a build will be started every time you commit code to any of the tracked branches. - **pull_request** - a build will be started when a pull request is opened or updated to verify the resulting merge commit. - **pull_request_labeled** - a build will be started every time you add a new label to a **GitHub** pull request. - **tag** - Codemagic will automatically build the tagged commit whenever you create a tag for this app. Note that the watched branch settings do not affect tag builds. Below you can find the steps to enable automatic build triggering: 1. Grab the webhooks URL and configure it in the repository settings. You can find the webhook URL in the Codemagic web app when navigating to your application and selecting the Webhooks tab. Below you can find how to configure webhooks with Azure DevOps. ### Azure DevOps webhook configuration Open your application repository, go to **Project Settings** > **Service Hooks**, click on **Create a new subscription...** and select **Web Hooks**. Under **Trigger on this type of event**, choose the event you wish to trigger builds for. Codemagic supports **Code pushed**, **Pull request created**, and **Pull request updated** events. In Azure, each of the events requires its own webhook. Once the event has been selected, choose your repository under filters and configure any additional settings. 2. Configure the **triggering** section in **codemagic.yaml**. The ready-to-use codemagic.yaml samples above have it already added. Check them for reference: ```yaml ``` triggering: events: - push - tag - pull_request - pull_request_labeled branch_patterns: - pattern: develop include: true source: true ``` ``` 3. Done! Now, as soon as any changes are made based on the events above, builds will be triggered and you can check the webhook messages by navigating to your application and selecting the Webhooks tab. Additionally, by using **when** to run and skip builds along with using **changeset** inside **when**, you can avoid unnecessary builds when functional components of your repository were not modified. More information about it can be found [here](https://docs.codemagic.io/yaml-running-builds/starting-builds-automatically/#using-when-to-run-or-skip-builds) ## Code signing iOS apps All iOS applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. Codemagic handles the code signing process with ease through its manual and automatic code signing methods. The following steps will help you set up code signing for iOS applications: 1. Have your Apple Developer account as required by Apple 2. You can either let Codemagic generate a distribution certificate and provisioning profile or you do it yourself in Apple Developer account, then share them with Codemagic, so it can use these resources during code signing the application: ### Adding code signing certificate The steps below describe how to upload a distribution certificate. ### Option: Upload certificate 1. Log in to App Store Connect and navigate to Users and Access > Integrations » App Store Connect API. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing App Manager access rights. 4. Click Generate. 5. As soon as the key is generated, you can see it added to the list of active keys. Click Download API Key to save the private key. 6. Open your Codemagic Team settings, go to Team integrations > Developer Portal > Manage keys. 7. Click the Add key button. 8. Enter the App Store Connect API key name. This is a human readable name for the key that will be used to refer to the key later in application settings. 9. Enter the Issuer ID and Key ID values. 10. Click on Choose a **.p8** file or drag the file to upload the App Store Connect API key downloaded earlier. 11. Click Save. ### Option: Generate new certificate If you have added the App Store Connect API key to Codemagic, you can also generate a new Apple Development or Apple Distribution certificate. 1. Open your Codemagic Team settings, go to codemagic.yaml settings > Code signing identities. 2. Open iOS certificates tab. 3. Click Generate certificate. 4. Provide a Reference name for the certificate. 5. Choose the Certificate type. 6. Select the App Store Connect API key to use. 7. Click Create certificate. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team’s App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to codemagic.yaml settings > Code signing identities. 2. Open iOS certificates tab. 3. Click Fetch certificate. 4. Select a certificate from the Development certificates or Distribution certificates list. 5. Click Fetch selected. ### Adding code signing provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. ### Option: Fetch from developer account You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team’s App Store Connect API key. The bundle identifier is listed for every available profile along with it’s name. The profiles are displayed grouped by category: Development profiles, Ad Hoc profiles, App Store profiles, and Enterprise profiles. For each selected profile, it is necessary to provide a unique Reference name, which can be later used in codemagic.yaml to fetch the profile. 1. Open your Codemagic Team settings, go to codemagic.yaml settings > Code signing identities. 2. Open iOS provisioning profiles tab. 3. Click Fetch profiles 4. Select the desired profile(s) and enter a Reference name for each one. 5. Click Download selected. (scroll down if necessary) ### Option: Upload a profile You can upload provisioning profiles with the .mobileprovision extension, providing a unique Reference name is required for each uploaded profile. 1. Open your Codemagic Team settings, go to codemagic.yaml settings > Code signing identities. 2. Open iOS provisioning profiles tab. 3. Upload the provisioning profile file by clicking on Choose a .mobileprovision file or by dragging it into the indicated frame. 4. Enter the Reference name for the profile. 5. Click Add profile. ## Code signing Android apps All Android applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. Follow the steps below to complete the android code signing configuration: 1. Generate a keystore file for signing your release builds. Running the following Java Keytool utility on your local machine will generate the necessary keystore file: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` 2. Open your Codemagic Team settings, and go to codemagic.yaml settings > Code signing identities. 3. Open Android keystores tab. 4. Upload the keystore file by clicking on Choose a file or by dragging it into the indicated frame. 5. Enter the Keystore password, Key alias and Key password values as indicated. 6. Enter the keystore Reference name. This is a unique name used to reference the file in codemagic.yaml 7. Click the Add keystore button to add the keystore. 8. Go to your android workflow in codemagic.yaml, and reference the keystore file name like below: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` ## Publishing iOS apps to App Store Connect Codemagic enables you to automatically publish your iOS or macOS app to App Store Connect for beta testing with TestFlight or distributing the app to users via App Store. Codemagic uses the App Store Connect API key for authenticating communication with Apple’s services. You can read more about generating an API key from Apple’s documentation page. The following steps will allow you to configure the process successfully: 1. As you have already created and connected your .p8 file from the App Store Connect account as explained above under the Adding code signing certificate section, we can refer to the steps there for generating the api key and adding to Codemagic 2. After completing those steps, all you need is to use the reference name in codemagic.yaml: ```yaml workflows: ios-workflow: name: iOS Workflow integrations: app_store_connect: ``` 3. And add the publishing section in codemagic.yaml as shown in the ready-to-use content right at the top: ```yaml publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2024-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2024 Nevercode Ltd ``` With these, your app will be published to TestFlight or App Store Connect for production. All it takes is just specifying **true** or **false**. ## Publishing Android apps to Google Play Store Like App Store Connect publishing, Codemagic builds and publishes your Android apps to Play Store. To achieve it, you need to follow the steps below: 1. To allow Codemagic to publish applications to Google Play, it is necessary to set up access using Google Play API. Visual explanation of how to create a service account json file and connect it with your Play Store app can be found [here](https://docs.codemagic.io/yaml-publishing/google-play/) 2. After creating the required JSON file, you can now configure Play Store publishing in **codemagic.yaml**. [Here](https://docs.codemagic.io/yaml-publishing/google-play/#configure-publishing-in-codemagicyaml) you can find on how to achieve it easily. ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/migrating-from-bitrise/ title: Migrating from Bitrise description: How to migrate your projects from Bitrise to Codemagic last_modified: 2026-06-26 ================================================================================ # Migrating from Bitrise > How to migrate your projects from Bitrise to Codemagic Codemagic makes use of [`codemagic.yaml`](../yaml/yaml-getting-started/) for configuring your workflow. As Codemagic supports any Git-based cloud or self-hosted repository, there is no need to migrate your code - simply add a `codemagic.yaml` file to your repository root folder. In Codemagic, there is also a [Flutter workflow editor](../flutter-configuration/flutter-projects/) for Flutter applications, which simplifies the setup but removes some flexibility. ## Migrating builds with codemagic.yaml If you have already set up your application on Bitrise, migrating to Codemagic is straightforward. ### Option: Android ### Code signing To set up code signing with `codemagic.yaml`, you must add your keystore and related information (passwords, alias, etc.) as environment variables. #### Modify build.gradle Modify your **`android/app/build.gradle`** as follows: ```kotlin ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` #### Configure environment variables The environment variables referenced by the `build.gradle` need to be stored in the Codemagic UI. A detailed explanation on how Environment variables and groups work can be found [here](../variables/environment-variable-groups). The keystore file, like all binary files, has to be base64 encoded before storing its value. - For **Linux** machines, we recommend installing xclip: ```Shell sudo apt-get install xclip cat codemagic.keystore | base64 | xclip -selection clipboard ``` Alternatively, you can run the following command and carefully copy/paste the output: ```Shell openssl base64 -in codemagic.keystore ``` > > **Tip**: When copying file contents always include any tags. e.g. Don't forget to copy `-----BEGIN PRIVATE KEY-----` and `-----END PRIVATE KEY-----` too. > - On **macOS**, running the following command base64 encodes the file and copies the result to the clipboard: ```Shell cat codemagic.keystore | base64 | pbcopy ``` - For **Windows**, the PowerShell command to base64 encode a file and copy it to the clipboard is: ```powershell [Convert]::ToBase64String([IO.File]::ReadAllBytes("codemagic.keystore")) | Set-Clipboard ``` 1. Open your Codemagic app settings, go to **Environment variables** tab. 2. Enter `CM_KEYSTORE` as the **_Variable name_**. 3. Paste the base64 encoded value of the keystore file in the **_Variable value_** field. 4. Enter a variable group name, e.g. **_android_code_signing_**. Click the button to create the group. 5. Make sure the **Secret** option is selected so that the variable can be protected by encryption. 6. Click the **Add** button to add the variable. 7. Continue by adding `CM_KEYSTORE_PASSWORD`, `CM_KEY_ALIAS` and `CM_KEY_PASSWORD` 8. Add the `CM_KEYSTORE_PATH` variable with the value `$CM_BUILD_DIR/codemagic.keystore` > > **Tip:** Store all the keystore variables in the same group so they can be imported to codemagic.yaml workflow at once. > Environment variables have to be added to the workflow either individually or as a group. Modify your `codemagic.yaml` file by adding the following: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: groups: - android_code_signing ``` Environment variables added with the **Secret** option checked are transferred to the build machine encrypted and are available only while the build is running. The build machine is destroyed at the end. The content of the `base64` encoded files needs to be decoded before it can be used. Instead of the `Android sign` step on Bitrise, define a script in the `codemagic.yaml` to base64 decode your keystore to a specified location: ```yaml workflows: android-workflow: # .... environment: # .... scripts: - name: Set up keystore script: | echo $CM_KEYSTORE | base64 --decode > $CM_KEYSTORE_PATH ``` ### Building Suppose you have followed the above instructions on setting up code signing with the `codemagic.yaml` configuration. In that case, to continue with Codemagic, add a script to your scripts sections to build the application. You can find various build scripts for different types of applications in our [Sample projects](../yaml-quick-start/codemagic-sample-projects/). An example build script for building a Native Android application: ```yaml scripts: - name: Build Android script: | ./gradlew assembleRelease ``` With Codemagic, you can configure which artifacts to receive at the end of the build under the [artifacts section](../yaml/yaml-getting-started/#artifacts). This provides relatively more flexibility in comparison to Bitrise's `Deploy to Bitrise.io` step. For teams on Annual or Enterprise plans, the build artifacts do not expire. The artifacts section can for example be configured in the `codemagic.yaml` as follows: ```yaml artifacts: - app/build/outputs/**/**/*.aab - app/build/outputs/**/**/*.apk ``` ### Deployment To deploy to **Google Play**, a service account is required. Creating a service account is the same process in Codemagic and Bitrise. In theory, both platforms could use the same service account. If you have already uploaded your service account to Bitrise, you can download it from there under `Generic file storage`. Alternatively, you can set up a new service account following the instructions [here](../knowledge-base/google-services-authentication/). To add your service account to your configuration file, add it as an environment variable. For example, `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. First, navigate to your application and click the `Environment variables` tab. To add the file, encode its contents with base64 and paste the value into Codemagic; make sure to check **Secret** when providing sensitive information. You can either add it to an already created group or create a new group, which you can later reference in your `codemagic.yaml`. Like Bitrise's `Google Play Deploy` step, Codemagic allows you to modify the track, rollout fraction, and update priority. In addition, you can conveniently configure to submit the build as a draft or choose to send the changes directly to review. Follow the example [here](../yaml-publishing/google-play/) to configure publishing to Google Play in your `codemagic.yaml`. The `Google Play Deploy` step in `bitrise.yml` and the publishing in `codemagic.yaml` are relatively similar. However, Bitrise requires you to add the package name of the application. Codemagic publishes the relevant artifacts generated during the build with their respective names. **bitrise.yml** ```yaml - google-play-deploy@3: inputs: - package_name: android_application.apk - user_fraction: '0.25' - update_priority: '3' - track: alpha - status: draft - retry_without_sending_to_review: 'true' - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_URL" ``` **codemagic.yaml** ```yaml publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: alpha in_app_update_priority: 3 rollout_fraction: 0.25 changes_not_sent_for_review: true submit_as_draft: true ``` ### Option: iOS ### Code signing Like Bitrise, Codemagic lets users configure either a manual or an automatic option for handling iOS code signing profiles and certificates. #### Automatic iOS code signing Codemagic uses the [App Store Connect API](../yaml-code-signing/signing-ios/#creating-the-app-store-connect-api-key) for managing signing profiles and certificates. Bitrise uses the same API in the `Manage iOS Code Signing` step. Thus, Codemagic requires the same values as Bitrise for handling automatic code signing. With the `codemagic.yaml` configuration, the values have to be provided as [environment variables](../yaml-code-signing/signing-ios/#saving-the-api-key-to-environment-variables). In addition, Codemagic requires you to create an RSA 2048 bit private key to be included in the signing certificate. Then, using the defined variables in your scripts section to automate creating and fetching profiles and certificates is possible. Follow the steps defined in our [documentation](../yaml-code-signing/signing-ios/#automatic-code-signing) to find information on how to generate the necessary details and use them in your configuration. An example of using scripts to manage automatic code signing is found below: ```yaml scripts: - name: Set up keychain to be used for code signing using Codemagic CLI 'keychain' command script: keychain initialize - name: Fetch signing files script: | # You can allow creating resources if existing are not found with `--create` flag app-store-connect fetch-signing-files "$(xcode-project detect-bundle-id)" \ --type IOS_APP_DEVELOPMENT \ --create - name: Set up signing certificate script: keychain add-certificates - name: Set up code signing settings on Xcode project script: xcode-project use-profiles ``` As you can use Codemagic's automatic code signing to create new profiles and certificates, the process is very easily manageable. #### Manual iOS code signing With the manual option, Codemagic requires you to add all of your signing files (profiles, certificates, etc.) as environment variables. These are the same files uploaded on Bitrise under the application's `Code Signing` tab. If you have already set up manual code signing on Bitrise, setting it up with Codemagic is relatively simple. You can download the necessary provisioning profiles and certificates from Bitrise's `Code Signing` tab. In order to use manual code signing, you need the following: - **Signing certificate**: Your development or distribution certificate in .P12 format. - **Certificate password**: The certificate password if the certificate is password-protected. - **Provisioning profile**: You can get it from **Apple Developer Center > Certificates, Identifiers & Profiles > Profiles** and select the provisioning profile you would like to export and download. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter `CM_CERTIFICATE` as the **_Variable name_**. 3. Run the following command on the certificate file to `base64` encode it and copy to clipboard: ```Shell cat ios_distribution_certificate.p12 | base64 | pbcopy ``` 4. Paste into the **_Variable value_** field. 5. Enter a variable group name, e.g. **_ios_code_signing_**. 6. Make sure the **Secret** option is selected so that the variable can be protected by encryption. 7. Click the **Add** button to add the variable. 8. Repeat steps 2 -7 to create the variable `CM_PROVISIONING_PROFILE` and paste the `base64` encoded value of the provisioning profile file. 9. Add the `CM_CERTIFICATE_PASSWORD` variable, make it **Secret** and add it to the same variable group. 10. Environment variables have to be added to the workflow either individually or as a group. Modify your `codemagic.yaml` file by adding the following: ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: groups: - ios_code_signing ``` However, you can call the variables differently if you reference them correctly in the scripts section. In the case of multiple provisioning profiles, the recommended naming convention is `CM_PROVISIONING_PROFILE_1`, `CM_PROVISIONING_PROFILE_2` etc. As mentioned above, unlike with the Bitrise `Certificate and profile installer` step, you must reference the added files in your scripts section. Follow the detailed documentation [here](../yaml-code-signing/signing-ios/#manual-code-signing) or check out the example below. ```yaml scripts: - name: Set up keychain to be used for code signing using Codemagic CLI 'keychain' command script: keychain initialize - name: Set up Provisioning profiles from environment variables script: | PROFILES_HOME="$HOME/Library/MobileDevice/Provisioning Profiles" mkdir -p "$PROFILES_HOME" PROFILE_PATH="$(mktemp "$PROFILES_HOME"/$(uuidgen).mobileprovision)" echo ${CM_PROVISIONING_PROFILE} | base64 --decode > "$PROFILE_PATH" echo "Saved provisioning profile $PROFILE_PATH" - name: Set up signing certificate script: | echo $CM_CERTIFICATE | base64 --decode > /tmp/certificate.p12 if [ -z ${CM_CERTIFICATE_PASSWORD+x} ]; then # when using a certificate that is not password-protected keychain add-certificates --certificate /tmp/certificate.p12 else # when using a password-protected certificate keychain add-certificates --certificate /tmp/certificate.p12 --certificate-password $CM_CERTIFICATE_PASSWORD fi - name: Set up code signing settings on Xcode project script: xcode-project use-profiles ``` ### Building In Bitrise, the archiving to create the IPA for distribution is done in the `Xcode Archive & Export for iOS` step. Suppose you have followed the above instructions on setting up code signing with the `codemagic.yaml` configuration. In that case, to continue with Codemagic, add a script to your scripts sections to build the application. You can find various build scripts for different types of applications in our [Sample projects](../yaml-quick-start/codemagic-sample-projects/). An example build script for building a Native iOS application: ```yaml scripts: - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" ``` With Codemagic, you can configure which artifacts to receive at the end of the build under the [artifacts section](../yaml/yaml-getting-started/#artifacts). This provides relatively more flexibility in comparison to Bitrise's `Deploy to Bitrise.io` step. For teams on Annual or Enterprise plans, the build artifacts do not expire. The artifacts section can for example be configured in the `codemagic.yaml` as follows: ```yaml artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM ``` ### Deployment Like with Bitrise's `Deploy to App Store Connect`, the use of [App Store Connect API](../yaml-code-signing/signing-ios/#creating-the-app-store-connect-api-key) is required for deploying and publishing. Suppose you have set up automatic code signing with Codemagic. In that case, it is relatively easy to continue with the final step to publish the application to the Apple store as you have already added all the required variables to your `codemagic.yaml` configuration. If not, follow the steps [here](../yaml-code-signing/signing-ios/#creating-the-app-store-connect-api-key). Note that Codemagic only requires the API key, its id, and the issuer id for publishing. The details for setting up deployment and extra parameters can be found [here](../yaml-publishing/app-store-connect/#distribution-to-app-store-connect). The `Deploy to App Store Connect` step in `bitrise.yml` and the publishing in `codemagic.yaml` are relatively similar. However, Codemagic asks you to provide your key id along with your issuer id. **bitrise.yml** ```yaml - deploy-to-itunesconnect-application-loader@1: inputs: - api_issuer: 21d78e2f-b8ad-... - api_key_path: "$BITRISEIO_API_KEY_URL" - connection: api_key ``` **codemagic.yaml** ```yaml publishing: app_store_connect: api_key: $APP_STORE_CONNECT_PRIVATE_KEY key_id: 3MD9688D9K issuer_id: 21d78e2f-b8ad-... ``` ### Option: Flutter WFE Besides using the `codemagic.yaml` file for configuration, it is also possible to use the **Flutter workflow editor** for Flutter applications. Note that you can either create separate workflows for `iOS` and `Android` or build them in the same workflow. ### iOS workflow To build your Flutter iOS project with Flutter workflow editor, navigate to your workflow, and under `Build for platforms`, select `iOS`. Additional arguments can be defined under the `Build` section. #### iOS code signing Like Bitrise, Codemagic allows you to configure manual or automatic code signing. To configure code signing, navigate to **Distribution** > **iOS code signing**. ##### Automatic iOS code signing Setting up automatic code signing once you have already done it on Bitrise is relatively simple. An **App Store Connect API key** is required to manage your certificates and provisioning profiles. The API key allows the service to connect to your developer account. In Bitrise, to connect your Apple Developer account, you must first navigate to your profile settings, set up the connection, explicitly enable it under your application settings and add the `Manage iOS Code Signing` step to your workflow. Codemagic Flutter workflow editor works almost the same. You can find the option to connect your Developer Portal account under user or team settings. Codemagic requires you to provide all of the same data - a name for your API key, the issuer ID, and the key ID, along with a .p8 file downloaded from App Store Connect. A step by step instruction on generating the key can can be found [here](../flutter-code-signing/ios-code-signing/#step-1-creating-an-app-store-api-key-for-codemagic). Then, choose the correct API key in your workflow settings under iOS code signing. Check `Automatic` under `Select code signing method` and select the provisioning profile type under `Provisioning profile type`. If the certificates and profiles do not exist, Codemagic will attempt to generate them. Take note that Apple only allows three distribution certificates per account. Unlike Bitrise's `Manage iOS Code Signing` step, there is no need to add further steps to code sign the application. ##### Manual iOS code signing If you have already set up manual code signing on Bitrise, it is easy to set it up on Codemagic. You can download the files you have uploaded on Bitrise under the applications `Code Signing` tab. After that, navigate to your workflow in Codemagic and upload these under `iOS code signing` once the code signing method is set to `manual`. Like Bitrise, you can upload multiple provisioning profiles, for example, to handle application extensions. However, unlike Bitrise's `Certificate and profile installer` step, no extra step is required with Codemagic. #### Deployment Like with Bitrise's `Deploy to App Store Connect`, the use of [App Store Connect API](../yaml-code-signing/signing-ios/#creating-the-app-store-connect-api-key) is required for deploying and publishing. Suppose you have set up automatic code signing with Codemagic. In that case, it is relatively easy to continue with the final step to publish the application to the Apple store as you have already connected your Apple Developer account. If not, follow the steps described [here](../flutter-code-signing/ios-code-signing/#step-1-creating-an-app-store-api-key-for-codemagic). Once you have connected the account, navigate to **Distribution** > **App Store Connect**, enable publishing and choose the created API key from the dropdown list. ### Android workflow To build your Flutter Android project with Flutter workflow editor, navigate to your workflow, and under `Build for platforms` select `Android`. Additional arguments can be defined under the `Build` section. #### Android code signing If you have already set up Android code signing on Bitrise, you can download your keystore under your workflows `Code Signing` tab. Setting up the code signing in the Codemagic Flutter workflow editor works similarly to Bitrise. In your Codemagic workflow, navigate to **Distribution** > **Android code signing**, upload the keystore and provide the necessary passwords for the key and keystore and the key alias. It is also necessary to configure code signing in your `build.gradle`. Like with Bitrise, it is possible to set it up based on Gradle configuration. You can modify your `build.gradle` to reference and use environment variables as an alternative. Follow the steps for either of the options [here](../flutter-code-signing/android-code-signing/) to set up Android code signing. No extra step like `Android sign` in Bitrise is required. #### Deployment To deploy to Google Play, a service account is required. Creating a service account is the same process in Codemagic and Bitrise. In theory, both platforms could use the same service account. To set up distribution to Google Play on Codemagic, navigate to **Distribution** > **Google Play**. There it is possible to upload the created service account. If you do not have a service account, follow the instructions [here](../knowledge-base/google-services-authentication/). Like Bitrise's `Google Play Deploy` step, Codemagic allows you to modify the track, rollout fraction, and update priority. In addition, you can conveniently configure to submit the build as a draft or choose not to send the changes directly to review. ================================================================================ source: https://docs.codemagic.io/troubleshooting/accessing-builder-machine-via-ssh/ title: Remote access to the build machine description: How to connect to the build machine with SSH or VNC/RDP last_modified: 2026-06-26 ================================================================================ # Remote access to the build machine > How to connect to the build machine with SSH or VNC/RDP You can enable remote access and connect to the virtual machine running your build via SSH or a VNC/RDP client. The **SSH access** allows you to access the build machine through a terminal and run commands on it. This is an excellent option for debugging your builds. You can see the processes running during the CI job, reproduce all commands run during the build, or debug your custom scripts. The **VNC/RDP clients** allow you to access the remote build machine GUI. For example Mac machines may have multiple versions of Xcode and iOS simulators preinstalled, so you can run and test your iOS apps or change Xcode configuration files without owning a Mac yourself. Linux and Mac machines use VNC and Windows machines use RDP for GUI remote access. ## How remote access to the build machines works All virtual machines are located within the private network. In order to allow users to connect to the virtual machine, Codemagic allows a temporary SSH or VNC/RDP access through the public gateway using a unique SSH key or user credentials that are generated before each build. The unique key and user credentials are valid for the duration of the build only and are revoked after the build is finished. For security reasons, remote access has to be enabled manually for each new build from Codemagic UI. ## Setting up an SSH connection to the virtual machine 1. Click **Start new build** button in Codemagic UI. 2. Check **Enable SSH/VNC access** checkbox in the **Start new build modal**. 3. While the build is running, click **Explore build machine via SSH or VNC/RDP client** above the build steps to see the command and instructions for establishing SSH access. 4. Copy the command to the clipboard manually or using the Copy button next to the command. 5. Run the generated script in the terminal before the build finishes. An SSH session to the machine running the build will be opened in your terminal. If you don't run the script before the build finishes, the unique SSH key expires and can't be used anymore. A new script will be generated every time you run the build, so previous scripts cannot be reused. > > **Note:** The script for establishing SSH connection works natively on Linux and macOS but requires additional software like Git-bash on Windows. > ## Setting up VNC/RDP connection to the virtual machine 1. While the build is running, click **Explore build machine via SSH or VNC/RDP client** above the build steps to see the command and instructions for establishing VNC or RDP access, depending on the platform your build is running on. 2. Use the given **Host**, **Port**, **Username** and **Password** on your VNC/RDP client to establish the connection. > > **Tip:** You can download VNC Viewer for Windows [here](https://www.realvnc.com/en/connect/download/viewer/windows/). > > If you are on macOS and need to connect to a Windows machine using RDP, we recommend using the official Microsoft Remote Desktop client for macOS which can be installed from [Mac App Store](https://apps.apple.com/us/app/microsoft-remote-desktop/id1295203466) > > When using VNC Viewer or Microsoft Remote Desktop, make sure to add the values for **Host** and **Port** into the address field in this format: `:` (for example, `192.159.66.83:16543`). > New credentials will be generated every time you run the build, so previous credentials cannot be reused. ## Using the remote build machine You can use the remote session to reproduce all commands run during the build, rerun the build with a different configuration, or set up platform-specific files, e.g. CocoaPods. * To access the clone of your project on the VM, run `cd $CM_BUILD_DIR` in the terminal. * The command `printenv` prints all the environment variables exported during the build on Linux/macOS. Use `dir env:` on Windows to achieve the same in PowerShell. You can see some of Codemagic built-in environment variables explained [here](../building/environment-variables/#codemagic-read-only-environment-variables). * The `sudo` command is available on Linux/macOS so you can execute all commands with root privileges. PowerShell on Windows machines is already running in privileged mode. ## Remote access session time limit The build virtual machine will remain available for an SSH or VNC/RDP connection for 10 minutes after the build finishes running. Once connected, the debug session remains active until build is cancelled or the maximum build duration limit is reached (60 minutes by default). ## Useful tips for debugging * You can access your project on the builder machine by running `cd $CM_BUILD_DIR` * If you encounter an error during the build, a good way to get started is by digging into the build logs on Codemagic and rerunning the first failed command. * The command `printenv` prints all the environment variables exported during the build on Linux/macOS. Use `dir env:` on Windows to achieve the same in PowerShell. See [environment variables](../building/environment-variables/) for an explanation of built-in environment variables. * The `sudo` command is available to execute any commands with root privileges on Linux/macOS. PowerShell on Windows machines is already running in privileged mode. * During an active SSH session, you can rerun the build with a different configuration right from the terminal. * Before terminating the connection, you may want to copy-paste the contents of the terminal window to keep a record of your actions on the builder machine. ### Making Configuration Changes * It is very easy to save any configuration changes that you make on Codemagic VM. The repository is cloned from your GitHub/GitLab/Bitbucket account, so you can directly commit the changes using git and push them to your account. * In order to push the changes to your repo, you need to authenticate yourself in your git provider. This is necessary because Codemagic VM only has read access to the GitHub repo. * Example, in order to authenticate with GitHub, you need to use your GitHub personal access token. See how to generate the token from [here](https://github.com/settings/tokens). You can run these commands from the terminal: ```bash cd folder_name .... .... gh auth login --with-token YOUR_GITHUB_PAT_TOKEN git add . git commit -m "Added configuration changes" git push ``` ================================================================================ source: https://docs.codemagic.io/flutter-testing/running-automated-tests/ title: Running automated tests description: How to run automated tests in builds configured with the Flutter workflow editor last_modified: 2023-07-11 ================================================================================ # Running automated tests > How to run automated tests in builds configured with the Flutter workflow editor Codemagic supports running **unit**, **integration** and **widget** tests as well as static code analysis with [**flutter analyze**](./static-code-analysis). When testing is enabled, tests are run automatically every time your project is built. You can configure the test settings in **App settings > Tests**. ### Detecting tests During the first build of your app, Codemagic will scan the repository's content and automatically detect the tests according to the project structure. The expected locations of the tests are as follows: Unit and widget tests: `project_root/test` Integration tests (Flutter Driver tests): `project_root/test_driver` > > > **Note:** If your Flutter project is in a subdirectory of the repository, Codemagic cannot detect your tests automatically unless you add at least one test file in the `project_root/test` or `project_root/test_driver` folder. > > ### Running Flutter Driver tests There are several options for running integration tests during the build. You can select one option per workflow: - iOS simulator (selected by default) - Android emulator - Chrome Devices available on the machine are: ``` emulator • emulator • Google • android apple_ios_simulator • iOS Simulator • Apple • ios Chrome (web) • chrome • web-javascript • Google Chrome ``` For iOS and Android, it's recommended to launch the desired emulator before the tests start: ```bash flutter emulators --launch ios ``` or ```bash flutter emulators --launch emulator ``` > > > **Tip**: You can set up separate [workflows](../flutter/creating-workflows/) to run tests both on iOS and Android. > > #### Mobile The recommended approach to running integration tests is to use `flutter test` and the `integration_test` dependency. To do so, navigate to **App settings > Tests > Integration and unit tests** and under **Flutter drive arguments** define the following: ```bash test integration_test ``` To run only a specific test, the path has to be specified: ```bash test integration_test/app_test.dart ``` #### Web However, the above approach is not suitable for integration tests for web using `chromedriver`, and the following arguments are recommended instead: ```bash drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart ``` > > > Note that for this approach, creating the `test_driver` folder with the `integration_test.dart` file beforehand is required, as per [Flutter documentation](https://docs.flutter.dev/cookbook/testing/integration/introduction#5b-web). > > ### Stop build if tests or analysis fail If you check **Stop build if tests or analysis fail**, the build will stop after finishing all the enabled tests or analysis runs when any of them fail. Such builds will have the status "failed". ### Running tests in Firebase Test Lab Integration tests can also be run on real devices in Firebase Test Lab when using the [integration_test](https://github.com/flutter/flutter/tree/master/packages/integration_test) package and custom scripts in Codemagic. See a detailed guide on how to set up testing in Firebase Test Lab [here](https://blog.codemagic.io/codemagic-flutter-integration-tests-firebase-test-lab/). ================================================================================ source: https://docs.codemagic.io/yaml-testing/testing/ title: Running tests description: How to run tests with codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Running tests > How to run tests with codemagic.yaml Test scripts are added under `scripts` in the [overall architecture](../getting-started/yaml#template), before the build commands. You can display test results visually in the build overview if you use an expanded form of the script in `codemagic.yaml`. Just include the `test_report` field with a glob pattern matching the test result file location. We support every test runner, including GoTest, RSpec, PHPUnit, Karma, PyTest, ESLint, Cucumber, ExUnit, Mocha, CargoTest, and JUnit. If your test runner can export [Junit XML](https://llg.cubic.org/docs/junit/) and `.JSON` for Flutter's `--machine` report test results, Codemagic can use it. For instructions on testing your app on real devices in Firebase Test Lab, refer [here](./firebase-test-lab). ## Flutter unit tests To run Flutter unit tests, simply add the `flutter test` command to your scripts section. ```yaml scripts: - name: Unit tests script: | mkdir -p test-results flutter test --machine > test-results/flutter.json test_report: test-results/flutter.json ``` **Tip:** you can display Flutter test results visually in the build overview if you use the expanded form of the script in codemagic.yaml. Just include the `test_report` field with a glob pattern matching the test result file location: ## Flutter integration tests The `integration_test` dependency allows you to run integration tests on a real device or emulator. Android application tests can be run on an Android emulator, iOS application tests can be run on an iOS simulator, and web application tests can be run on a web browser driver. **Tip:** It is possible to generate machine readable output for integration tests using the `--machine` flag; hence the results can be displayed in the UI. Just include the `test_report` field with a glob pattern matching the test result file location: ```yaml scripts: - name: Integration tests script: | mkdir -p test-results flutter -d emulator-5554 test --machine > test-results/flutter.json integration_test # for iOS use: -d iPhone test_report: test-results/flutter.json ``` To run integration tests for web, it is possible to use `chromedriver`. Take note that for running tests on web, it is necessary to provide the `--driver` and `--target` arguments, and machine-readable output is unavailable. ```yaml scripts: - name: Integration tests script: | flutter config --enable-web chromedriver --port=4444 & flutter -d chrome drive --driver=test_driver/integration_driver.dart --target=integration_test/app_test.dart ``` ### Running application tests on a mobile simulator/emulator ### Option: Android > > Due to limitations by Apple silicon, the Apple Virtualization API doesn’t support nested virtualization required for Android emulators. To use Android emulators in macOS workflows, please use third-party service integrations such as emulator.wtf, Katalon, Firebase, or AWS Device Farm. > For the Android emulator you can launch and run your tests as follows: ```yaml scripts: - name: Emulator tests script: | flutter config --enable-web # The ampersand is used to run the emulator in the background without blocking the next command: flutter emulators --launch emulator & # adb wait-for-device is used to wait for the emulator to finish loading: adb wait-for-device flutter -d emulator-5554 test integration_test ``` ### Option: iOS You can launch the iOS simulator and run tests as follows: ```yaml scripts: - name: Emulator tests script: | flutter emulators --launch apple_ios_simulator flutter -d iPhone test integration_test ``` You can launch a specific iOS simulator and run tests on the simulator using ‘simctl’ which is a binary to interact with iOS simulators from the command line, as follows: ```yaml scripts: - name: Emulator tests script: | # this command will will shutdown the existing simulators to save on resources. xcrun simctl shutdown all # # create new simulator with specified configuration, you can run # 'xcrun simctl list' - to check the list of available simulator configurations TEST_DEVICE=$(xcrun simctl create test-device com.apple.CoreSimulator.SimDeviceType.iPhone-16 com.apple.CoreSimulator.SimRuntime.iOS-18-5) # # boot the newly created simulator xcrun simctl boot $TEST_DEVICE # # run the actual test command flutter -d $TEST_DEVICE test integration_test ``` ### Running web application tests on a web browser driver ### Option: Chrome ```yaml scripts: - name: 'Flutter integration test for web' script: | chromedriver --port=4444 & flutter config --enable-web flutter drive --driver=test_driver/integration_driver.dart --target=integration_test/app_test.dart -d web-server --release --browser-name chrome ``` ### Option: Safari ```yaml scripts: - name: 'Flutter integration test for web' script: | sudo safaridriver --enable safaridriver --port 4444 & flutter config --enable-web flutter drive --driver=test_driver/integration_driver.dart --target=integration_test/app_test.dart -d web-server --release --browser-name safari ``` ## React Native Unit Tests using Jest This basic example illustrates how to use Jest tests defined in the `package.json` file as follows: ```json // package.json "scripts": { "test": "jest" }, "jest": { "preset": "jest-expo", "setupFiles": ["/testing/jest-setup.js"] } ``` In the root directory of the project, create a new file named `jest.config.js` with the following content: ```javascript module.exports = { preset: 'react-native', setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'], } ``` The `preset` is used as a base for Jest’s configuration and should point to an npm module that has a `jest-preset.json` or `jest-preset.js` file at the root. The `setUpFilesAfterEnv` specifies a list of paths to modules that run some code to configure or set up the testing framework before each test file in the suite is executed. To execute the tests, use the following script in your `codemagic.yaml` file: ```yaml scripts: - name: 'Flutter integration test for web' script: | npm test # or: yarn test ``` In React Native, 3rd party modules are oftentimes published as **untranspiled**. Since all files inside `node_modules` are not transformed by default, Jest will not understand the code in these modules, resulting in syntax errors. To overcome this, you need to use `transformIgnorePatterns` to allow transpiling such modules. In such cases, modify your `package.json` as follows: ```json "jest": { "preset": "jest-expo", "transformIgnorePatterns": [ "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*)" ] } ``` ## React Native Integration Tests using Appium and Emulator [Appium](https://appium.io/) is an open-source testing automation framework for testing cross-platform and mobile applications. You can use **Appium** and **WebDriverIO** with React Native thanks to its out-of-the-box support. Before running tests in Codemagic, you need to install and setup **WebDriverIO** in your project root directory. Run the following command **on your local machine** and provide input to a series of questions: ```bash npx wdio config ``` After answering a series of questions, a file named `wdio.conf` will be generated inside the `tests` directory. Edit the content of that file as follows to enable WebDriverIO to work with Appium and run tests on Android Emulator: ```javascript exports.config = { services: ['appium'], port: 4723, runner: 'local', specs: [ './tests/specs/**/*.js' ], capabilities: [{ maxInstances: 1, browserName: '', appiumVersion: '2.0.0', platformName: 'Android', platformVersion: '', // Specify your emulator details deviceName: '', app: '', automationName: 'UiAutomator2' }], logLevel: 'trace', bail: 0, waitforTimeout: 10000, connectionRetryTimeout: 90000, connectionRetryCount: 3, framework: 'mocha', reporters: ['spec'], mochaOpts: { ui: 'bdd' timeout: 60000 } } ``` To execute the tests, use the following scripts in your `codemagic.yaml` file: ```yaml scripts: - name: Install npm dependencies # Add Appium and WebDriverIO dependencies script: npm install && npm install -g appium && npm install --save webdriverio @wdio/cli - name: Launch emulator # Insert before the build command script: | react-native run-android & adb wait-for-device - name: Launch Appium script: appium - name: Run WebDriver test suite script: npx wdio ./wdio.conf.js ... ``` ## Native iOS To execute the tests, use the following scripts in your `codemagic.yaml` file: ```yaml scripts: - name: iOS test script: | xcode-project run-tests \ --workspace MyAwesomeApp.xcworkspace \ --scheme MyAwesomeApp \ --device "iPhone 16" test_report: build/ios/test/*.xml ``` Please check [Codemagic CLI tools documentation](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/run-tests.md#run-tests) to learn more about more optional arguments to `xcode-project run-tests`. ## Native macOS > > **Note:** macOS UI Testing is only supported on Xcode 13 images and above as it requires System Integrity Protection (SIP) to be disabled in order to access the accessibility permissions. Older images with Xcode 12 and below do not have SIP disabled and are unsuitable for UI testing macOS apps. > To execute the tests, use the following scripts in your `codemagic.yaml` file: ```yaml scripts: - name: macOS test script: | xcode-project run-tests \ --project MyAwesomeApp.xcodeproj \ --scheme MyAwesomeApp \ --sdk macosx \ --test-xcargs "CODE_SIGNING_ALLOWED='no'" \ --output-dir build/macos/test test_report: build/macos/test/*.xml ``` For macOS tests, no destination is specified. Please check [Codemagic CLI tools documentation](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/run-tests.md#run-tests) to learn more about optional arguments to `xcode-project run-tests`. ## Native Android For non-UI tests or unit tests: ```yaml scripts: - name: Test script: ./gradlew test test_report: app/build/test-results/**/*.xml ``` For UI tests (also known as instrumented tests): ```yaml scripts: - name: Launch emulator script: | cd $ANDROID_HOME/tools emulator -avd emulator & adb wait-for-device - name: Test script: | set -e ./gradlew connectedAndroidTest adb logcat -d > emulator.log test_report: app/build/outputs/androidTest-results/connected/*.xml ``` **Tip**: you can save the emulator log with the `adb logcat -d > emulator.log` command ================================================================================ source: https://docs.codemagic.io/flutter-running-builds/scheduling/ title: Scheduling builds with Flutter workflow editor description: Create schedules to run builds at regular intervals using Flutter workflow editor last_modified: 2022-11-03 ================================================================================ # Scheduling builds with Flutter workflow editor > Create schedules to run builds at regular intervals using Flutter workflow editor You can schedule Codemagic to automatically build your app on certain days and times. This way, your QA can start the day with the latest version of the app, or you can configure a workflow to run the long test suites at a convenient time and only run fast tests with builds triggered by commits to the repo. ## Setting up scheduled builds 1. Open your application in Codemagic. 2. Switch to the **Scheduled builds** tab and click the **Add new schedule** button. 3. Select the **Branch** and the **Workflow** to run. 4. In the **Schedule for** field, select the days you want to run the build. 5. Specify the start time (UTC) of the build by selecting a value from the **At** field. Note that the build may be delayed up to 15 minutes during peak hours. 6. Click **Add schedule** to save the schedule. Saved schedules for each app are displayed in the **Scheduled builds** section on the right sidebar in app settings. If you no longer need the schedule, you can delete it by hovering on the schedule and clicking the trash bin icon. Builds that are triggered from a schedule are marked with "Schedule" as the trigger in the build overview page. ================================================================================ source: https://docs.codemagic.io/yaml-running-builds/scheduling/ title: Scheduling builds with codemagic.yaml description: Create schedules to run builds at regular intervals last_modified: 2026-06-26 ================================================================================ # Scheduling builds with codemagic.yaml > Create schedules to run builds at regular intervals You can schedule Codemagic to automatically build your app on certain days and times. This way, your QA can start the day with the latest version of the app, or you can configure a workflow to run the long test suites at a convenient time and only run fast tests with builds triggered by commits to the repo. ## Setting up scheduled builds 1. Open your application in Codemagic. 2. Switch to the **Scheduled builds** tab and click the **Add new schedule** button. 3. Select the **Branch** and the **Workflow** to run. 4. In the **Schedule for** field, select the days you want to run the build. 5. Specify the start time (UTC) of the build by selecting a value from the **At** field. Note that the build may be delayed up to 15 minutes during peak hours. 6. Click **Add schedule** to save the schedule. Saved schedules for each app are displayed in the **Scheduled builds** section on the right sidebar in app settings. If you no longer need the schedule, you can delete it by hovering on the schedule and clicking the trash bin icon. Builds that are triggered from a schedule are marked with "Schedule" as the trigger in the build overview page. ================================================================================ source: https://docs.codemagic.io/yaml-code-signing/signing-ios/ title: Signing iOS apps description: How to set up iOS code signing in codemagic.yaml last_modified: 2026-08-26 ================================================================================ # Signing iOS apps > How to set up iOS code signing in codemagic.yaml All iOS applications have to be digitally signed before they can be installed on real devices or made available to the public. > > **Note:** This guide covers iOS code signing using Codemagic's **Code Signing Identities** — uploading certificates and provisioning profiles to the Codemagic UI once and reference them in `codemagic.yaml`. > > If you prefer to use CLI tools in your build scripts to manage code signing resources, see [Alternative code signing methods](../yaml-code-signing/alternative-code-signing-methods). >
{{< youtube idRJZxVafY0 >}} ## Managing and uploading files Team admin permissions are required to upload and edit files under the **Code signing identities** section. However, all team members can view the file info for any of the uploaded files. ### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > ### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. ### Adding the Code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. ### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > ## Referencing certificates and profiles in codemagic.yaml Codemagic provides two means of fetching the required certificates and provisioning profiles during the build with the use of `codemagic.yaml`. Fetching can either be configured by specifying the distribution type and bundle identifier, or for more advanced use-cases, individual files can be fetched by their reference names. ### Fetching files by distribution type and bundle identifier To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` Note that when using the fields `distribution_type` and `bundle_identifier`, it is not allowed to configure `provisioning_profiles` and `certificates` fields. > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ### Fetching specific files by reference names For a more advanced configuration, it is possible to pick out specific uploaded profiles and certificates for Codemagic to fetch during the build. To do so, list the references of the uploaded files under the `provisioning_profiles` and `certificates` fields, respectively. Note that when fetching individual files, the fields `distribution_type` and `bundle_identifier` are not allowed. Steps `Initialize keychain` & `Add certificates to keychain` scripts are not required as those are automatically fetched during the build process. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: provisioning_profiles: - profile_reference # - ... certificates: - certificate_reference # - ... ``` Codemagic saves the files to the following locations on the build machine: - Profiles: `~/Library/MobileDevice/Provisioning Profiles` - Certificates: `~/Library/MobileDevice/Certificates` It is additionally possible to include names for environment variables that will point to the file paths on the build machine. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: provisioning_profiles: - profile: profile_reference environment_variable: THIS_PROFILE_PATH_ON_DISK # - ... certificates: - certificate: certificate_reference environment_variable: THIS_CERTIFICATE_PATH_ON_DISK # - ... ``` ## Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > ================================================================================ source: https://docs.codemagic.io/specs-linux/ubuntu-24.04/ title: Ubuntu 24.04 description: A list of tools available out-of-the-box on Codemagic Linux Ubuntu 24.04 last_modified: 2026-02-27 ================================================================================ # Ubuntu 24.04 > A list of tools available out-of-the-box on Codemagic Linux Ubuntu 24.04 ## Hardware - Linux X2 virtual machine: `8 vCPUs, 32 GB memory` - Linux X4 virtual machine: `16 vCPUs, 64 GB memory` ## System - System version `Ubuntu 24.04.4 LTS` - Kernel version `6.17.0-1008-gcp` - Disk `155GB (Free Space: 93GB)` ## Android Studio > Android Studio `2024.3.1` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;34.0.0 | 34.0.0 | Android SDK Build-Tools 34 | build-tools/34.0.0 build-tools;35.0.0 | 35.0.0 | Android SDK Build-Tools 35 | build-tools/35.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.31.5 | 3.31.5 | CMake 3.31.5 | cmake/3.31.5 cmake;3.31.6 | 3.31.6 | CMake 3.31.6 | cmake/3.31.6 cmdline-tools;latest | 19.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest-2 emulator | 35.5.8 | Android Emulator | emulator extras;google;auto | 2.0 | Android Auto Desktop Head Unit Emulator | extras/google/auto extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;simulators | 1 | Android Auto API Simulators | extras/google/simulators extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;22.0.7026061 | 22.0.7026061 | NDK (Side by side) 22.0.7026061 | ndk/22.0.7026061 ndk;25.2.9519653 | 25.2.9519653 | NDK (Side by side) 25.2.9519653 | ndk/25.2.9519653 ndk;29.0.13113456 | 29.0.13113456 rc1 | NDK (Side by side) 29.0.13113456 | ndk/29.0.13113456 platform-tools | 35.0.2 | Android SDK Platform-Tools | platform-tools platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36 | 1 | Android SDK Platform 36 | platforms/android-36 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-33 | 1 | Sources for Android 33 | sources/android-33 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36 | 1 | Sources for Android 36 | sources/android-36 system-images;android-34;google_apis_playstore;x86_64 | 14 | Google Play Intel x86_64 Atom System Image | system-images/android-34/google_apis_playstore/x86_64 system-images;android-35;google_apis_playstore;x86_64 | 9 | Google Play Intel x86_64 Atom System Image | system-images/android-35/google_apis_playstore/x86_64 system-images;android-36;google_apis;x86_64 | 5 | Google APIs Intel x86_64 Atom System Image | system-images/android-36/google_apis/x86_64 system-images;android-36;google_apis_playstore;x86_64 | 5 | Google Play Intel x86_64 Atom System Image | system-images/android-36/google_apis_playstore/x86_64 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 22.0.7026061 | `/usr/local/share/android-sdk/ndk/22.0.7026061` | | 29.0.13113456 | `/usr/local/share/android-sdk/ndk/29.0.13113456` | | 25.2.9519653 | `/usr/local/share/android-sdk/ndk/25.2.9519653` | ## Android emulators > AVD Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/avdmanager` **Available emulators** | **Name** | **Device** | **Based On** | |------|--------|----------| | emulator | pixel_4 (Google) | Android 14.0 ("UpsideDownCake") Tag/ABI: google_apis_playstore/x86_64 | | emulator-35 | pixel_4 (Google) | Android API 35 Tag/ABI: google_apis_playstore/x86_64 | | emulator-36 | pixel_6a (Google) | Android API 36 Tag/ABI: google_apis_playstore/x86_64 | {{< collapsible title="Full details" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/avdmanager list avd Available Android Virtual Devices: Name: emulator Device: pixel_4 (Google) Path: /home/builder/.config/.android/avd/emulator.avd Target: Google Play (Google Inc.) Based on: Android 14.0 ("UpsideDownCake") Tag/ABI: google_apis_playstore/x86_64 Skin: pixel_4 Sdcard: 512M --------- Name: emulator-35 Device: pixel_4 (Google) Path: /home/builder/.config/.android/avd/emulator-35.avd Target: Google Play (Google Inc.) Based on: Android API 35 Tag/ABI: google_apis_playstore/x86_64 Skin: pixel_4 Sdcard: 512M --------- Name: emulator-36 Device: pixel_6a (Google) Path: /home/builder/.config/.android/avd/emulator-36.avd Target: Google Play (Google Inc.) Based on: Android API 36 Tag/ABI: google_apis_playstore/x86_64 Skin: pixel_6a Sdcard: 512M ``` {{< /collapsible >}} ## Java versions | **Version** | **Path** | |-------------|----------| | 11 | `/usr/lib/jvm/java-1.11.0-openjdk-amd64` | | **17** (default) | `/usr/lib/jvm/java-1.17.0-openjdk-amd64` | | 21 | `/usr/lib/jvm/java-1.21.0-openjdk-amd64` | | 8 | `/usr/lib/jvm/java-1.8.0-openjdk-amd64` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.13 | `/home/builder/programs/gradle-8.13` | | 8.11.1 | `/home/builder/programs/gradle-8.11.1` | | 8.1.1 | `/home/builder/programs/gradle-8.1.1` | | 7.6 | `/home/builder/programs/gradle-7.6` | | 7.3.1 | `/home/builder/programs/gradle-7.3.1` | ## Other pre-installed tools - aws `2.33.29` - azure-cli `2.83.0` - curl `8.5.0` - docker `29.2.1` - ew-cli `1.2.0` - fastlane `2.227.0` - firebase `13.34.0` - gem `3.6.2` - gh `2.45.0` - git `2.43.0` - Google Cloud SDK `558.0.0` - gsutil `5.35` - ionic `7.2.0` - jq `1.7` - ktlint `1.5.0` - node `22.14.0` - npm `11.2.0` - OpenSSH `9.6p1` - python `3.12.5` - ruby `3.4.2` - snapcraft `8.14.1` - sudo `1.9.15p5` - tar `1.35` - unzip `6.00` - wget `1.21.4` - yarn `4.12.0` - yq `4.49.2` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/yaml-basic-configuration/yaml-getting-started/ title: Using codemagic.yaml description: Configure all your workflows in a single file last_modified: 2026-06-18 ================================================================================ # Using codemagic.yaml > Configure all your workflows in a single file `codemagic.yaml` is a highly customizable configuration file for setting up your CI/CD pipeline with Codemagic. Configure all your workflows in a single file and commit the file to version control. {{< youtube er7hRWhW0B0 >}} ## Building with YAML In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. When detected in the repository, `codemagic.yaml` is automatically used for configuring builds triggered in response to the events defined in the file, provided that a [webhook](../building/webhooks) is set up. Builds can also be started manually by clicking **Start new build** in Codemagic and selecting the branch and workflow to build in the **Specify build configuration** popup. > > > Check out the [**cheatsheet**](/codemagic-yaml-cheatsheet.html) we have created to help you when using Codemagic YAML. > > ## Syntax You can readily commit `codemagic.yaml` with the following content to test it out: ```yaml workflows: hello-world: name: Hello world workflow scripts: - echo "Hello World!" ``` The scripts in the `scripts` section will be run right after the repository is cloned. `codemagic.yaml` follows the traditional [YAML syntax](https://yaml.org/). Here are a few tips and tricks on how to better structure the file. > > **Note:** You can use the Codemagic JSON schema to validate `codemagic.yaml` in your IDE. See how to set it up [here](../knowledge-base/validate-yaml/). > ### Section names For easier reading of the configuration file and build logs, you can divide the scripts into meaningful sections with descriptive names. ```yaml scripts: - name: Build for iOS # Name of the section script: flutter build ios # The script(s) to be run in that section ``` ### Reusing sections If a particular section would be reused multiple times in the file, e.g. in each workflow, you can avoid repetitions by using **anchors**. This is also convenient when you need to make changes to the code, as you would have to edit it in just one place. Define the section to be reused by adding `&` in front of it. ```yaml scripts: - &increment_build_number # Defined section name: Increment build number script: agvtool new-version -all $(($PROJECT_BUILD_NUMBER +1)) ``` Reuse the defined section elsewhere by adding a `*` in front of it. ```yaml scripts: - script1 - *increment_build_number # Reused section - script3 ``` You can also define the reusable section under `definitions` by adding `&` in front of the section name. ```yaml definitions: env_versions: &env_versions xcode: latest cocoapods: default ``` Expand the defined section elsewhere by using aliased mapping (`<<`) and adding a `*` in front of the section name. ```yaml workflows: ios-release: name: iOS release environment: << : *env_versions ``` Here's a [sample](https://github.com/codemagic-ci-cd/codemagic-sample-projects/blob/main/yaml/yaml_anchors_aliases_sample/codemagic.yaml) `codemagic.yaml` that extensively uses anchors, aliases, and aliased mappings to reuse the sections in different workflows. ## Template This is the skeleton structure of `codemagic.yaml`. Each section, along with the configuration options, is described in more detail ```yaml workflows: my-workflow: name: My workflow name labels: - QA - ${TENANT_NAME} instance_type: mac_mini_m2 max_build_duration: 60 inputs: # more information about build inputs:https://docs.codemagic.io/knowledge-codemagic/build-inputs/ name: # input ID description: Input description default: Codemagic environment: groups: - group_name vars: PUBLIC_ENV_VAR: "value here" flutter: stable xcode: latest cache: cache_paths: - ~/.pub-cache triggering: events: - push branch_patterns: - pattern: '*' include: true source: true cancel_previous_builds: false scripts: - echo "Hello, ${{ inputs.name }}" - ... artifacts: - build/**/outputs/bundle/**/*.aab publishing: email: recipients: - name@example.com scripts: - echo 'Post-publish script' ``` ### Workflows You can use `codemagic.yaml` to define several workflows for building a project. Each workflow describes the entire build pipeline from triggers to publishing. For example, you may want to have separate workflows for developing, testing, and publishing the app. ```yaml workflows: my-workflow: # workflow ID name: My workflow name # workflow name displayed in Codemagic UI instance_type: mac_mini_m2 # machine instance type max_build_duration: 60 # build duration in minutes (min 1, max 120) environment: cache: triggering: scripts: artifacts: publishing: ``` The main sections in each workflow are described below. ### Instance type `instance_type:` specifies the [build machine type](../specs/machine-type) to use for the build. The supported build machines are: | **Instance Type** | **Build Machine** | | ------------- | ----------------- | | `mac_mini_m2` | Apple silicon M2 Mac mini | | `mac_mini_m4` | Apple silicon M4 Mac mini | | `linux_x2` | Linux X2 | | `linux_x4` | Linux X4 | | `windows_x2` | Windows |
> > **Note:** Instance types `mac_mini_m4`, `linux_x2`, `linux_x4`, and `windows_x2` are only available for teams and users with [billing enabled](../billing/billing/). > ### Build inputs Build inputs are parameters that allow you to customize your build configurations right before starting a new build without hardcoding them in **codemagic.yaml**. For example, build inputs can be used to determine whether to build the workflow for test or release purposes or which Xcode version to use, etc. More information about how to configure build inputs and examples can be found [here](https://docs.codemagic.io/knowledge-codemagic/build-inputs/). ### Environment `environment:` section specifies the environment variables and their respective group and build machine software versions.
> > **Note:** Environment variables must belong to a group if environment variables are defined in the Codemagic app settings. > #### Environment variable groups The snippet below shows how to import [environment variable groups](../building/environment-variable-groups/) defined in the team settings and application settings and also how to define them in the configuration file. Environment variables typically include credentials and API keys required for [code signing](../code-signing-yaml/signing). Click **Secret** to encrypt the values. Note that binary files have to be [`base64 encoded`](../yaml/configuring-environment-variables/#storing-sensitive-valuesfiles) locally before they can be saved to environment variables and decoded during the build. ```yaml environment: groups: # Define your environment variables groups here - keystore_credentials - app_store_credentials - manual_cert_credentials - firebase_credentials - other # Android code signing - Add the keystore_credentials group environment variables in Codemagic UI # (either in Application/Team variables) # CM_KEYSTORE # CM_KEYSTORE_PASSWORD # CM_KEY_PASSWORD # CM_KEY_ALIAS # iOS automatic code signing - Add the app_store_credentials group environment variables # in Codemagic UI (either in Application/Team variables) # APP_STORE_CONNECT_ISSUER_ID # APP_STORE_CONNECT_KEY_IDENTIFIER # APP_STORE_CONNECT_PRIVATE_KEY # CERTIFICATE_PRIVATE_KEY # iOS manual code signing - Add the manual_cert_credentials group environment variables # in Codemagic UI (either in Application/Team variables) # CM_CERTIFICATE # CM_CERTIFICATE_PASSWORD # CM_PROVISIONING_PROFILE # Firebase secrets - Add the firebase_credentials group environment variables in Codemagic UI # (either in Application/Team variables # ANDROID_FIREBASE_SECRET # IOS_FIREBASE_SECRET # Add the other group environment variables in Codemagic UI # (either in Application/Team variables # SSH_KEY_GITHUB # defining an ssh key used to download private dependencies # CREDENTIALS # publishing a package to pub.dev # APP_CENTER_TOKEN # publishing an application to App Center ``` > > **Tip:** Store related variables in the same group so they can be imported to codemagic.yaml workflow in a single step. >

> > **Note:** If a group of variables is reusable for various applications, it can be defined in [Global variables and secrets](../variables/environment-variable-groups/#global-variables-and-secrets) in **Team settings** for easier access. > #### Workflow environment variables The snippet below shows how to define workflow specific public environment variables. ```yaml environment: vars: # Define your environment variables here PUBLIC_ENV_VAR: "value here" ``` #### Build machine and software versions The snippet below shows how to specify the versions of Flutter, Xcode, Ubuntu, CocoaPods, Node, npm, ndk, Java and Ruby used in the build. ```yaml environment: flutter: stable # Define the channel name, version (e.g. v1.13.4), or fvm for Flutter Version Management xcode: latest # Define latest, edge or version (e.g. 11.2) ubuntu: 24.04 # Define the OS version for Linux builds (e.g. 24.04) cocoapods: default # Define default or version node: lts # Define default, latest, current, lts, carbon (or another stream), nightly or version npm: default # Define default, latest, next, lts or version ndk: r27 # Define default or revision if supported (e.g. r27) or full version (e.g. 27.0.12077973) java: 17 # Define default, or platform version (e.g. 17) ruby: default # Define default or version (macOS only) ``` Currently, only the above-mentioned software versions can be customized via the environment section in the yaml file. If a different software version needs to be customized, then it may require a different approach depending upon use cases. > > **Note:** The Xcode version defines type of macOS build machine used for the build (even if you're building Android). See the default software versions on Codemagic macOS build machines [here.](../specs/versions-macos/) >

> > **Note**: Using a non-default version of Ruby for macOS builds will increase the time of your `Preparing build machine` step significantly. > #### Environment section example You can freely use all of the above features of environment section in conjunction. ```yaml environment: vars: # Define your public environment variables here PUBLIC_ENV_VAR: "value here" groups: # Import UI defined environment variable groups(either in Application/Team variables) here - staging xcode: latest # Define latest, edge or version (e.g. 11.2) flutter: stable # Define the channel name or version (e.g. v1.13.4) ``` ### Cache `cache:` defines the paths to be cached and stored on Codemagic. For example, you may consider caching the following paths: | **Path** | **Description** | | ------------------------------------------- | ------------------------------------------------ | | `$FLUTTER_ROOT/.pub-cache` | Dart cache | | `$HOME/.gradle/caches` | Gradle cache. Note: do not cache `$HOME/.gradle` | | `$HOME/Library/Caches/CocoaPods` | CocoaPods cache | | `$CM_BUILD_DIR`/node_modules | Node cache |
> > > **Note:** Caching `$HOME/Library/Developer/Xcode/DerivedData` won't help speed up iOS builds. > > ```yaml cache: cache_paths: - ~/.gradle/caches - ... ``` You can read more about configuring caching for your builds and its usage limits [here](https://docs.codemagic.io/knowledge-codemagic/caching/) > > **Note:** Codemagic doesn't support caching symlinks. > > > **Note:** Each workflow has its own cache. It is possible to view the cache for each workflow under the **Caching** tab in the Codemagic UI. > ### Triggering > > **Note:** For automatic build triggering, it is required to configure a webhook in the repository. In your app settings, click **Create webhook** on the right sidebar under **Webhooks** to have Codemagic create a webhook. If you need to set up a webhook manually, refer [here](../building/webhooks) for details. > `triggering:` defines the events for automatic build triggering and watched branches. If no events are defined, you can start builds only manually. A branch pattern can match the name of a particular branch, or you can use wildcard symbols to create a pattern that matches several branches. Note that for **pull request builds**, you have to specify whether the watched branch is the source or the target of the pull request. To avoid running builds on outdated commits, you can set `cancel_previous_builds` to automatically cancel all ongoing and queued builds triggered by webhooks on push or pull request commit when a more recent build has been triggered for the same branch. ```yaml triggering: events: # List the events that trigger builds - push - pull_request - pull_request_labeled #GitHub only - tag branch_patterns: # Include or exclude watched branches - pattern: '*' include: true source: true # Applicable only to Pull Request triggers to determine if pattern is for source or target branch - pattern: excluded-target include: false source: false - pattern: included-source include: true source: true tag_patterns: # Include or exclude watched tag labels - pattern: '*' include: true - pattern: excluded-tag include: false - pattern: included-tag include: true cancel_previous_builds: false # Set to `true` to automatically cancel outdated webhook builds ``` > For information about using API calls to trigger builds, look [here](../rest-api/overview/).

> > Read more about configuring [additional conditions to run or skip](https://docs.codemagic.io/yaml-running-builds/starting-builds-automatically/#using-when-to-run-or-skip-builds) builds or build steps. > ### Scripts Scripts specify what kind of application is built. This is where you can specify the commands to [test](../testing-yaml/testing/), build and code sign your project (see our documentation for [iOS code signing](../code-signing-yaml/signing-ios) and [Android code signing](../code-signing-yaml/signing-android)). You can also run shell (`sh`) scripts directly in your `.yaml` file, or run scripts in other languages by defining the language with a shebang line or by launching a script file present in your repository. When you set `ignore_failure` to `true`, the workflow will continue to run even if the script fails. ```yaml scripts: - echo "single line script" - name: Flutter test script: flutter test ignore_failure: true - | #!/usr/bin/env python3 print('Multiline python script') - name: Build for iOS script: flutter build ios ``` There are example scripts available for building a [Flutter application](./building-a-flutter-app/), [React Native application](./building-a-react-native-app/), [native Android application](./building-a-native-android-app/) or a [native iOS application](./building-a-native-ios-app/). By default, scripts are run after your app sources are fetched and the repository is cloned. To run scripts before the repository cloning step, use the pre_clone_scripts step: ```yaml workflows: default-workflow: name: Default Workflow pre_clone_scripts: - name: Scripts to run before cloning the repository script: ... scripts: - name: Scripts to run after cloning the repository script: ... ``` ### Artifacts Configure the paths and names of the artifacts you would like to use in the following steps, e.g. for publishing, or have available for download on the build page. All paths are relative to the clone directory, but absolute paths are supported as well. You can also use [environment variables](../building/environment-variables) in artifact patterns. ```yaml artifacts: - build/**/outputs/apk/**/*.apk # relative path for a project in root directory - subfolder_name/build/**/outputs/apk/**/*.apk # relative path for a project in subfolder - build/**/outputs/**/*.aab - build/**/outputs/**/mapping.txt - build/ios/ipa/*.ipa - build/macos/**/*.pkg - /tmp/xcodebuild_logs/*.log - flutter_drive.log ``` There are several things to keep in mind about patterns: * The pattern can match several files or folders. If it picks up files or folders with the same name, the top level file or folder name will be suffixed with `_{number}`. * If one of the patterns includes another pattern, duplicate artifacts are not created. * `apk`, `aab`, `aar`, `ipa`, `app`, `pkg`, proguard mapping (`mapping.txt`), `flutter_drive.log`, `jar`, `zip`, `xarchive` and `dSYM.zip` files will be available as separate items in the Artifacts section on the build page. The rest of the artifacts will be included in an archive with the following name pattern: `{project-name}_{version}_artifacts.zip`. ### Publishing Codemagic has a number of integrations for publishing but you can also publish elsewhere with custom scripts. See the options under the [Publishing section](../publishing-yaml/distribution/). Note that by default the publishing scripts are run regardless of the build status. You can specify additional conditions with if statements. ```yaml publishing: email: recipients: - name@example.com scripts: name: Check for apk script: | apkPath=$(find build -name "*.apk" | head -1) if [[ -z ${apkPath} ]] then echo "No .apk were found" else echo "Publishing .apk artifacts" fi ``` You can also use the publishing scripts to report build status. ```yaml scripts: - name: Report build start script: # build started . . . - name: Build finished successfully script: touch ~/SUCCESS publishing: scripts: - name: Report build status script: | if [ -a "~/SUCCESS" ] ; then # build successful else # build failed fi ``` ### Labels You may use `codemagic.yaml` to define labels for your apps. Labels serve as additional information about the workflow you are building and are helpful when you have multiple versions of a workflow. The labels are visible on the `/builds` and `/app//build/` pages. As shown in the snippet below, labels also support environment variables. ```yaml workflows: sample_workflow: name: My Workflow labels: - QA - ${TENANT_NAME} ``` If you are building white label apps and use the Codemagic REST API to initiate your builds, labels should be passed as described [here](https://docs.codemagic.io/rest-api/builds/) because it is not possible to override environment variables that will be used as labels. ## Working directory You may select a working directory globally for the entire workflow or individual scripts only. If not specified, the global working directory defaults to the directory where the repository is cloned (`/Users/builder/clone`). You can override the global working directory by specifying the working directory in the individual steps. Consider the example below: ```yaml workflows: build-apps: name: Build iOS and Android working_directory: mobile scripts: - name: Prepare script: pwd # current working directory is /Users/builder/clone/mobile - name: Build iOS working_directory: mobile/ios script: pwd # current working directory is /Users/builder/clone/mobile/ios - name: Build Android working_directory: mobile/android script: pwd # current working directory is /Users/builder/clone/mobile/android - name: Process Logs working_directory: /Users/builder/Library/Logs script: pwd # current working directory is /Users/builder/Library/Logs ``` Working directory paths are relative to the repository clone directory, e.g. if `mobile` is the working directory, then the script will be executed in `/Users/builder/clone/mobile`. Note that you can specify an absolute path as a working directory as well. ## Validating codemagic.yaml locally Using the Codemagic JSON schema, you can validate your `codemagic.yaml` for structure and syntax errors right in your IDE. The same level of validation is carried out on the frontend in the YAML editor in your project settings. The JSON schema does not validate the maximum build duration value, software version values, credentials, environment variable values, or whether you have access to any paid features. Codemagic JSON schema is available out of the box in the IDEs integrated with [schemastore.org](http://schemastore.org/), e.g. Android Studio and Visual Studio Code. If your IDE does not have the Codemagic JSON schema available by default, you can set up validation manually. To do so: * make sure you have YAML language support in the IDE * configure the IDE to use the Codemagic JSON schema for validation available at [https://codemagic.io/codemagic-schema.json](https://codemagic.io/codemagic-schema.json) ================================================================================ source: https://docs.codemagic.io/knowledge-white-label/white-label-apps-overview/ title: White labeling overview description: An overview of white labeling with Codemagic last_modified: 2026-06-26 ================================================================================ # White labeling overview > An overview of white labeling with Codemagic In the context of CI/CD, “white labeling” refers to automating the process of rebranding your core app for each customer and then publishing the app to stores or other distribution channels. A white labeling pipeline will run scripts to change colours, logos, images, fonts and update other app settings such as bundle identifiers, provisioning profiles, certificates, API endpoints, and other configuration settings unique to each customer. These workflows can also be configured to run unit and integration tests, code quality analysis, update release notes, and automatically distribute app builds to your testers. Builds can be configured to start as soon as code is pushed to your repository, tags are added, or a pull request is merged. Using different workflows on different branches allows you to carry out actions such as producing a build for devs only to try on their own device, or creating a build that is sent directly to your QA testers. ## Pre-requisites for white labeling If you are building white label apps for multiple customers, you will need access to the appropriate Apple API keys or Google Service Accounts for publishing to their store accounts. You will also need to make sure that distribution certificates, bundle ids, provisioning profiles, APNS certificates, analytics configurations etc. are available for each version of the app you are going to build. In order to write your white labeling scripts, familiarity with shell scripting will also be an advantage. You can find some samples for common tasks [here](https://docs.codemagic.io/yaml-quick-start/white-label-getting-started/). ## Managing assets The most important part when white labeling your application is your customer's assets. So you need to find a way to manage assets. One approach is to create a zip archive for each customer that contains their unique assets and use a unique identifier in the file name for each customer. For example, `assets_001.zip` would clearly identify that this zip archive contains the assets for client `001`. Each customer zip archive should have the following files with this naming convention: - **`ios_assets/`**. This folder contains the iOS icons from `/ios/Runner/Assets.xcassets/AppIcon.appiconset/`. - **`android_assets/`**. This folder contains the Android icons from `/android/app/src/main/res/`. ## Flavors versus a white labeling workflow With flavors you create different versions of your app within the same project. They are typically used when you would like to create a handful of different versions of your app so you can create a “development” build, a “qa” build and a “production” build. Each version might be configured to point to a different API endpoint, or have a different icon to show which version it is so it’s clear which app is being used when testing the app. In Xcode you add different build schemes which can be used to customize the project output. Similarly, in Android Studio you can create product build variants and create a separate folder for each flavor’s resources. If you only needed to white label a few versions of your app then you could use this approach to build different versions of your app. However, it’s not very scalable and creates an unnecessarily large project and makes it harder to automate the white label process. An automated white label workflow, on the other hand, doesn’t require that your app has multiple schemes or flavors configured in your Xcode or Android project. When the app is built, a series of scripts are run which change the project’s properties and change things like icons, images, fonts, and values in xml and plist files. In this way, a single base app can be used to create as many different versions as you need without having to add the customizations directly to the project. ## Limitations of white label workflows Neither Apple nor Google provide APIs that allow you to add a new application programmatically in their stores. This means you have to manually add the first version of a new application in the App Store or Google Play. Once this has been done it’s possible to automatically publish updated app builds to the stores. Tasks such as updating screenshots and descriptions or other metadata can be performed using third-party tools such as Fastlane. ## Pricing for building white label apps There is no extra charge for setting up white label workflows with Codemagic. However, if you are white labeling many versions of your app you might want to add additional concurrencies so multiple versions can be built in parallel. Codemagic’s **pay-as-you-go plan** lets you use up to three concurrencies, whereas **Annual** and **Enterprise** plans have three concurrencies by default and you can add additional concurrencies as your needs grow. You can find detailed pricing information [here](https://docs.codemagic.io/billing/pricing/). ## Parallel white label builds If you have a large number of white label apps, it can take many hours to build and publish them all. Fortunately, with Codemagic it is possible to use multiple concurrencies to run builds in parallel. This means that if you have 40 white label app versions to build and you have 3 concurrencies available, the first 3 builds will start immediately and the remaining 37 builds will be queued for building. As soon as one of the first builds completes, the next build in the queue will start and so on until all the builds are complete. ## Testing your white label apps Running automated static code analysis, unit tests, or integration tests as part of a white label workflow is one way to ensure that all code meets expected standards before it is deployed to production. This is particularly important on `dev` or `qa` branches before any PR requests are merged into the production branch. In a Flutter project, for example, unit tests can be run using the following script: ```yaml name: Unit tests script: | mkdir -p test-results flutter test --machine > test-results/flutter.json ``` For more information on running tests for native iOS and Android, React Native please find more information [here](../yaml-testing/testing/). Integration tests can be run on the simulators or emulators on Codemagic’s machines, but it’s also possible to integrate your workflows with external testing services where your iOS and Android apps can be tested on a variety of device configurations and real devices. There are many services to choose from, but here are some popular choices: - [Firebase Test Lab](https://docs.codemagic.io/yaml-testing/firebase-test-lab/) - [Emulator.wtf](https://docs.codemagic.io/yaml-testing/emulator-wtf/) - [LamdaTest](https://docs.codemagic.io/integrations/lambdatest-integration/) ## Distributing builds to developers or QA testers In addition to unit and integration testing, developers and QA teams still want to get hands on with their apps to test bug fixes and new functionality. Pre-release apps can be distributed in any of the following ways: - Install the app directly from Codemagic notification emails. - Configure Codemagic’s Slack integration and install build artifacts directly from notification messages. - Use the QR code in the Codemagic web app to install the app directly to your device. - Use the public build dashboards feature to make builds available for download. - Configure your workflows to upload your app to Firebase App Distribution or other third party distribution services. - Publishing development builds to TestFlight for internal or external test groups. - Publish your pre-release to a testing track in Google Play Console. ## Optimizing build speed Even though it’s possible to build both iOS and Android apps on macOS machines, we offer Linux machines as well. If Linux machines are preferred for Android builds, then you should create separate workflows for iOS and Android builds and set the `instance_type` property in your *codemagic.yaml*. - For iOS, use the latest Apple silicon machine where possible. Set the instance type to `mac_mini_m2` in the `codemagic.yaml` configuration file. - For Android builds, use premium Linux machines. Set the instance type to `linux_x2` in the `codemagic.yaml` configuration file. ```yaml workflows: ios-dev-release: name: iOS dev release instance_type: mac_mini_m2 .... android-dev-release: name: Android dev release instance_type: linux_x2 .... ``` ## Getting started with white labeling on Codemagic We would recommend getting familiar with setting up a single version of your app to begin with. Set up your workflow using a codemagic.yaml configuration file and consult the documentation to understand core concepts, such as using environment variables, build triggers, script steps, code signing and publishing. Once you have successfully built and published a version of your app to the stores, continue by adding additional versions to your configuration file. For more information about getting started with the **codemagic.yaml** configuration file, please refer to the documentation [here](../yaml/yaml-getting-started/). Once you are familiar with how Codemagic works, you should try your automation scripts on your local machine to test things like authenticating with your own CMS system, or running scripts that change application assets, such as icons or images. You can even use Codemagic's open-source [CLI tools](https://github.com/codemagic-ci-cd/cli-tools) to test features such as code signing and publishing. Once you are confident that your scripts work as expected, you can then set up your workflow on Codemagic. ## Next steps Check out the getting started guide [here](../yaml-quick-start/white-label-getting-started/) or the final white-label sample project [here](https://github.com/codemagic-ci-cd/white-label-demo-project). ================================================================================ source: https://docs.codemagic.io/specs-windows/windows-2022/ title: Windows 2022 description: A list of tools available out-of-the-box on Codemagic Windows 2022 build machines. last_modified: 2026-04-21 ================================================================================ # Windows 2022 > A list of tools available out-of-the-box on Codemagic Windows 2022 build machines. ## Hardware - Windows virtual machine: `8 vCPUs, 32 GB memory` ## System - System version `Microsoft Windows Server 2022 Datacenter (OS Build 20348.643)` - Disk `150GB (Free Space: 66GB)` ## Android Studio Android Studio Iguana `2023.2.1` installed at `C:\Program Files\Android\Android Studio\` ## Android SDK > SDK Manager at `C:\Users\builder\programs\android-sdk\cmdline-tools\latest\bin\sdkmanager.bat` {{< collapsible title="Installed SDK packages" >}} ``` $ C:\Users\builder\programs\android-sdk\cmdline-tools\latest\bin\sdkmanager.bat --list_installed Installed packages: Loading package information... Loading local repository... [========= ] 25% Loading local repository... [========= ] 25% Fetch remote repository... [=======================================] 100% Fetch remote repository... ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools\30.0.3 build-tools;34.0.0 | 34.0.0 | Android SDK Build-Tools 34 | build-tools\34.0.0 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake\3.22.1 cmdline-tools;latest | 13.0 | Android SDK Command-line Tools (latest) | cmdline-tools\latest extras;google;Android_Emulator_Hypervisor_Driver | 2.0.0 | Android Emulator hypervisor driver (installer) | extras\google\Android_Emulator_Hypervisor_Driver extras;google;google_play_services | 49 | Google Play services | extras\google\google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras\google\instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras\google\market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras\google\market_licensing extras;google;usb_driver | 13 | Google USB Driver | extras\google\usb_driver extras;google;webdriver | 2 | Google Web Driver | extras\google\webdriver extras;intel;Hardware_Accelerated_Execution_Manager | 7.6.5 | Intel x86 Emulator Accelerator (HAXM installer) - Deprecated | extras\intel\Hardware_Accelerated_Execution_Manager ndk;26.2.11394342 | 26.2.11394342 | NDK (Side by side) 26.2.11394342 | ndk\26.2.11394342 platform-tools | 35.0.1 | Android SDK Platform-Tools | platform-tools platforms;android-29 | 5 | Android SDK Platform 29 | platforms\android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms\android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms\android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms\android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms\android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms\android-34 sources;android-29 | 1 | Sources for Android 29 | sources\android-29 sources;android-30 | 1 | Sources for Android 30 | sources\android-30 sources;android-31 | 1 | Sources for Android 31 | sources\android-31 sources;android-32 | 1 | Sources for Android 32 | sources\android-32 sources;android-33 | 1 | Sources for Android 33 | sources\android-33 sources;android-34 | 2 | Sources for Android 34 | sources\android-34 system-images;android-34;google_apis;x86_64 | 12 | Google APIs Intel x86_64 Atom System Image | system-images\android-34\google_apis\x86_64 {{< /collapsible >}} ## Java versions | **Version** | **Path** | |---------|------| | 1.8 | `C:\Program Files\OpenJDK\jdk-1.8.0` | | 11 | `C:\Program Files\OpenJDK\jdk-11.0.22` | | 17 | `C:\Program Files\OpenJDK\jdk-17` | | 20 | `C:\Program Files\OpenJDK\jdk-20.0.1` | | **21** (default) | `C:\Program Files\OpenJDK\jdk-21.0.2` | ## Gradle versions | **Version** | **Path** | |--------|------| | 8.14.1 | `C:\Users\builder\programs\gradle-8.14.1` | ## Other pre-installed tools - Android NDK `26.2.11394342` - 7zip `23.1` - chocolatey `2.2.2` - chocolatey-core.extension `1.4.0` - chocolatey-windowsupdate.extension `1.0.5` - curl `8.6.0` - DotNetFx `4.8.0.20220524` - fastlane `2.219.0` - firebase `13.6.0` - gem `3.5.3` - gh `2.46.0` - Google Cloud SDK `468.0.0` - gsutil `5.27` - git `2.44.0` - grep `3.11` - less `634.0` - node `20.12.2` - npm `10.5.0` - openssl `3.6.2` - powershell-core `7.4.1` - pyenv-win `3.1.1` - python `3.9.6` - ruby `3.3.0` - ssh - unzip `6.0` - vcredist140 `14.38.33135` - vcredist2015 `14.0.24215.20170201` - vim `9.1.202` - visualcpp-build-tools `17.14.29` - wget `1.21.4` - yarn `1.22.19` - zip `3.0.0` ================================================================================ source: https://docs.codemagic.io/specs/xcode-update-policy/ title: Xcode update policy description: How we release and deprecate Xcode versions last_modified: 2026-02-25 ================================================================================ # Xcode update policy > How we release and deprecate Xcode versions ## Overview Codemagic macOS build machines come with a range of Xcode versions and runtimes preinstalled. As a minimum, the machines in our shared pool will always support the latest major Xcode version along with all of its minor versions as well as previous major versions that can be used for App Store submissions. You can check the currently available Xcode versions [here](../specs/versions-macos). If you require access to older Xcode versions that are not available in the shared pool, please [contact us](https://codemagic.io/pricing/#enterprise). ## Xcode version updates When a new beta or release version of Xcode is released, we aim to make it available to our users as soon as possible. New versions are usually rolled out over the weekend. Patch releases will replace the previous patch version of an Xcode release. If you have specified your Xcode version with the precision of a patch version, we will automatically resolve it to the latest patch of that version. Codemagic uses two aliases for Xcode versions -- `latest` and `edge`. `latest` points to the latest *release* version of Xcode. When a new major release version is rolled out, we do not point `latest` to that version immediately but announce the date on our [GitHub Discussions](https://github.com/orgs/codemagic-ci-cd/discussions) page. In case of minor and patch version updates, `latest` is updated as soon as the versions are rolled out. `edge` always points to the latest available Xcode version (`major.minor.patch`) on our build machines and can thus point to a release or a beta version. We recommend using `latest` and `edge` in your build configuration if you want to regularly test your builds against the latest release or beta versions. ## Deprecation of Xcode versions Our Xcode version deprecation policy for the machines in the shared pool is guided by [Apple's requirements](https://developer.apple.com/news/upcoming-requirements/). When an Xcode version is no longer supported for App Store Connect submissions, we will schedule that version for deprecation. In such cases we will post an announcement about the upcoming deprecation and the timeline in our [GitHub Discussions](https://github.com/codemagic-ci-cd/codemagic-docs/discussions) page. Please note that in certain cases we may decide to keep Xcode versions available for a longer period of time. ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-native-android-app/ title: Android native apps description: How to build an Android app with codemagic.yaml last_modified: 2026-03-24 ================================================================================ # Android native apps > How to build an Android app with codemagic.yaml This guide will illustrate all of the necessary steps to successfully build and publish a native Android app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/android/android-native-quick-start). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` #### Signing Android apps using Gradle To sign your Android app, simply modify your **`android/app/build.gradle`** or **`android/app/build.gradle.kts`** as follows: ### Option: build.gradle ```Groovy ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` ### Option: build.gradle.kts ```groovy import java.io.File import java.util.* val keystoreProperties = Properties().apply { var file = File("key.properties") if (file.exists()) load(file.reader()) } plugins { ... } android { ... val appVersionCode = (System.getenv()["NEW_BUILD_NUMBER"] ?: "1")?.toInt() defaultConfig { ... versionCode = appVersionCode ... } signingConfigs { create("release") { if (System.getenv()["CI"].toBoolean()) { // 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 { storeFile = file(keystoreProperties.getProperty("storeFile")) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } } } buildTypes { getByName("release") { isMinifyEnabled = false signingConfig = signingConfigs.getByName("release") } } } dependencies { ... } ``` ## Setting up the Android package name Configure Android package name by adding the corresponding variable in the `codemagic.yaml`: ```yaml workflows: react-native-android: # .... environment: groups: # ... vars: PACKAGE_NAME: "io.codemagic.sample.androidnative" ``` ## Configure scripts to build the app Add the following scripts to your `codemagic.yaml` file in order to prepare the build environment and start the actual build process. In this step you can also define the build artifacts you are interested in. These files will be available for download when the build finishes. For more information about artifacts, see [here](../yaml/yaml-getting-started/#artifacts). ```yaml scripts: # .... - name: Set Android SDK location script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/local.properties" - name: Build Android release script: | ./gradlew bundleRelease # -> to create the .aab # gradlew assembleRelease # -> to create the .apk artifacts: - app/build/outputs/**/*.aab ``` ## Build versioning If you are going to publish your app to Google Play, each uploaded artifact must have a new version. Codemagic allows you to easily automate this process and increment the version numbers for each build. For more information and details, see [here](../configuration/build-versioning). One very useful method of calculating the code version is to use Codemagic command line tools to get the latest build number from Google Play and increment it by one. You can find the full sample project with the instructions on alternative ways to perform Android build versioning [in our repository](https://github.com/codemagic-ci-cd/android-versioning-example). The prerequisite is a valid **Google Cloud Service Account**. Please follow these steps: 1. Go to [this guide](https://docs.codemagic.io/yaml-publishing/google-play/) and complete the steps in the **Google Play** section. 2. Skip to the **Creating a service account** section in the same guide and complete those steps also. 3. You now have a `JSON` file with the credentials. 4. Open Codemagic UI and create a new Environment variable `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. 5. Paste the content of the downloaded `JSON` file in the **_Value_** field, set the group name (e.g. **google_play**) and make sure the **Secret** option is checked. --- 6. Add the **google_play** variable group to the `codemagic.yaml` ```yaml workflows: android-workflow-id: # .... environment: groups: - google_play ``` 7. Modify the build script to calculate the build number and use it as gradlew arguments. ```yaml scripts: # .... - name: Build Android release script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z $LATEST_GOOGLE_PLAY_BUILD_NUMBER ]; then # fallback in case no build number was found from Google Play. # Alternatively, you can `exit 1` to fail the build # BUILD_NUMBER is a Codemagic built-in variable tracking the number # of times this workflow has been built UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi cd android ./gradlew bundleRelease \ -PversionCode=$UPDATED_BUILD_NUMBER \ -PversionName=1.0.$UPDATED_BUILD_NUMBER ``` 8. Modify the `android/app/build.gradle` file to get the build number values and apply them: ```kotlin // get version code from the specified property argument `-PversionCode` during the build call def getMyVersionCode = { -> return project.hasProperty('versionCode') ? versionCode.toInteger() : -1 } // get version name from the specified property argument `-PversionName` during the build call def getMyVersionName = { -> return project.hasProperty('versionName') ? versionName : "1.0" } .... android { .... defaultConfig { ... versionCode getMyVersionCode() versionName getMyVersionName() ``` ## Publishing Codemagic offers a wide array of options for app publishing and the list of partners and integrations is continuously growing. For the most up-to-date information, check the guides in the **Configuration > Publishing** section of these docs. To get more details on the publishing options presented in this guide, please check the [Email publishing](../yaml-publishing/email) and the [Google Play Store](../yaml-publishing/google-play) publishing docs. #### Email publishing If the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` } #### Publishing to Google Play Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: ```yaml workflows: native-android: name: Native Android max_build_duration: 120 instance_type: mac_mini_m2 environment: android_signing: - keystore_reference groups: - google_play vars: PACKAGE_NAME: "io.codemagic.sample.androidnative" scripts: - name: Set Android SDK location script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/local.properties" - name: Build Android release script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z $LATEST_GOOGLE_PLAY_BUILD_NUMBER ]; then # fallback in case no build number was found from google play. Alternatively, you can `exit 1` to fail the build UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi ./gradlew bundleRelease -PversionCode=$UPDATED_BUILD_NUMBER -PversionName=1.0.$UPDATED_BUILD_NUMBER artifacts: - app/build/outputs/**/*.aab publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` ## Next steps While this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. ================================================================================ source: https://docs.codemagic.io/integrations/appknox-integration/ title: Appknox integration description: How to integrate your workflows with Appknox using codemagic.yaml last_modified: 2026-06-05 ================================================================================ # Appknox integration > How to integrate your workflows with Appknox using codemagic.yaml **Appknox** is a mobile application security testing solution that can be integrated into your Codemagic CI/CD pipelines to run security checks for your applications. ## Configuring Appknox in Codemagic Signing up with Appknox [here](https://www.appknox.com/) is required to be able to generate your personal access token in the Appknox UI. After receiving the token, follow the steps below: 1. Open your Codemagic app settings, and go to the **Environment variables** tab 2. Enter the desired **_Variable name_**, e.g. `APPKNOX_ACCESS_TOKEN` 3. Enter the required value as **_Token value_** 4. Enter the variable group name, e.g. **_appknox_credentials_** 5. Make sure the **Secret** option is selected 6. Click the **Add** button to add the variable 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - appknox_credentials ``` 8. Adding the following scripts in **codemagic.yaml** will allow you to start the security scanning process in the Appknox environment: ```yaml - name: Appknox binary installation script: curl -L https://github.com/appknox/appknox-go/releases/latest/download/appknox-`uname -s`-x86_64 > /usr/local/bin/appknox && chmod +x /usr/local/bin/appknox ``` Make sure that the following script is executed in the post-build script (after your app binary is built): ```yaml - name: Upload binary to Appknox script: appknox upload PATH_TO_APP_BINARY ``` It is also possible to check if the scanner detected any vulnerability risk levels by executing the following command: ```yaml - name: Check vulnerability risk level script: appknox cicheck --risk_threshold ``` ================================================================================ source: https://docs.codemagic.io/rest-api/applications/ title: Applications API description: API for managing apps added to Codemagic last_modified: 2026-06-26 ================================================================================ # Applications API > API for managing apps added to Codemagic APIs for managing applications are currently available for developers to preview. During the preview period, the API may change without advance notice. > > **Using the API with apps configured with codemagic.yaml:**
> Unlike with Workflow Editor, information about workflows in **codemagic.yaml** is not stored in Codemagic and is therefore not available before starting a build and cloning the repository. Therefore, the API does not return workflow information such as `workflowId` for **codemagic.yaml** workflows. > ## Retrieve all applications `GET /apps` #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ --request GET https://api.codemagic.io/apps ``` #### Response ```json { "applications": [{ "_id": "6172cc7d57278d06d4e915f1", "appName": "Foobar-App", "workflowIds": [ "5d85f242e941e00019e81bd2" ], "workflows": { "5d85f242e941e00019e81bd2": { "name": "Android Workflow" } } }] } ``` ## Retrieve an application `GET /apps/:id` Based on the application id provided, returns the application's information. #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ --request GET https://api.codemagic.io/apps/ ``` #### Response ```json { "application": { "_id": "5d85eaa0e941e00019e81bc2", "appName": "counter_flutter", "branches": [ "master" ], "workflowIds": [ "5d85f242e941e00019e81bd2" ], "workflows": { "5d85f242e941e00019e81bd2": { "name": "Android Workflow" } } } } ``` ## Add a new application `POST /apps` Adds a Git repository to the applications list. #### Parameters | **Name** | **Type** | **Description** | | --------------- | -------- | --------------- | | `repositoryUrl` | `string` | **Required.** SSH or HTTPS URL for cloning the repository. | | `teamId` | `string` | **Optional.** Team ID, if you wish to add an app directly to one of your teams. You must be an admin in the team specified. | #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ -d '{ "repositoryUrl": "git@github.com:my-organization/my-repo.git" }' \ -X POST https://api.codemagic.io/apps ``` #### Response ```json { "_id": "5c9c064185dd2310123b8e96", "appName": "my-repo" } ``` ## Add a new application from a private repository `POST /apps/new` Creates an application from a private repository with an SSH key #### Parameters | **Name** | **Type** | **Description** | | --------------- | -------- | --------------- | | `repositoryUrl` | `string` | **Required.** SSH or HTTPS URL for cloning the repository. | | `sshKey` | `JSON` | **Required.** | | `projectType` | `string` | `flutter-app` when adding Flutter application. | | `teamId` | `string` | **Optional.** Team ID, if you wish to add an app directly to one of your teams. You must be an admin of the team specified. | #### `sshKey` parameter | **Name** | **Type** | **Description** | | --------------- | -------- | --------------- | | `data` | `string` | **Required.** `base64`-encoded private key file. | | `passphrase` | `string` | **Required.** SSH key passphrase or `null` if the SSH key is without a passphrase. | To encode private key file and paste result to clipboard ```bash base64 id_rsa | pbcopy ``` #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ -d '{ "repositoryUrl": "git@github.com:my-organization/my-repo.git", "sshKey": { "data": "St89hgb-BASE64-ENCODED-SSH-KEY-FILE-H4ga7jgf==", "passphrase": null } }' \ -X POST https://api.codemagic.io/apps ``` #### Response ```json {"application" : { "_id": "5c9c064185dd2310123b8e96", "appName": "my-repo" }} ``` ## Modify application variables and secrets For up-to-date information on managing environment variables and secrets for apps configured using codemagic.yaml, please refer to the **Secrets and Environment Vars** endpoints in [Codemagic REST API documentation](https://codemagic.io/api/v3/schema). ================================================================================ source: https://docs.codemagic.io/knowledge-codemagic/build-versioning/ title: Automatic build versioning description: How to set a new build number to push to app stores last_modified: 2026-06-26 ================================================================================ # Automatic build versioning > How to set a new build number to push to app stores If you are going to publish your app to **App Store Connect** or **Google Play**, each uploaded artifact must have a new version satisfying each app store's requirements. You'll need to devise a build versioning strategy that satisfies the App Store and/or Google Play Store versioning requirements and works for your team's development processes. On this page, we will explain the App Store and Google Play build versioning requirements, how the Flutter framework generalizes build versioning, and various strategies to set your build versions using Codemagic. See the [build versioning codemagic blog article](https://blog.codemagic.io/build-versioning-with-codemagic/) for a detailed overview. {{< youtube UezlgmCZLcU >}} ## Overview of Build Versioning Requirements #### App Store Connect Requirements The main values for iOS & macOS versioning are `CFBundleShortVersionString` (Release Version Number) and `CFBundleVersion` (Build Version Number). The best explanation of these two values, despite being outdated, is Apple's technical note on [Version Numbers and Build Numbers](https://developer.apple.com/library/archive/technotes/tn2420/_index.html). [CFBundleShortVersionString](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring), Release Version Number, is the external user facing release version of your app displayed in the App Store. It must follow the `{major}.{minor}.{patch}` version format of three period separated integers. This must be incremented every time you release a version to the App Store. It's advisable to commit this value to version control and update it for every new release of your app to the App Store. [CFBundleVersion](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion), Build Version Number, is the internal build version number of your application used for testing and development. It appears in `{major}.{minor}.{patch}` format of one to three period separated integers. If {minor}.{patch} are not provided, then they will default to zero. Build version number must be incremented with every release candidate submitted to TestFlight for a particular release version number. For iOS, build version number can be reused across different release version numbers while for macOS, build version number must be unique across all release version numbers. This value is best incremented and set by your CI/CD pipeline for every build you're submitting to TestFlight. #### Google Play Requirements You can find the Google Play build versioning requirements in the [Android documentation](https://developer.android.com/studio/publish/versioning#appversioning). The important values defined in the build.gradle file are `versionName` and `versionCode`. `versionName` is a text based, external, version of your app that is displayed to users and visible in Google Play. There are no restrictions for `versionName`, so you should choose something that makes sense for you and your users, such as `{major}.{minor}.{patch}` versioning. It's advisable to commit this value to version control and update it for every new release of your app to the Play Store. `versionCode` is an internal version of your app that must be an integer value between `1` and `2100000000`. This must be incremented for every build you upload to Google Play. This value is best incremented and set by your CI/CD pipeline for every build. #### Flutter Build Versioning Flutter generalizes iOS and Android build versioning with the [pubspec.yaml **version** property](https://github.com/flutter/flutter/blob/master/packages/flutter_tools/templates/app/pubspec.yaml.tmpl#L9-L19). This is a value in the form `{major}.{minor}.{patch}+{build_number}` (e.g. `1.2.3+45`). In Flutter builds, the value for build name, `{major}.{minor}.{patch}`, sets `CFBundleShortVersionString` for iOS and `versionName` for Android. While the optional build number, `{build_number}`, sets `CFBundleVersion` for iOS and `versionCode` for Android. With `flutter build` commands these values can be overridden with the command line arguments `--build-name` and `--build-number` or by setting the environment variables `FLUTTER_BUILD_NAME` and `FLUTTER_BUILD_NUMBER`. In order to complete an automatic build versioning process for Flutter iOS apps, make sure the following keys along with their string values are set in `ios/Runner/info.plist`: ```bash CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleVersion $(FLUTTER_BUILD_NUMBER) ``` It is advisable to set your build version (e.g. `1.2.3`) in the `pubspec.yaml` `version` property and commit this to version control, as this will only change on every app release. On the other hand, you should consider having your CI/CD pipeline increment and set build number automatically, as this should be updated for every build.
--- ## Build versioning in Codemagic ### Environment variables There are several approaches you can use for build versioning on Codemagic. One of the easiest ways to increment the application version on every build is by using the [environment variables](/variables/environment-variables) that Codemagic exports during the build. There are two environment variables that count the number of builds: * `BUILD_NUMBER`. Holds the total count of builds (including the ongoing build) for a specific **workflow** in Codemagic. In other words, if you have triggered 10 builds for some workflow in Codemagic, the next time you build it, `BUILD_NUMBER` will be exported as `11`. * `PROJECT_BUILD_NUMBER`. Holds the total count of builds (including the ongoing build) for a **project** (application) in Codemagic. In contrast with `BUILD_NUMBER`, `PROJECT_BUILD_NUMBER` will increase every time you build any of the workflows of the app. ### Option: Flutter For Flutter, you can easily increment your build number and build name using the `PROJECT_BUILD_NUMBER` by passing the following to the build arguments: ```bash --build-name=1.0.$PROJECT_BUILD_NUMBER --build-number=$PROJECT_BUILD_NUMBER ``` Note that if the build version is manually incremented in `pubspec.yaml`, these arguments do not need to be passed to the build command. If you've added an existing project to Codemagic and need to offset the build number by the current build number, i.e. 200, then you can pass the following argument to correctly increment your build number. ```bash --build-number=$(($PROJECT_BUILD_NUMBER + 200)) ``` ### Option: Xcode You can use the [Xcode command line agvtool](https://developer.apple.com/library/archive/qa/qa1827/_index.html) to set the next build version name for your build. ```yaml scripts: - name: Set the build version script: | #!/bin/sh set -e set -x cd $CM_BUILD_DIR agvtool new-version -all $(($BUILD_NUMBER + 1)) ``` ## App Store or TestFlight latest build number Using Codemagic [CLI tools](../knowledge-codemagic/codemagic-cli-tools) it is possible to get the latest build number from **App Store** or from **TestFlight** so you can automatically increment the build version in your workflow. For more details, check the [get-latest-app-store-build-number](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/get-latest-app-store-build-number.md#get-latest-app-store-build-number) or [get-latest-testflight-build-number](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/get-latest-testflight-build-number.md#get-latest-testflight-build-number) actions from [app-store-connect](https://github.com/codemagic-ci-cd/cli-tools/tree/master/docs/app-store-connect#app-store-connect) Codemagic CLI Tool. In order to allow Codemagic to connect to your App Store Connect account, you need to provide API access to App Store Connect API. It is possible that some of these environment variables are already configured as part of the iOS code signing configuration. #### Creating the App Store Connect API key 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `APP_STORE_CONNECT_KEY_IDENTIFIER`. 3. Enter the variable value as **_Variable value_**. 4. Enter the variable group name, e.g. **_app_store_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to also add all of the above variables. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - app_store_credentials ``` ### Option: Flutter workflow editor %!s() ================================================================================ source: https://docs.codemagic.io/flutter-running-builds/timeout/ title: Build timeout settings using Flutter workflow editor description: Limit the maximum duration of builds using Flutter workflow editor last_modified: 2022-11-03 ================================================================================ # Build timeout settings using Flutter workflow editor > Limit the maximum duration of builds using Flutter workflow editor By default, Codemagic builds are set to time out after 60 minutes. You can decrease or increase the maximum build duration **per workflow**. * In `codemagic.yaml`, the build timeout limit can be defined in the [workflow section](../getting-started/yaml#workflows). * For Flutter projects configured via the workflow editor, you can adjust the maximum build duration in **App settings > Workflow settings > Max build duration**. Move the slider right or left to increase or decrease the maximum build duration. The minimum build duration is 30 min and the maximum is 120 min. ================================================================================ source: https://docs.codemagic.io/yaml-running-builds/timeout/ title: Build timeout settings in codemagic.yaml description: Limit the maximum duration of builds using codemagic.yaml last_modified: 2022-12-12 ================================================================================ # Build timeout settings in codemagic.yaml > Limit the maximum duration of builds using codemagic.yaml By default, Codemagic builds are set to time out after 60 minutes. You can decrease or increase the maximum build duration **per workflow**. * In `codemagic.yaml`, the build timeout limit can be defined in the [workflow section](../getting-started/yaml#workflows). * For Flutter projects configured via the workflow editor, you can adjust the maximum build duration in **App settings > Workflow settings > Max build duration**. Move the slider right or left to increase or decrease the maximum build duration. The minimum build duration is 30 min and the maximum is 120 min. ================================================================================ source: https://docs.codemagic.io/troubleshooting/common-android-issues/ title: Common Android issues description: How to overcome common issues building Android mobile apps on Codemagic last_modified: 2026-06-18 ================================================================================ # Common Android issues > How to overcome common issues building Android mobile apps on Codemagic ### Builds work locally but fail on Codemagic ###### Description Builds succeeds locally but fails on Codemagic, throwing vague errors (e.g. _**Gradle task bundleRelease failed with exit code 1**_), or the build is successful, but some functions aren't working. {{}} ###### Cause These issues are likely caused by plugin and/or gradle versions used locally being different from the versions used on Codemagic. If you are using a gradle version that is different from Codemagic, you have to define it in `gradle wrapper`. Otherwise, Codemagic ignores your `build.gradle` file, and your build won't work properly. See which software versions Codemagic uses on [macOS](../specs/versions-macos), on [Linux](../specs/versions-linux) and on [Windows](../specs/versions-windows) instances. ###### Solution First, you need to make sure that the `gradlew` file isn't in `.gitignore`. Look for `**/android/gradlew`, and if it's in `.gitignore`, delete it from there. Then add `!gradle-wrapper.jar` to a new line in `.gitignore` to create an exception so that `gradle-wrapper.jar` would also be excluded from `.gitignore`. Run `./gradlew wrapper --gradle-version [your gradle version]` locally to create `gradlew` and `gradle-wrapper.properties` files in your repository. Commit the changes and rerun your Codemagic build. ###### Additional steps Additional steps are required if you see the following error during the build process: _**Error! Failed to check gradle version. Malformed executable tmpABCDEF/gradlew**_ Codemagic runs `./gradlew --version` on the builder side to check if it is suitable for execution. If you see the error message shown above, there is something wrong with checking the gradle version. To investigate and fix the issues: 1. Make a clean clone of the repository and execute the following commands: ```bash cd chmod +x gradlew ./gradlew --version ``` 2. Make a fix for the issue found. 3. Commit changes to the repo. 4. Run the build again in Codemagic. {{< /collapsible >}} ### Cannot resolve Gradle plugin ###### Description Android users experiencing issues resolving plugins because of the sunset of JCenter. {{}} ###### Cause On February 3. 2021, JFrog, the company that maintains JCenter, [announced that they will be shutting down Bintray and JCenter](https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/). ###### Solution To avoid disruptions to your build pipelines, start migrating to a new hosting solution like `mavenCentral()`, rather than using JCenter or Bintray. To fully migrate away from JCenter, replace all `jcenter()` occurrences with `mavenCentral()` in all build.gradle files. ```groovy repositories { mavenCentral() google() //other repos } ``` - Disable or delete cache. - Run your build pipeline to see if everything works still. - If your build is successful, you're done. - If your build still fails, you'll need to troubleshoot which dependencies still require JCenter. The errors in the failed build step will point out the dependencies using JCenter. > > Note: You'll have to completely upgrade all dependencies that require JCenter to avoid failed builds. > {{< /collapsible >}} ### Java heap space out of memory error or JVM garbage collector is thrashing ###### Description Builds fail with the below error: ERROR:: R8: java.lang.OutOfMemoryError: Java heap space FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:minifyReleaseWithR8'. > com.android.tools.r8.CompilationFailedException: Compilation failed to complete Or FAILURE: Build failed with an exception. * What went wrong: Gradle build daemon has been stopped: since the JVM garbage collector is thrashing {{}} ###### Solution Java Heap space error is a well-known issue and can be thrown for multiple reasons e.g. enabling ProGuard or DexGuard requires more power to complete the tasks. Here are some suggested solutions to try: 1. Set **JAVA_TOOL_OPTIONS: "-Xmx5g"** as an environement variable. This allows the JVM to use up to 5 GB of memory, which can help prevent memory allocation errors. ```yaml workflows: android-workflow: # .... environment: groups: # ... vars: JAVA_TOOL_OPTIONS: "-Xmx5g" ``` - if using Workflow Editor - add `JAVA_TOOL_OPTIONS` with the value `-Xmx5g` under the Environment Variables section 2. Upgrading to the latest version of Gradle in the `gradle-wrapper.properties` file and the Android Gradle plugin in the `android/build.gradle` file to the latest version could help fix the issue. You can refer to the Official Documentation from Android Developer guides to learn more about the latest compatible version [here](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle). 3. Set the maximum heap size by adding **-Dorg.gradle.jvmargs="-Xmx4096m"** to the build command or you can add the following line in **android/gradlew**: ``` exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain -Dorg.gradle.jvmargs="-Xmx4096m" "$@" ``` > > To access more powerful macOS M4 and M4 Max Studio machines, please get in touch with us [here](https://codemagic.io/pricing/#enterprise). > {{< /collapsible >}} ### Could not find method firebaseAppDistribution() for arguments... ###### Description When publishing to Firebase app Distribution using Gradle, build fails with this error "Could not find method firebaseAppDistribution() for arguments..." {{}} ###### Cause This issue is likely caused by missing Distribution Gradle plugin or missing dependency for the App Distribution Gradle plugin. ###### Solution 1. In your root-level (project-level) Gradle file (usually android/build.gradle), add the App Distribution Gradle plugin as a buildscript dependency: ```groovy buildscript { repositories { // Make sure that you have the following two repositories google() // Google's Maven repository mavenCentral() // Maven Central repository } dependencies { ... classpath("com.android.tools.build:gradle:9.2.0") // Make sure that you have the Google services Gradle plugin dependency classpath("com.google.gms:google-services:4.4.4") // Add the dependency for the App Distribution Gradle plugin classpath("com.google.firebase:firebase-appdistribution-gradle:5.2.1") } } ``` 2. In your module (app-level) Gradle file (usually android/app/build.gradle), add the App Distribution Gradle plugin, and make sure that it is located below **com.android.application** plugin because the sequence of applying plugin matters: ```groovy apply plugin: 'com.android.application' apply plugin: 'com.google.firebase.appdistribution' ``` Check the [official Firebase documentation](https://firebase.google.com/docs/app-distribution/android/distribute-gradle?apptype=aab#step_1_set_up_your_android_project) for more information. {{< /collapsible >}} ================================================================================ source: https://docs.codemagic.io/troubleshooting/common-windows-issues/ title: Common Windows issues description: How to overcome common issues building mobile apps on Codemagic with Windows last_modified: 2026-02-18 ================================================================================ # Common Windows issues > How to overcome common issues building mobile apps on Codemagic with Windows ### Cannot access variables from the app ###### Description You can't access the variable directly by using `$VAR_NAME`. {{}} You can reference the variable in subsequent parts of your workflow by using `$env:VAR_NAME`. However, when using a variable to set another variable in the `vars:` section, use the following syntax: ```yaml environment: vars: VAR_1: ---\$VAR_2\--- ``` {{< /collapsible >}} ### Using Command Prompt ###### Description The default shell on the Windows machines is `PowerShell`, but you need to run scripts using `Command Prompt`. {{}} Invoke the `Command Prompt` app directly and pass your script as an argument: ```yaml scripts: - name: Run a command in Command Prompt script: | cmd.exe \c YOUR_COMMAND_HERE ``` {{< /collapsible >}} ### Script with spaces and quotes not behaving as expected ###### Description When PowerShell sees a command starting with a string, it just evaluates the string. Typically, this means echoing it to the screen: ```powershell PS> "C:\Program Files\Unity Hub\Unity Hub.exe" Hello World ``` {{}} If you want PowerShell to interpret the string as a command name, use the call operator **(&)**: ```powershell & 'C:\Program Files\Unity Hub\Unity Hub.exe' ... ``` If you want to use `PowerShell` to run an `.exe` file with parameters that contain spaces or quotes, use the `Start-Process` method: ```powershell Start-Process -NoNewWindow -FilePath "path-to-your-exe-file" -ArgumentList 'your-arguments-are-here' -Wait ``` {{< /collapsible >}} ### Wrong value in base64 encoded environment variables ###### Description Scripts fail when using `base64` encoded variables or use incorrect values. {{}} Encoded variables need to be decoded back into their original form before they can be used. For example, to decode a variable `$VAR1` and save the result as variable `PATH`, use the following script: ```powershell [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("$env:VAR1")) | Out-File -FilePath $env:PATH ``` {{< /collapsible >}} ### Cannot access the build machine using SSH or VNC/RDP ###### Description Linux and macOS machines can be accessed using SSH or VNC. However, the access does not work when using a Windows build machine. {{}} SSH and VNC access is not available on Windows build machines. You can access them using an RDP client instead. Learn more: [Remote access to the build machine](../troubleshooting/accessing-builder-machine-via-ssh/). {{< /collapsible >}} ================================================================================ source: https://docs.codemagic.io/yaml-basic-configuration/configuring-environment-variables/ title: Environment variables and variable groups description: How to configure environment variables and groups in Codemagic last_modified: 2026-03-17 ================================================================================ # Environment variables and variable groups > How to configure environment variables and groups in Codemagic Environment variables are the recommended way to store configuration settings and sensitive data—such as credentials, configuration files, or API keys—needed for successful builds and integrations with external services. Sensitive information should never be committed to your Git repository. Instead, add it securely as environment variables in the Codemagic UI, where it can be accessed during workflows without being exposed in version control. If you're storing **secrets** in environment variables, you can enable an extra layer of security by marking the variable as **Secret**. This encrypts the variable and hides its value in the UI and build logs. You can add environment variables and secrets on the [app level](#app-level-environment-variables) or on the [team level](#global-variables-and-secrets) to make them available across team apps. Codemagic organizes user-defined environment variables into **variable groups** which you can import during the build, read more about it [below](#variable-groups-and-accessing-variables). Codemagic also provides a variety of built-in environment variables to streamline your workflows. You can check the full list [here](../yaml-basic-configuration/environment-variables). See an overview of how to work with environment variables in Codemagic in the video below.
{{< youtube 7pAxVFe66hI >}} ## Variable groups and accessing variables All environment variables and secrets added in the Codemagic UI must be assigned to a **group**. To make the variables available to the build machine, the variable group must be referenced in your codemagic.yaml workflow. A variable group allows you to define and store related environment variables that can be imported together in a codemagic.yaml file. For instance, you might create separate `staging` and `production` groups, each containing variables with the same names but different values. By importing the appropriate group in your workflow, you can reuse the same script logic while dynamically applying environment-specific configurations. Variable groups to be imported are listed in the [environment section](../yaml-basic-configuration/yaml-getting-started#environment) of codemagic.yaml. For example, variable groups named `staging` and `production` can be imported using the following syntax: ```yaml workflows: workflow-name: environment: groups: - staging - production ``` Variables defined in environment variable groups work exactly as all other environment variables. E.g., the value of a variable named `API_TOKEN` can be referenced in a workflow as `$API_TOKEN`. ## App-level environment variables The environment variables you add in application settings are accessible only to the application at hand. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**. 3. Enter the **_Variable value_**. 4. Enter the variable group name, e.g. **_appstore_credentials_**. Click the button to create the group. 5. If the **Secret** option is selected, the variable will be protected by encryption. Its value will not be visible in Codemagic UI or build logs, it will be transferred securely to the build machine and made available only while the build is running. 6. Click the **Add** button to add the variable. ## Global variables and secrets The **Global variables and secrets** section in team settings allows defining variable groups that can be made available to any application of the team. It is possible to limit applications' access to the variable group in variable group settings. Selecting **All applications** will grant all present and future apps access to the variable group. You can review application access settings anytime. Marking a variable **Secret** will encrypt the variable and hide its value in the Codemagic UI and build logs. The variable will be transferred securely to the build machine and made available only while the build is running. ### Bulk import of variables To add many variables at once, click **Add variables** and select the option to import variables from a `.env` file. For each variable listed in the upload modal, you can choose to enable extra security by clicking the lock icon. ## Storing binary files In order to store **_binary files_** in environment variables, they first need to be **_base64 encoded_** locally. To use the files, you will have to decode them during the build. Commonly used binary files that need to be base64 encoded include: - Android keystore (.jks or .keystore) - Provisioning profiles when manual code signing (.mobileprovision) - iOS distribution certificate (.p12) when manual code signing. The following examples show how to save a file named `codemagic.keystore` depending on your OS: ### Option: Linux For Linux machines, we recommend installing xclip: ```Shell sudo apt-get install xclip cat codemagic.keystore | base64 | xclip -selection clipboard ``` Alternatively, you can run the following command and carefully copy/paste the output: ```Shell openssl base64 -in codemagic.keystore ``` > > **Tip**: When copying file contents always include any tags. e.g. Don't forget to copy `-----BEGIN PRIVATE KEY-----` and `-----END PRIVATE KEY-----` too. > ### Option: macOS On macOS, running the following command base64 encodes the file and copies the result to the clipboard: ```Shell cat codemagic.keystore | base64 | pbcopy ``` ### Option: Windows For Windows, the PowerShell command to base64 encode a file and copy it to the clipboard is: ```powershell [Convert]::ToBase64String([IO.File]::ReadAllBytes("codemagic.keystore")) | Set-Clipboard ``` After running these command lines, you can paste the automatically copied string into the Variable value field in Codemagic UI. > > **Tip**: A convenient way to check if a file is binary is to try to peek into the file using `less filename.extension`. If it is binary, you'll be asked "**_filename maybe is a binary file. See it anyway?_**" > ### Using binary files during build In order to use binary files during the build time, you need to `base64` decode them and generate the file again. This can be performed with a simple `echo` command in a script. ```yaml workflows: workflow-name: environment: scripts: - name: Generate keystore file script: | echo $YOUR_ENVIRONMENT_VARIABLE | base64 --decode > /path/to/decode/to/codemagic.keystore ``` ## Environment variable precedence Environment variables with the same name and group from different sources will have the following precedence: 1. API variables 2. Application variables 3. Global variables This means that variables defined in a scope of higher precedence will override variables defined in a lower scope if they have the same name. If variables with the same name are defined and imported from different variable groups of the same level of precedence, the values from the last imported variable group will be used. For example, if two application variable groups `magic` and `wand` are defined each with a variable named `magic_number` and imported in a codemagic.yaml like so: ```yaml environment: groups: - magic - wand ``` Then the variable value in the group `wand` will be used. ## Commonly used variable examples #### Android builds The following variable groups and variables are commonly used in Android builds. Add them in Codemagic UI (either as Application or as Team variables), make sure to click **Secret** to make sensitive data encrypted, and include the variable groups in your workflow. **Variable name** | **Variable value** | **Group** --- | --- | --- CM_KEYSTORE_PATH | /tmp/keystore.keystore | keystore_credentials CM_KEYSTORE | contents of keystore - [`base64 encoded`](#storing-binary-files) | keystore_credentials CM_KEYSTORE_PASSWORD | Put your keystore password here | keystore_credentials CM_KEY_PASSWORD | Put your key alias password here | keystore_credentials CM_KEY_ALIAS | Put your key alias here | keystore_credentials GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS | Put your Google Play service account credentials here | google_play_credentials GOOGLE_PLAY_TRACK | Any default or custom track that is not in ‘draft’ status | google_play_credentials PACKAGE_NAME | Put your package name here | other ```yaml environment: groups: - keystore_credentials - google_play_credentials - other ``` #### iOS builds The following variable groups and variables are commonly used in iOS builds. Add them in Codemagic UI (either as Application or as Team variables), make sure to click **Secret** to make sensitive data encrypted, and include the variable groups in your workflow. **Variable name** | **Variable value** | **Group** --- | --- | --- APP_STORE_CONNECT_ISSUER_ID | Put your App Store Connect Issuer Id here | appstore_credentials APP_STORE_CONNECT_KEY_IDENTIFIER | Put your App Store Connect Key Identifier here | appstore_credentials APP_STORE_CONNECT_PRIVATE_KEY | Put your App Store Connect Private Key here | appstore_credentials CERTIFICATE_PRIVATE_KEY | Put your Certificate Private Key here | appstore_credentials BUNDLE_ID | Put your bundle id here | ios_config APP_STORE_ID | Put your TestFlight Apple id number (General > App Information > Apple ID) | ios_config XCODE_WORKSPACE | Put the name of your workspace here | ios_config XCODE_SCHEME | Put the name of your scheme here | ios_config ```yaml environment: groups: - appstore_credentials - ios_config ``` ================================================================================ source: https://docs.codemagic.io/flutter-publishing/publishing-to-google-play/ title: Google Play publishing with Flutter workflow editor description: Deploy a Flutter app to Google Play using the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # Google Play publishing with Flutter workflow editor > Deploy a Flutter app to Google Play using the Flutter workflow editor Codemagic enables you to automatically publish your app to the **internal**, **alpha**, **beta** and **production** tracks on Google Play. To do so, you must first [set up Android code signing](../code-signing/android-code-signing/ 'Android code signing') and then configure publishing to Google Play. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured with **codemagic.yaml** please go to [Publishing to Google Play using codemagic.yaml](../yaml-publishing/google-play). > ## Requirements 1. Setting up access using Google Play API as shown below. 2. A **service account in Google Play Console** to obtain the **JSON credentials file** 3. Granting the necessary App permissions and access permissions to the service account. 4. You must build the app in **release mode** and set up **Android code signing**. You can check it [here](../flutter/flutter-projects/#building-android-app-bundles). Before releasing the app to Google Play, ensure that it meets [Google Play's best practices guidelines](https://developer.android.com/distribute/best-practices/launch/). ## Setting up Google Play API access To allow Codemagic to publish applications to Google Play, it is necessary to set up access using Google Play API. 1. Open your app's project on the [Google Cloud Console](https://console.cloud.google.com/) (or create a new one [here](https://console.cloud.google.com/projectcreate) if necessary). 2. Enable the [Google Play Android Developer API](https://console.developers.google.com/apis/api/androidpublisher.googleapis.com/). ![Google Cloud 1](../uploads/2024/9/google_cloud_1.png) 3. Create a new service account from **CREATE CREDENTIALS** on the [Credentials menu page](https://console.cloud.google.com/apis/credentials). ![Google Cloud 2](../uploads/2024/9/google_cloud_2.png) 4. In Step 1, enter the account name and description. ![Google Cloud 3](../uploads/2024/9/google_cloud_3.png) 5. In Step 2, select the **Service Accounts > Service Account User** role. ![Google Cloud 4](../uploads/2024/9/google_cloud_4.png) 6. Step 3 is unnecessary, so complete it by clicking **Done**. ![Google Cloud 5](../uploads/2024/9/google_cloud_5.png) 7. Open the edit page from the **Actions** column of the created service account. ![Google Cloud 6](../uploads/2024/9/google_cloud_6.png) 8. From the **KEYS** tab page, click on **ADD KEY > Create new key**. ![Google Cloud 7](../uploads/2024/9/google_cloud_7.png) 9. Select **JSON** as the Key type and create a new key. ![Google Cloud 8](../uploads/2024/9/google_cloud_8.png) 10. The private key for this service account will be downloaded. Please store it in a safe place as it will be necessary later for the Codemagic configuration. ![Google Cloud 9](../uploads/2024/9/google_cloud_9.png) 11. Once you've completed this, let's move to the [Google Play Console](https://play.google.com/console). 12. Click on **Invite new users** on the **Users and permissions** page. ![Google Play 1](../uploads/2024/9/google_play_console_1.png) 13. For the **Email address**, enter the one for the service account you just created. ![Google Play 2](../uploads/2024/9/google_play_console_2.png) 14. From the **Add app**, select the target app. ![Google Play 3](../uploads/2024/9/google_play_console_3.png) 15. Grant permissions for the **Releases** section (the rest of the settings can be left as default), and click **Apply**. ![Google Play 4](../uploads/2024/9/google_play_console_4.png) 16. Invite the service account by clicking **Invite user**. ![Google Play 5](../uploads/2024/9/google_play_console_5.png) ## Setting up publishing to Google Play on Codemagic Once you make all the preparations as described [above](../publishing/publishing-to-google-play/#requirements) and configure publishing to Google Play, Codemagic will automatically distribute the app to Google Play every time you build the workflow. > > **Note:** The very first version of the app must be added to Google Play manually. You can download the **app_release.aab** from the build artifacts. In addition, each uploaded binary must have a different version; see how to automatically [increment build version](../building/build-versioning/ 'Build versioning') on Codemagic. > 1. Navigate to the Distribution section in Workflow editor settings. 2. Click **Google Play** to expand the option. 3. Upload your credentials JSON file. 4. Select a **track** for publishing. - Internal --- publish for internal testing and QA - Alpha --- publish for testing with a small group of trusted users - Beta --- publish for testing to a wider set of users - Production --- release the app to production - Custom --- release the app to a custom closed testing track 5. If you want to publish to a custom track, enter the custom track name. 6. If your application supports [in-app updates](https://developer.android.com/guide/playcore/in-app-updates), set the desired priority. If not, select **Default**. 7. In case you want to release a [staged version](https://support.google.com/googleplay/android-developer/answer/6346149?hl=en) of your application, which reaches only a fraction of users, set **Rollout fraction** to a value between 0 and 1. To release to everyone, leave the value empty. 8. If you are getting the next error: `Changes cannot be sent for review automatically. Please set the query parameter changesNotSentForReview to true`, mark the checkbox **Do not send changes for review**. But if the checkbox is marked and the app is sent for review automatically, you will get the error `Changes are sent for review automatically. The query parameter changesNotSentForReview must not be set.` 9. In case you want to upload the artifacts generated in the build to Google Play as a draft release, select **Submit release as draft**. Note that you cannot set the rollout fraction for draft releases. 10. If you want to publish the .apk even when one or more tests fail, mark the **Publish even if tests fail** checkbox. 11. Select **Enable Google Play publishing** at the top of the section to enable publishing. > > **Note:** You can use the "**Wear OS Only**" track to manage Wear OS releases in Play Console. To target "**Wear OS Only**" track, add **wear:** in the track name. > ================================================================================ source: https://docs.codemagic.io/yaml-publishing/google-play/ title: Google Play publishing with codemagic.yaml description: How to deploy an app to Google Play using codemagic.yaml last_modified: 2026-03-24 ================================================================================ # Google Play publishing with codemagic.yaml > How to deploy an app to Google Play using codemagic.yaml Codemagic enables you to automatically publish your android application to Google Play. > > **Note:** This guide only applies to workflows configured with the **codemagic.yaml**. If your workflow is configured with **Flutter workflow editor** please go to [Publishing to Google Play using Flutter workflow editor](../publishing/publishing-to-google-play). >

{{< youtube qrtk6e0BYjM >}} Codemagic enables you to automatically publish your app either to one of the predefined tracks on Google Play or to your custom closed testing tracks. In order to do so, a service account is required when setting up publishing to Google Play. The service account JSON key file must be added to Codemagic to authenticate with these services. ## Configure Google Play API access 1. To allow Codemagic to publish applications to Google Play, it is necessary to set up access using Google Play API. 2. In the Google Cloud Console, navigate to **Dashboard > IAM and Admin** and click **Create Service Account**.

![Google play start](../uploads/gcp_service_user.png) 3. In step 1, fill in the **Service account details** and click **Create**. The name of the service account will allow you to identify it among other service accounts you may have created. 4. In step 2, click the **Select a role** dropdown menu and choose the role. In this example we will use **Service Account User** as the desired role. Start typing the name of the role that you wish to add.

![Google cloud editor](../uploads/google_cloud_two.png) 5. In step 3, you can leave the fields blank and click **Done**. 6. In the list of created service accounts, locate the account you just created. Copy its email address, which will be required later. Then, click on the menu in the **Actions** column, then click **Manage keys**.

![Google cloud key](../uploads/google_cloud_three.png) 7. In the Keys section, click **Add Key > Create new key**. Make sure that the key type is set to `JSON` and click **Create**. Save the key file in a secure location to have it available.

![Google cloud json](../uploads/google_cloud_four.png) 8. Back in **Google Play Console**, navigate to **Users and Permissions** and click **Invite new users**. Enter the email id which you copied in step 6.
9. Navigate to **Users and Permissions**. Click on the invited user and go to **App Permissions**. Add the desired applications to grant access.

![Google play selected](../uploads/app-permissions.png) 10. Ensure that you check the Releases section. You can leave the rest of the settings as default and click **Apply** (financial data permissions can be left blank).

![Google play apply](../uploads/s4.png) 11. On the **Account permissions** tab, leave everything as it is. (There is NO need to grant the service account **Admin** access). 12. Finally, click **Invite user** to finish setting up the service account on Google Play. In the Invite user window, the Email address field is pre-filled. Under Permissions, the default ones are already selected. You can go with these. Click Invite user at the bottom of the page.

![Google play all](../uploads/s5.png) ## Preparing your first release ⚠️ Important: The very first version of your app must be uploaded to Google Play manually. 1. Run your Codemagic workflow to produce an `app-release.aab`. Make sure to [configure Android code signing](../yaml-code-signing/signing-android/) so the app is properly signed before uploading. 2. Download the generated `app-release.aab` binary from the build artifacts section. 3. Go to your Google Play Console, create your application entry (if it doesn’t exist yet), and manually upload this .aab in Production ![google_play_create_app](../uploads/2024/9/google_play_create_app.png) 4. Create new release (or the track you want to start with). ![google_play_create_new_release](../uploads/2024/9/google_play_create_new_release.png) 5. Complete the required app setup steps (app details, screenshots, content rating, etc.) and roll out your release. After this first manual upload, Codemagic can automatically publish subsequent versions to the track(s) you configured in your codemagic.yaml. Also remember: each new build uploaded to Google Play must have a higher version code than the previously uploaded one. You can automate [incrementing the build versions](../building/build-versioning/ 'Build versioning') in your Codemagic workflows. ## Configure publishing in codemagic.yaml Once you make all the preparations as described above and configure publishing to Google Play, Codemagic will automatically distribute the app to Google Play every time you build the workflow. 1. Save the contents of the `JSON` key file as a [secret environment variable](../variables/environment-variable-groups/#storing-sensitive-valuesfiles) in application or team settings: 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. 3. Copy and paste the key file content as **_Variable value_**. 4. Enter the variable group name, e.g. **_google_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - google_credentials ``` 2. Configure publishing section in `codemagic.yaml` to publish to Google Play: ```yaml publishing: google_play: # Contents of the JSON key file for Google Play service account saved # as a secret environment variable credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS # Name of the track internal, alpha, beta, production, internal app sharing, # or your custom track name track: internal # Optional string. The release name. # Not required to be unique. If not set, the name is generated from the APK's versionName. release_name: Custom release name # Optional Priority of the release (only set if in-app updates are supported) # integer in range [0, 5] in_app_update_priority: 3 # Optional. Rollout fraction (set only if releasing to a fraction of users) # value between (0, 1) rollout_fraction: 0.25 # Optional boolean To be used ONLY if your app cannot be sent for review automatically * changes_not_sent_for_review: true # Optional boolean. Publish artifacts under a draft release. # Can not be used together with rollout_fraction. Defaults to false submit_as_draft: true # Optional. Enable release to be promoted to another track in addition to where it is # originally published. release_promotion: # Name of the track to which release is promoted. track: alpha # Optional. Rollout fraction (set only if releasing to a fraction of users) # value between (0, 1) rollout_fraction: 0.25 # Optional boolean. Promote the release as draft. # Can not be used together with rollout_fraction. Defaults to false promote_as_draft: true ``` 3. Codemagic enables you to automatically publish your app to one of the tracks: - **Internal** --- publish for internal testing and QA - **Alpha** --- publish for testing with a small group of trusted users - **Beta** --- publish for testing to a wider set of users - **Production** --- release the app to production - **Custom** --- release the app to a custom closed testing track In order to publish to a track (e.g. `internal`) and immediately promote the same release to another track (e.g. `alpha`) to reach a wider audience, additionally configure the `release_promotion` section. > > **Note:** You can use the "**Wear OS Only**" track to manage Wear OS releases in Play Console. > To target "**Wear OS Only**" track, add **wear:** in the track name. > > `track: wear:internal` > 4. If your application supports [in-app updates](https://developer.android.com/guide/playcore/in-app-updates), Codemagic allows setting the update priority. Otherwise, `in_app_update_priority` can be omitted or set to `0`. 5. In addition, Codemagic supports [staged releases](https://support.google.com/googleplay/android-developer/answer/6346149?hl=en), allowing users to choose which fraction of the testers or users get access to the application. To release to everyone, omit `rollout_fraction` from codemagic.yaml. > > **Tip:** You can override the publishing track specified in the configuration file using the environment variable `GOOGLE_PLAY_TRACK`. This is useful if you're starting your builds via [Codemagic API](../rest-api/overview/) and want to build different configurations without editing the configuration file. >

> > **Note:** To use different Google Play Console accounts for publishing your Android apps, set up separate workflows. > ================================================================================ source: https://docs.codemagic.io/flutter-code-signing/macos-code-signing/ title: macOS code signing description: How to set up macOS code signing in the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # macOS code signing > How to set up macOS code signing in the Flutter workflow editor Code signing is required by Apple for integrating app services, installing your macOS app on another machine or uploading it to distribute it through the Mac App Store or outside of Mac App Store. It enables you to identify who developed the app and ensure that all the changes to the app come from you or your team. To create an application package that can be published to Mac App Store on Codemagic, you need to set up code signing. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured with **codemagic.yaml** please go to [Signing macOS apps using codemagic.yaml](../code-signing-yaml/signing-macos). > ## Prerequisites Before you can start signing or distributing your app, there are a few things you need. * [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership * An [app ID](https://developer.apple.com/account/resources/identifiers/bundleId/add/) for your macOS app in the Apple Developer portal * **signing certificates** (`Personal Information Exchange, .p12`) * A **provisioning profile** (`.provisionprofile`) The signing certificates — development or distribution — help to identify who built the code. A provisioning profile — development or distribution — contains information about the app ID, the devices on which the app can be installed and the certificates that can be used for signing the app. Note that if your app contains app extensions, you need an additional provisioning profile for each app extension. > > **Note:** With **automatic code signing**, Codemagic will create both the certificate and the provisioning profile on your behalf without requiring a Mac. > > With **manual code signing**, you need to upload the signing files manually. > Signing an application with a development certificate and profile requires the UUID of the machine which builds the application to be present in the profile. Therefore, using a development certificate is not possible on Codemagic since the build machine won't be listed in the used profile. Distribution is possible to Mac App Store (using `Mac App Distribution` and `Mac Installer Distribution` certificates and `Mac App Store` profile) and outside of Mac App Store (using `Developer ID Application` certificate and `Developer ID` profile). **Note**: Currently, Codemagic only supports code signing the app for publishing to the Mac App Store. ## Automatic code signing Codemagic makes automatic code signing possible by connecting to [App Store Connect via its API](https://developer.apple.com/app-store-connect/api/) for creating and managing your code signing certificates and provisioning profiles. It is possible to set up several code signing identities and use different code signing settings per workflow. The following sections describe how to set up automatic code signing for builds configured in the UI. If you're building with `codemagic.yaml`, please refer [here](../code-signing-yaml/signing-macos). Note that Apple Developer Portal has a limitation of a maximum of 2 macOS distribution certificates per team. This means that if you already have 2 `Mac Installer Distribution` certificates, Codemagic won't be able to create new ones. Using existing certificates won't be possible because the private key required to install them is only stored on your machine. You may revoke an existing certificate to allow Codemagic to create a new one using a Codemagic team-specific private key which is only stored on Codemagic. Alternatively, you can use [manual code signing](#manual-code-signing-to-publish-to-mac-app-store). ### Step 1. Creating an App Store API key for Codemagic %!s()The Apple Developer Portal integration can be enabled in the **Team integrations** section in your team settings (if you're a team admin). This allows you to conveniently use the same access credentials for automatic code signing and publishing across different apps and workflows. 1. In the list of available integrations, click the **Connect** button for **Developer Portal**. 2. In the **App Store Connect API key name**, provide a name for the key you are going to set up the integration with. This is for identifying the key in Codemagic. 3. Enter the **Issuer ID** related to your Apple Developer account. You can find it above the table of active keys on the Integrations tab of the [Users and Access](https://appstoreconnect.apple.com/access/integrations/api) page. 4. Enter the **Key ID** of the key to be used for code signing. 5. In the **API key** field, upload the private API key downloaded from App Store Connect. 6. Click **Save** to finish the setup. If you work with multiple Apple Developer teams, you can add additional keys by clicking **Add another key** right after adding the first key and repeating the steps described above. You can delete existing keys or add new ones when you click **Manage keys** next to the Developer Portal integration in personal account or team settings. ### Step 3. Enabling automatic code signing for workflow Once the Apple Developer Portal has been enabled for the account or team the app belongs to, you can easily enable automatic code signing per workflow. 1. Go to **App settings > Distribution > macOS code signing**. 2. Select **Automatic** as the code signing method. If you haven't enabled the Apple Developer Portal integration yet, you will be asked to enable it before you can continue configuration. 3. If you have several keys available, select the right key in the **App Store Connect API key** field. 4. Mark the checkbox **Project type setting > is Mac Catalyst** if you need a Mac Catalyst profile. 7. Select your app's **bundle identifier**. Codemagic lists all the bundle IDs available for the selected App Store Connect API key. If you can't see your app's bundle identifier listed, create one in [Apple Developer Portal](https://developer.apple.com/account/resources/identifiers/add/bundleId). As the next step, you can [configure publishing to App Store Connect](../publishing/publishing-to-app-store) to submit the app to App Store Connect and distribute it via Mac App Store. ## Manual code signing With the manual code signing method, you are required to upload the `Mac App Distribution` and `Mac Installer Distribution` certificates and the `Mac App Store` profile. You can also upload additional profiles if required. >See how to [export certificates and provisioning profiles](#exporting-certificates-and-provisioning-profiles). ### Setting up manual code signing 1. Go to **App settings > Distribution > macOS code signing**. 2. Select **Manual** as the code signing method. 3. Upload your `Mac App Distribution` signing certificate (in `.p12` format). If your certificate is password-protected, enter the **Certificate password**. 3. Upload your `Mac Installer Distribution` signing certificate (in `.p12` format). If your certificate is password-protected, enter the **Certificate password**. 4. Upload your provisioning profile (`.provisionprofile`). Note that if your app contains app extensions, you are required to upload an additional provisioning profile for each extension. {{< figure size="medium" src="../uploads/manual_code_signing_macos.png" caption="Manual macOS code signing setup ================================================================================ source: https://docs.codemagic.io/yaml-distributing/app-preview/ title: Previewing apps in the browser description: Test your iOS or Android app in the browser with App Preview last_modified: 2026-06-18 ================================================================================ # Previewing apps in the browser > Test your iOS or Android app in the browser with App Preview App Preview is our iOS simulator and Android emulator running in your browser. Launch and interact with your iOS or Android app right in the browser, regardless of the operating system you are using. Test your app against different device and OS configurations, emulate GPS location or demo the latest app version without needing access to a physical device. {{< youtube l1VeZXtO0zQ >}} **Tip:** The following sections describe creating previewable artifacts using codemagic.yaml. If you're using the Flutter Workflow Editor, follow the instructions [here](../flutter-distributing/app-preview). ## Enabling App Preview and Free Trial > > This feature is available for **teams** only. > Teams on the **Pay as you go** plan can enable the feature via the **App Preview** page on the left sidebar and will get 100 free trial minutes. Once used up, further app preview minutes will be billed at the rate of $0.095/min and included in your monthly invoice. Teams on annual plans can try out App Preview by [contacting us](https://codemagic.io/contact/). ## Creating iOS .app binaries for previewing on the simulator To create a `.app` to run on the iOS simulator, consult the **codemagic.yaml** samples below. ### Option: iOS Sample **codemagic.yaml** for building an iOS `.app` binary using Xcode build commands. ```yaml workflows: simulator-workflow: name: Build for simulator environment: xcode: latest scripts: - name: Build with Generic Destination script: | xcodebuild build \ -project "yourproject.xcodeproj" \ -scheme "yourscheme" \ -sdk iphonesimulator \ -configuration Debug artifacts: - /Users/builder/Library/Developer/Xcode/DerivedData/**/*.app ``` ### Option: Flutter Sample **codemagic.yaml** for building an iOS `.app` binary for Flutter projects. ```yaml workflows: flutter-ios-simulator: name: Flutter iOS Simulator environment: flutter: 3.27.3 xcode: latest scripts: - flutter build ios --simulator --flavor staging # --flavor is optional artifacts: - build/ios/iphonesimulator/Runner.app ``` On a successful build, you will see the **Quick Launch** button next to the `.app` artifact in build overview. ## Creating Android .apk binaries for previewing on the emulator You can preview any `.apk` artifact built in Codemagic. In your codemagic.yaml, ensure that the `artifacts` section contains the path to the `.apk` artifact so that it is picked up and displayed among the build artifacts in Codemagic, as in the following example. ```yaml workflows: android: name: Android debug workflow scripts: - name: Set Android SDK location script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/local.properties" - name: Build Android script: | ./gradlew assembleDebug artifacts: - app/build/outputs/apk/debug/app-debug.apk ``` On a successful build, you will see the **Quick Launch** button next to the `.apk` artifact in build overview. ## Previewing apps Clicking **Quick Launch** next to a suitable artifact launches an iOS simulator or an Android emulator respectively with your app installed on it, right in your browser. To use a different device and OS combination, click the three dots on the controls menu and select **Change device**. The preview session remains active for a maximum of **20 minutes** and is limited to one concurrent session by default. To end the ongoing session, select **Stop session** from the menu. ================================================================================ source: https://docs.codemagic.io/billing/pricing/ title: Pricing description: An overview of Codemagic pricing last_modified: 2026-08-10 ================================================================================ # Pricing > An overview of Codemagic pricing ## React Native CodePush React Native CodePush is available to teams via two subscription models: Pay-as-you-go (billed monthly per successful install) or Fixed-price plan (pay up-front per Monthly Active Users). ### Pay-as-you-go This is a flexible, usage-based plan charged on the number of successful installs per month. You are charged $1 for every 2,500 installs (or fewer), with a minimum charge of $1. You are billed on the 1st of each month for the previous month's usage. ### Fixed price CodePush (Over-the-Air updates) for React Native projects is priced as follows: 1. $99/month per 100k Monthly Active Users (MAU) 2. No limit on updates and bandwidth 3. We can offer up to 12 months up front payment, otherwise billing is monthly. Invoicing is available starting 1M MAU. > > 🔔 Annual subscriptions get 2 months of free usage discount. > | Monthly Active Users (MAUs) | Monthly price (USD) | Yearly price (USD) | |-----------------------------|---------------------|----------------------| | 10,000 | $99 | $990 | | 100,000 | $99 | $990 | | 150,000 | $198 | $1,980 | | 500,000 | $495 | $4,950 | | 1,000,000 | $990 | $9,900 | | 2,000,000 | $1,980 | $19,800 | | 5,000,000 | $4,950 | $49,500 | | 10,000,000 | $9,900 | $99,000 | ## CI/CD ### Pricing for Individuals #### 1. Free plan This plan is suitable for individuals working on hobby or indie projects. You can also use this plan for running a proof of concept. Individuals receive **500 free minutes** per month on macOS M2 machines on a personal account. These 500 free minutes are **reset on the 1st of each month**. Free minutes are not available if you are using a Team. You cannot invite collaborators to an individual plan. To start using Codemagic for free, [sign up here](https://codemagic.io/signup). #### 2. Buying Additional Minutes You can enable billing on personal accounts and pay for any additional minutes you want to use. You will still have **500 free build minutes** on macOS M2 VM. To enable billing, proceed [here](https://codemagic.io/billing/user). Postpaid minutes are billed on the first day of the following month in which they were used. Usage on macOS M2 VM that exceeds 500 minutes is charged at the rate shown below. Builds on Linux and Windows do not have free build minutes. The per-minute pricing for each instance type is shown below. | **Item** | **Price** | | ---------------------------- | --------------------------------- | | macOS (M2) VM | $0.095 / minute | | macOS (M4) VM | $0.114 / minute | | Linux X2 & Windows VMs | $0.045 / minute | ### Pricing for Teams #### 1. Pay-as-you-go For teams, all build minutes using macOS M2 VM, macOS M4 VM, Linux VM, and Windows VM are charged at the rates shown below. Each extra build concurrency allows running an additional build in parallel. For example, adding two extra build concurrencies allows running a total of three builds in parallel. You can **add additional concurrencies** in the Codemagic web app by clicking 'Billing' in the left-hand menu. In the 'Billing Overview' click **Update** in the Build concurrency section and select the number of concurrencies you wish to add to your Team. Each additional concurrency is $49/month and you will be billed for each concurrency on the last day of each month. | **Item** | **Price** | | -------------------------- | --------------- | | macOS (M2) VM | $0.095 / minute | | macOS (M4) VM | $0.114 / minute | | Linux X2 & Windows VMs | $0.045 / minute | | Extra build concurrency | $49 / month | Consider an annual or Enterprise plan if more than three concurrent builds are required or if you would like unlimited build minutes on macOS (Apple Silicon M4 Max), Linux, and Windows instances. #### 2. Fixed Annual Plans The following options are available for teams with different macOS machines: ### Option: macOS M2">}} An annual subscription with access to **macOS M2s** instances and **2 months free** is **$3,990/year**. The Codemagic **macOS M2** annual plan gives you a fixed-price plan with the following benefits: * 3 concurrencies (with access to macOS M2, Linux X2, and Windows instances) * Unlimited build minutes * Unlimited team seats * In-app chat support * Additional concurrencies are **$1,500/year**. The fixed annual plan can only be paid with a credit card. If you have already created a Team in the Codemagic web app, you can upgrade to the annual plan as follows: 1. Log in to Codemagic. 2. Click **Billing** in the left-hand menu. 3. Click on the **Enable billing** button. 4. Enter your **credit card** details and **company information**. 5. Once you have entered your details, Pay-as-you-go billing will be enabled. To upgrade to the Fixed-price annual plan, click on the **Upgrade** button and follow the instructions to subscribe to the Fixed-price annual plan. If you require additional concurrencies or have any other questions about the annual plan, including requests for **macOS M4 instances**, please contact us [here](https://codemagic.io/pricing/#enterprise). If you require annual invoicing, please refer to the Enterprise plans below. %!s() ### Option: macOS M4 An annual subscription with access to **macOS M4** instances is **$5,400/year**. The Codemagic **macOS M4** annual plan gives you a fixed-price plan with the following benefits: * 3 concurrencies (with access to macOS M4, Linux X4, and Windows instances) * Unlimited build minutes * Unlimited team seats * In-app chat support * Additional concurrencies are **$1,800/year**. The **macOS M4** annual plan can only be paid with a credit card. To request this plan, please contact us [here](https://codemagic.io/pricing/#enterprise) ### Option: macOS Mac Studio M4 Max The Codemagic **macOS Mac Studio M4 Max** annual plan gives you a fixed-price plan with the following benefits: * 3 concurrencies (with access to macOS Mac Studio M4 Max, Linux X4, and Windows instances) * Unlimited build minutes * Unlimited team seats * In-app chat support The **macOS Mac Studio M4 Max** annual plan can only be paid with a credit card. To request this plan, please contact us [here](https://codemagic.io/pricing/#enterprise) ### Burstable concurrencies Burstable concurrencies allow you to use more concurrencies than you otherwise would have available during peak times and pay **1/3** of the price for those concurrencies. If queue time is important for you, you can have a reserve of concurrencies available to use during high demand so you don’t build up a queue. Similarly, if you’re making a big release that would otherwise take a long time, you could use burstable concurrencies. > > 🔔 Burstable concurrencies are available starting from 10 concurrencies and you will get billed monthly using the 95th percentile method. > To determine which concurrencies are bursted and which ones are not we divide the billing period into 5 second intervals and sample concurrency usage every 5 seconds. We then reorder this graph in descending order so the left of the graph consists of high use of concurrency and the tail end of the graph is low use of concurrency. We then discard 5% of the high use as “bursting” and consider only the use at 95th percentile. If you subscribe to 10 concurrencies and consume 4 within the 95th percentile, then you pay full price for 4 and **1/3** of the price for the remaining 6. ### Pricing for Enterprises This plan is recommended if you need to go through a **security compliance process**, **vendor registration** or have special requirements such as an **NDA**, **DPA**, **dedicated hosts**, **custom base images**, or other account management services. Enterprise plan pricing starts from $12k/year. The following options are available with the Enterprise offering: ### Option: macOS M4 - Unlimited builds on: - macOS M4 (Mac mini M4 10-core CPU / 16GB RAM) - Linux X4 (16 vCPUs, 64 GB memory) - Windows (8 vCPUs, 32 GB memory) - 180-minute build timeout - Priority support - Private Slack/Discord/MS Teams channel - Service level agreement - Account management services - Technical account manager - Audit Log Connector - Build Analytics Dashboard - SSO Login (OpenID, OAuth2 or SAML 2.0) - OpenID Connect (on request) If you would like more information about our Enterprise plan, please contact us [here](https://codemagic.io/pricing/#enterprise). ### Option: macOS Studio M4 Max - Unlimited builds on: - macOS Studio M4 Max (Mac Studio M4 Max 16-core CPU / 32GB RAM) - Linux X4 (16 vCPUs, 64 GB memory) - Windows instances (8 vCPUs, 32 GB memory) - 180-minute build timeout - Priority support - Private Slack/Discord/MS Teams channel - Service level agreement - Account management services - Technical account manager - Audit Log Connector - Build Analytics Dashboard - SSO Login (OpenID, OAuth2 or SAML 2.0) - OpenID Connect (on request) If you would like more information about our Enterprise plan, please contact us [here](https://codemagic.io/pricing/#enterprise). ### Option: Virtual Private Cloud A Virtual Private Cloud (VPC) of dedicated **Mac mini M4** or **Mac Studio M4 Max** hosts can be set up for your organization. It is only used by your organization and provides 2 VMs that can be configured with the software you require. Dedicated hosts can also be EU-based if you have specific data residency requirements. If you would like more information about our Enterprise plan, please contact us [here](https://codemagic.io/pricing/#enterprise). ### Option: Enterprise Billing Annual invoicing with bank transfer is available for Enterprise plans. Payment is also possible via **AWS Marketplace** and **Google Cloud Marketplace** private offers. Discounts are available for multi-year contracts. Codemagic is **SOC 2 Type II** audited and the report is available on request. If you would like more information about our Enterprise plan, please contact us [here](https://codemagic.io/pricing/#enterprise). ### Resellers It's possible to resell the Codemagic Enterprise plan. Contact us [here](https://codemagic.io/pricing/#enterprise) for further details. ### Build history and artifact storage Build history and artifact retention periods depend on your account type and pricing plan. We retain your build records, logs, and artifacts stored in Codemagic for the applicable retention period, after which they are automatically deleted.
| **Account type** | **Retention period** | |---------------|-------------------| | Personal accounts | 30 days | | Teams on Pay as you go plan | 60 days | | Teams on Fixed Annual plan | 1 year | | Enterprise plans | 1 year by default | #### Backing up build artifacts If you need to support older versions of your application and need access to old versions of your `ipa`, `apk`, `dSYM`, and proguard mapping files to debug issues, then these should be downloaded and stored outside Codemagic. Once they have been deleted from Codemagic, they cannot be retrieved. You can download build artifacts via the Codemagic UI or using the [Codemagic REST API](../rest-api/builds/). To keep copies of your future build artifacts, we advise you to set up publishing to external storage, see an example [here](../yaml-distributing/aws/). #### Instance Types Codemagic provides macOS, Windows, and Linux instance types. The instance types and hardware specifications can be found below. | **Item** | **Specification** | | ------------------------ | --------------------------------------------------------------------------------| | macOS M2 VM | Mac mini M2 8-core CPU / 8GB RAM | | macOS M4 VM | Mac mini M4 10-core CPU / 16GB RAM | | macOS Studio M4 Max VM | Mac Studio M4 Max 16-core CPU / 32GB RAM | | Linux X2 VM | 8 vCPUs, 32 GB memory | | Linux X4 VM | 16 vCPUs, 64 GB memory | | Windows VM | 8 vCPUs, 32 GB memory > > To access more powerful macOS M4 Max Studio and Linux X4, please get in touch with us [here](https://codemagic.io/pricing/#enterprise). > If you are planning to run instrumentation tests with Android emulators, it is advised to use Linux instances. Please note that Android emulators are not available on macOS M2 VMs due to the Apple Virtualization Framework not supporting nested virtualization. For Linux instances, details of the hardware specification, system information, and pre-installed software can be found [here](https://docs.codemagic.io/specs/versions-linux/) For macOS instances, details of the hardware specification, system information, and pre-installed software can be found [here](https://docs.codemagic.io/specs/versions-macos/) For Windows instances, details of the hardware specification, system information, and pre-installed software can be found [here](https://docs.codemagic.io/specs/versions-windows/) ================================================================================ source: https://docs.codemagic.io/yaml-notification/telegram/ title: Sending Build Notifications to Telegram description: Automate sending a notification message to Telegram with APK, AAB, or IPA download links using its HTTP API via cURL last_modified: 2026-05-29 ================================================================================ # Sending Build Notifications to Telegram > Automate sending a notification message to Telegram with APK, AAB, or IPA download links using its HTTP API via cURL This guide shows you how to automate the process of sending APK, AAB, or IPA download links to Telegram using Codemagic's CI/CD pipeline. ### Prerequisites To set up Telegram notifications, you'll need: - A **Telegram Bot Token**, obtained by creating a bot. - The **Chat ID** where the bot will send the messages. Check [Telegram documentation](https://core.telegram.org/bots#how-do-i-create-a-bot) for instructions on creating a bot. ### Add Environment Variables in Codemagic Add the following environment variables to your project settings in Codemagic: - **TELEGRAM_BOT_TOKEN**: Your Telegram bot token - **TELEGRAM_CHAT_ID**: The ID of the chat where the bot will send notifications - **CODEMAGIC_API_TOKEN**: Your Codemagic API token (found under **Account settings > API token**) ### Setup Codemagic Configuration To publish the binary to Telegram, you first need to create a public download URL for the .aab file and set an expiration timestamp. Then, this URL will be sent via the Telegram bot. Add the following configuration to your codemagic.yaml file: ```yaml android-workflow: name: Android Workflow instance_type: mac_mini_m2 environment: vars: TELEGRAM_BOT_TOKEN: "telegram-bot-token" TELEGRAM_CHAT_ID: "telegram-chat-id" CODEMAGIC_API_TOKEN: "codemagic-api-token" scripts: # Your existing build scripts here artifacts: - build/**/outputs/**/*.aab publishing: scripts: - name: Publish to Telegram script: | # Fetch the artifact URL for the .aab file ARTIFACT_URL=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith(".aab")) | .url') # Set the expiration timestamp for the public URL (3 days from now) expiration_timestamp=$(date -v+3d +%s) # use expiration_timestamp=$(date -d "+3 days" +%s) for Linux # Create a public download URL for the artifact response=$(curl -s -H "Content-Type: application/json" \ -H "x-auth-token: $CODEMAGIC_API_TOKEN" \ -d "{\"expiresAt\": $expiration_timestamp}" \ -X POST $ARTIFACT_URL/public-url) public_url=$(echo $response | jq -r '.url') # Send the public URL to Telegram curl -s -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage" \ -d chat_id="$TELEGRAM_CHAT_ID" \ -d text="Here is the public URL for the .aab file: $public_url" ``` ================================================================================ source: https://docs.codemagic.io/rn-codepush/setup/ title: Setup description: Get CodePush running with Codemagic and React Native last_modified: 2026-06-05 ================================================================================ # Setup > Get CodePush running with Codemagic and React Native This section prepares a project to use CodePush with Codemagic. After completing these steps you will have: - a CodePush project created on the Codemagic server - the CLI installed and authenticated - a React Native app configured to receive OTA updates Codemagic hosts the CodePush server and developers interact with it using [access keys](#authenticate-the-cli) and the CodePush CLI. If you want to learn about how OTA updates work, check out the [concepts page](https://docs.codemagic.io/rn-codepush/concepts/). These instructions are for React Native New Architecture projects. If your app is already configured, skip to setting up [deployment keys](#add-codepush-to-a-react-native-app) and CI sections to verify configuration. The same Codemagic server can be used for all of your apps. > > ### Teach your AI assistant to use CodePush (Optional) > > Codemagic publishes a **Codemagic CodePush** agent skill for AI coding assistants. It gives your assistant the knowledge needed to configure your app, troubleshoot issues and use the CLI. > > Run the following in your terminal to install the skill. You will be asked which agents you use; the installer configures them accordingly. > > `npx skills add https://github.com/codemagic-ci-cd/codemagic-skills/tree/main/skills/codemagic-codepush` > > --- ## Install and configure the CLI Install the CodePush CLI globally: ```bash npm install -g @codemagic/code-push-cli ``` Verify the installation: ```bash code-push --version ``` This command prints the installed CLI version. If the installation was successful, you will see a version number (e.g., x.x.x). If the command is not found, it usually means the CLI was not installed correctly. ## Authenticate the CLI The CodePush CLI authenticates using access keys provided by Codemagic. Read more about how to obtain the access key [here](./security-and-access/#obtaining-the-access-key). To log in from the CLI, you can either provide the access token during the login process: ```bash code-push login --access-key $ACCESS_TOKEN ``` Alternatively, you can attach it when prompted by the following command: ```bash code-push login ``` This command authenticates the CLI directly using the provided access token. Once authenticated, the CLI can create apps, manage deployments, and publish updates. ## Create a CodePush project Each mobile application using CodePush must be registered on the server. This step creates a record on the CodePush server that your app will connect to for receiving updates. In most cases, you should create separate apps for each platform, for example: * MyApp-Android * MyApp-iOS React Native bundles differ between platforms, so separating them ensures that each app receives the correct update package and avoids compatibility issues. To create an Android app using the CLI: ```bash code-push app add MyApp-Android ``` For iOS: ```bash code-push app add MyApp-iOS ``` You can use any naming convention, but including the platform in the name is recommended for clarity when managing multiple apps. When an app is created, CodePush automatically creates two deployments: * Staging * Production These deployments act as separate release channels, allowing you to control which users receive which updates. * Staging → typically used for testing updates internally * Production → used for releasing updates to end users You can create additional deployments if needed (e.g., QA, Beta), depending on your workflow by running `code-push deployment add `. It is possible to rename existing deployments through `code-push deployment rename ` and delete via `code-push deployment rm ` ## Add CodePush to a React Native app After configuring the server and CLI, the next step is integrating the CodePush client SDK into your React Native application. This allows your app to receive over-the-air (OTA) updates without going through the app store. 1. **Install the React Native CodePush package:** ```bash # Using npm npm install @code-push-next/react-native-code-push # Using yarn yarn add @code-push-next/react-native-code-push ``` The SDK handles checking for updates, downloading new bundles, and applying updates when the app restarts. 2. **Configure Deployment Keys** Each CodePush deployment has a deployment key that tells the app which deployment to check for updates. List deployments and keys: ```bash code-push deployment list -k ``` Recommended usage: * Development builds → Staging deployment key * Production builds → Production deployment key This ensures test updates do not reach production users. Deployment keys are typically injected via environment variables or set in platform configuration files. 3. **Configure Server URL and Deployment Keys in Native Projects** To connect your React Native app to the CodePush server, you must configure the server URL and the deployment key in your native project files. These values tell the app which server to check for updates and which deployment channel to use. Server URL for Codemagic hosted service: ```bash https://codepush.pro/ ``` iOS (Info.plist) example: ```bash CodePushServerURL https://codepush.pro/ CodePushDeploymentKey YOUR_DEPLOYMENT_KEY ``` > > 📒 Notes: > * Replace YOUR_DEPLOYMENT_KEY with the key for Staging (development builds) or Production (release builds). > * These keys can also be injected dynamically using build scripts or environment variables to avoid hardcoding sensitive information. > * Ensures the app connects to the correct deployment when it starts. > Android (strings.xml) example: ```bash https://codepush.pro/ YOUR_DEPLOYMENT_KEY ``` > > 📒 Notes: > > * Same as iOS, use the correct deployment key for your build type. > * If you have multiple build variants (e.g., debug, release), configure keys separately for each variant to prevent test updates from reaching production users. > 4. **Wrap Your Root Component with CodePush** Integrate CodePush by wrapping your app’s root component: ```bash import codePush from '@code-push-next/react-native-code-push'; function App() { // Your app code here } export default codePush(App); ``` This enables the SDK to automatically check for updates on app start (or based on your chosen update strategy). By default, CodePush looks for updates each time the app launches. When an update is found, it downloads it quietly in the background and applies it the next time the app restarts, whether triggered by the user or the operating system. If you want your app to detect updates faster, you can configure it to sync with the CodePush server whenever the app returns from the background: ```bash let codePushOptions = { checkFrequency: codePush.CheckFrequency.ON_APP_RESUME, }; class MyApp extends Component {} MyApp = codePush(codePushOptions)(App); ``` Alternatively, if you need more precise control over when update checks occur—such as after a button tap or at scheduled intervals—you can invoke CodePush.sync() whenever needed with your preferred SyncOptions. You can also disable CodePush’s automatic update checks by setting the checkFrequency to manual: ```bash let codePushOptions = { checkFrequency: codePush.CheckFrequency.MANUAL }; class MyApp extends Component { onButtonPress() { codePush.sync({ updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE, }); } render() { return ( Check for updates ); } } MyApp = codePush(codePushOptions)(App); ``` ### CodePush iOS Setup (React Native) This guide covers the iOS-specific configuration required to enable CodePush OTA updates in your React Native app. **1. Install iOS Dependencies** Navigate to the ios directory and install CocoaPods: ```bash cd ios && pod install && cd .. ``` **2. Update AppDelegate** You need to configure your app to load the JavaScript bundle from CodePush instead of the embedded bundle. **Objective-C**: If your project is `Objective-C` based (scroll down for `Swift` based configuration), then open the `AppDelegate.m` file and add an import statement for the CodePush headers at the top: ```text #import ``` **3. Update JS Bundle Location** Find the following existing bundle reference in the `AppDelegate.m` file: ```bash jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; ``` And replace it with: ```bash jsCodeLocation = [CodePush bundleURL]; ``` At the end, your `sourceURLForBridge` method should look like this: ```bash - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else return [CodePush bundleURL]; #endif } ``` **Swift**: If your project is using `Swift` based configuration, then follow the steps below: 1. Navigate to your iOS project and open the `AppDelegate.swift` file 2. Add the following import at the top of the file: ```bash import CodePush ``` 3. Find the following line of code in the `AppDelegate.swift` file: ```bash Bundle.main.url(forResource: "main", withExtension: "jsbundle") ``` And replace it with: ```bash CodePush.bundleURL() ``` Your `bundleUrl` method should look like this: ```bash override func bundleURL() -> URL? { #if DEBUG RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") #else CodePush.bundleURL() #endif } ``` ### CodePush Android Setup (React Native) > > Plugin installation and configuration for React Native 0.76 version and above > **1. Ensure Native Linking** In `android/app/build.gradle`, add `codepush.gradle` as an additional build task definition to the end of the file: ```bash apply from: "../../node_modules/@code-push-next/react-native-code-push/android/codepush.gradle" ``` **2. Update MainApplication** Open the `MainApplication` file and update it as follows: ```shell ... // 1. Import the plugin class. import com.microsoft.codepush.react.CodePush class MainApplication : Application(), ReactApplication { override val reactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { override fun getPackages(): List = PackageList(this).packages.apply { // Packages that cannot be autolinked yet can be added manually here, for example: // add(MyReactNativePackage()) } // 2. Override the getJSBundleFile method in order to let // the CodePush runtime determine where to get the JS // bundle location from on each app start override fun getJSBundleFile(): String { return CodePush.getJSBundleFile() } }; } ``` For React Native **0.82** and above, make the following changes to `MainApplication.kt`: ```shell ... // 1. Import the plugin class. import com.microsoft.codepush.react.CodePush class MainApplication : Application(), ReactApplication { override val reactHost: ReactHost by lazy { getDefaultReactHost( context = applicationContext, packageList = PackageList(this).packages.apply { // Packages that cannot be autolinked yet can be added manually here, for example: // add(MyReactNativePackage()) }, // 2. RN 0.82+ uses ReactHost config instead of overriding getJSBundleFile(). // Set jsBundleFilePath to CodePush so CodePush resolves the JS bundle path // at startup (OTA update if available, fallback to bundled JS otherwise). jsBundleFilePath = CodePush.getJSBundleFile(), ) } } ``` ### Run a test OTA release To verify that CodePush is working end-to-end, you can publish a quick test release: ```bash code-push release-react ``` This single command: * Bundles your React Native JavaScript code * Uploads it to the CodePush server * Releases it to the default deployment (usually Staging, if another deployment channel is needed, you can manage it by adding `-d ` to the command above) For the full release workflow, see [Releasing updates](/rn-codepush/releasing-updates/). ## Next steps After completing setup, use the following sections to continue: - [Releasing updates](/rn-codepush/releasing-updates/) - publish your first OTA release - [CLI quick reference](/rn-codepush/cli-quick-reference/) - copy-paste commands for auth, releases, and rollouts - [CI integration](/rn-codepush/ci-integration/) - automate releases in CI/CD - [Production control](/rn-codepush/production-control/) - rollouts, rollbacks, and version targeting - [Security and access](/rn-codepush/security-and-access/) - authentication and signing - [Debugging and common issues](/rn-codepush/debugging-and-common-issues/) - troubleshooting - [Advanced: sync options](/rn-codepush/advanced-sync-options/) - customize `sync()`, dialogs, progress, and restart behavior ================================================================================ source: https://docs.codemagic.io/yaml-code-signing/signing-macos/ title: Signing macOS apps description: How to set up macOS code signing in codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Signing macOS apps > How to set up macOS code signing in codemagic.yaml All macOS applications have to be digitally signed before they can be installed on devices or made available to the public via the Mac App Store or outside of the Mac App Store. > > This guide only applies to workflows configured with the **codemagic.yaml**. If your workflow is configured with **Flutter workflow editor** please go to [Signing macOS apps using the Flutter workflow editor](../code-signing/macos-code-signing). > ## Automatic vs Manual code signing > > Signing macOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. > Signing macOS apps requires a `Signing certificate` (App Store **development** or **distribution** certificate in `.p12` format) and a `Provisioning profile`. In **Manual code signing** you save these files as Codemagic `Environment variables` and manually reference them in the appropriate build steps. In **Automatic code signing**, Codemagic takes care of Certificate and Provisioning profile management for you. Based on the `certificate private key` that you provide, Codemagic will automatically fetch the correct certificate from the App Store or create a new one if necessary. ## Certificate types There are several certificate types you can choose to sign your macOS app, depending on the distribution method you plan to use. - `MAC_APP_DEVELOPMENT` certificate allows you to build your app for internal testing and debugging. - `MAC_APP_DISTRIBUTION` certificate is used to sign a Mac app before submitting it to the Mac App Store - `MAC_INSTALLER_DISTRIBUTION` is used to sign and submit a Mac Installer Package to the Mac App Store - `DEVELOPER_ID_APPLICATION` is used to sign a Mac app before distributing it outside the Mac App Store - `DEVELOPER_ID_INSTALLER` is used to sign a Mac Installer Package before distributing it outside the Mac App Store For example, in order to publish to Mac App Store, the application must be signed with a `Mac App Distribution` certificate using a `Mac App Store` provisioning profile. If you want to create a `.pkg` Installer package, you must use a `Mac Installer Distribution` certificate. ## Obtaining the certificate private key To enable Codemagic to automatically fetch or create the correct signing certificate on your behalf, you need to provide the corresponding `certificate private key`. You then have to save that key as a Codemagic environment variable. ### Option: Create a new key You can create a new 2048 bit RSA key by running the command below in your terminal: ```Shell ssh-keygen -t rsa -b 2048 -m PEM -f ~/Desktop/mac_distribution_private_key -q -N "" ``` This new private key will be used to create a new Mac App Distribution certificate in your Apple Developer Program account if there isn't one that already matches this private key. ### Option: Use an existing key"%}} 1. On the Mac which created the `Mac App Distribution` certificate, open the **Keychain Access**, located in the **Applications and Utilities** folder. 2. Select the appropriate certificate entry. 3. Right-click on it to select "Export." 4. In the export prompt window that appears, make sure the file format is set to **Personal Information Exchange (.p12)**. 5. Give the file a name such as "MAC_DISTRIBUTION", choose a location and click **Save**. 6. On the next prompt, leave the password empty and click **OK**. 7. Use the following `openssl` command to export the private key: ```Shell openssl pkcs12 -in MAC_DISTRIBUTION.p12 -nodes -nocerts | openssl rsa -out mac_distribution_private_key ``` 8. When prompted for the import password, just press enter. The private key will be written to a file called **mac_distribution_private_key** in the directory where you ran the command. ## Automatic code signing When automatic code signing is used, then most up-to-date signing files are obtained directly from Apple during the build time. This requires that Codemagic has access to your Apple Developer portal account, which is achieved by using App Store Connect API key. ### Creating the App Store Connect API key It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > ### Configuring environment variables Provisioning profiles and code signing certificates are obtained from Apple Developer portal with the command [`app-store-connect fetch-signing-files`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#fetch-signing-files). App Store Connect API key information can be passed to it via environment variables [`APP_STORE_CONNECT_KEY_IDENTIFIER`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--key-idkey_identifier), [`APP_STORE_CONNECT_ISSUER_ID`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--issuer-idissuer_id), [`APP_STORE_CONNECT_PRIVATE_KEY`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--private-keyprivate_key). %!s() ### Option: Use App Store Connect integrationThe Apple Developer Portal integration can be enabled in the **Team integrations** section in your team settings (if you're a team admin). This allows you to conveniently use the same access credentials for automatic code signing and publishing across different apps and workflows. 1. In the list of available integrations, click the **Connect** button for **Developer Portal**. 2. In the **App Store Connect API key name**, provide a name for the key you are going to set up the integration with. This is for identifying the key in Codemagic. 3. Enter the **Issuer ID** related to your Apple Developer account. You can find it above the table of active keys on the Integrations tab of the [Users and Access](https://appstoreconnect.apple.com/access/integrations/api) page. 4. Enter the **Key ID** of the key to be used for code signing. 5. In the **API key** field, upload the private API key downloaded from App Store Connect. 6. Click **Save** to finish the setup. If you work with multiple Apple Developer teams, you can add additional keys by clicking **Add another key** right after adding the first key and repeating the steps described above. You can delete existing keys or add new ones when you click **Manage keys** next to the Developer Portal integration in personal account or team settings. Integration will take care of the App Store Connect API authentication part, but additionally the certificate private key has to be exported too. For this additional environment variable [`CERTIFICATE_PRIVATE_KEY`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--certificate-keyprivate_key) has to be defined. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter `CERTIFICATE_PRIVATE_KEY` as the **_Variable name_**. 3. Open the file `ios_distribution_private_key` with a text editor and copy the **entire contents** of the file, including the `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` tags. Alternatively, you can run the following command on the file: ```Shell cat ios_distribution_private_key | pbcopy ``` 4. Paste into the **_Variable value_** field. 5. Enter a variable group name, e.g. **_code-signing_**. Click the button to create the group. 6. Make sure the **Secret** option is selected so that the variable can be protected by encryption. 7. Click the **Add** button to add the variable. In your workflow you can now simply use the following to ensure that all variables are readily available during build: ```yaml workflows: ios-workflow: environment: groups: - code-signing integrations: app_store_connect: ``` This will expose necessary environment variables during the build. %!s() ### Option: Define environment variables by yourself %!s() ================================================================================ source: https://docs.codemagic.io/yaml-notification/slack/ title: Slack description: How to publish build status updates to Slack with links to artifacts in codemagic.yaml last_modified: 2026-03-17 ================================================================================ # Slack > How to publish build status updates to Slack with links to artifacts in codemagic.yaml Integrate Slack publishing into your Codemagic build pipeline to get notified when a build starts and receive build artifacts or logs when the build finishes. ### Connecting your Slack workspace To set up publishing to Slack, you first need to connect your Slack workspace in your account or team settings. Expand the **Integrations** or **Team integrations** section respectively and click **Connect** next to Slack. ![List of integrations](../uploads/slack_connect.png) Click **Connect** next to the Slack integration. You will then be redirected to an authorization page. Review the requested permissions and click **Allow** to give Codemagic Slack app access to your Slack workspace and allow it to post build status updates and build artifacts (see also our [privacy policy](https://codemagic.io/privacy-policy/)). ![Authorization page](../uploads/slack_allow.png) After you have successfully authorized Codemagic and connected your workspace, you will be redirected back to Codemagic. You can disconnect your Slack workspace anytime by clicking **Disconnect**. ![Slack integration is enabled](../uploads/slack_connected.png) ### Configuring Slack publishing The Slack channel for publishing is configured separately for each workflow in the `publishing` section of `codemagic.yaml` (refer [here](../publishing/email-and-slack-notifications/#slack) if you're configuring app settings in the Flutter workflow editor). > > **Note:** In order to publish to **private channels**, you need to invite the Codemagic app to the channels; otherwise, the app does not have access to private channels. To invite Codemagic app to private channels, write `@codemagic` in the channel. If the private channel access is restricted by Slack admin rights, it will have to be changed manually, otherwise publishing to that channel will not be possible. > If the build finishes successfully, release notes (if passed) and the generated artifacts will be published to the specified channel. The artifact download links in Slack notifications are, by default, valid for 24 hours. You can configure the lifetime of publicly accessible artifact download links by selecting your personal account or team and navigating to **Settings > Artifact download links**. If the build fails, a link to the build logs is published. When you set `notify_on_build_start` to `true`, the channel will be notified when a build starts. If you don't want to receive a Slack notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml publishing: slack: channel: '#channel-name' notify_on_build_start: true # To receive a notification when a build starts notify: success: false # To not receive a notification when a build succeeds failure: false # To not receive a notification when a build fails ``` When you set up Slack publishing, Codemagic publishes the following artifacts: - `app` - `ipa` - `apk` - the archive with Flutter web build directory - Linux application bundle files, Windows MSIX packages ================================================================================ source: https://docs.codemagic.io/flutter-testing/static-code-analysis/ title: Static code analysis description: How to run Static Code Analysis in Flutter workflow editor configured builds last_modified: 2023-07-25 ================================================================================ # Static code analysis > How to run Static Code Analysis in Flutter workflow editor configured builds ### Flutter Analyze Test your code with `flutter analyze` to find possible mistakes. You can read more about this feature in [Dart documentation](https://dart.dev/guides/language/analysis-options). By default, Flutter Analyze is disabled and has to be enabled in **App settings > Tests > Static code analysis** by checking the **Enable Flutter analyzer** option. When enabled, `flutter analyze` will be run with each build. You can see the results and the logs of the analysis under the **Testing** step in build overview. Codemagic specifies the `analyze` command in the **Flutter analyze arguments** field. You can pass additional arguments to customize static code analysis. For example, adding `--write=analyzer-output.txt` prints the results of static code analysis into a text file. If this is applied, the generated text file containing the test results can be retrieved as a downloadable artifact by adding this **Pre-publish** script: ```bash cp -r $CM_BUILD_DIR/analyzer-output.txt $CM_EXPORT_DIR/analyzer-output.txt ``` ### Stop build if tests or analysis fail If you check **Stop build if tests or analysis fail**, the build will stop after finishing all the enabled tests or analysis runs when any of them fail. Such builds will have the status "failed". ================================================================================ source: https://docs.codemagic.io/yaml-testing/firebase-test-lab/ title: Testing on Firebase Test Lab description: How to run tests on Firebase Test Lab last_modified: 2025-05-27 ================================================================================ # Testing on Firebase Test Lab > How to run tests on Firebase Test Lab Firebase Test Lab provides a cloud-based infrastructure for testing Android and iOS apps on various devices and configurations. You can test your apps on Firebase Test Lab as part of the Codemagic build workflow provided you have set up a Firebase project. To set up testing on Firebase Test Lab in Codemagic, follow these steps. ## Firebase Test Lab prerequisites You will need to set up the following in the [Firebase console](https://firebase.google.com/). 1. Create a Firebase project. 2. Create a service account with Editor permissions and download the **JSON key file** so you can authenticate with Firebase Test Lab during the build. See how to create a service account [here](https://docs.codemagic.io/yaml-publishing/google-play/#configure-google-play-api-access). 3. Enable the [Cloud Tools Results API](https://console.cloud.google.com/apis/library/toolresults.googleapis.com?pli=1&project=woven-voyage-217607&folder=&organizationId=). Please follow the guides in the [Firebase Test Lab documentation](https://firebase.google.com/docs/test-lab/?gclid=EAIaIQobChMIs5qVwqW25QIV8iCtBh3DrwyUEAAYASAAEgLFU_D_BwE) to set up a project. ## Configure testing in codemagic.yaml To access the Firebase project from Codemagic, add the service account JSON key file and the Firebase project name as [Environment variables](../yaml-basic-configuration/configuring-environment-variables). 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `GCLOUD_KEY_FILE`. 3. Copy and paste the content of the JSON key file as **_Variable value_**. 4. Enter the variable group name, e.g. **_firebase_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to add the `FIREBASE_PROJECT` variable to store your **Firebase project ID**. In your `codemagic.yaml` file, import the above environment variable group and add the corresponding testing script. > > **Note:** Codemagic machines come with gcloud CLI tools preinstalled. Refer to [CLI documentation for Android](https://firebase.google.com/docs/test-lab/android/command-line) and [CLI documentation for iOS](https://firebase.google.com/docs/test-lab/ios/command-line) for more details. > ### Option: Android ```yaml workflows: android-workflow: environment: groups: - firebase_credentials scripts: # ... - name: Create debug and test APK script: | set -ex cd android ./gradlew app:assembleAndroidTest ./gradlew app:assembleDebug -Ptarget="$CM_BUILD_DIR/integration_test/app_test.dart" - name: Run Firebase Test Lab tests script: | set -ex echo $GCLOUD_KEY_FILE > ./gcloud_key_file.json gcloud auth activate-service-account --key-file=gcloud_key_file.json gcloud --quiet config set project $FIREBASE_PROJECT gcloud firebase test android run \ --type instrumentation \ --app your-app.apk \ --test your-app-test.apk \ --device model=TestDevice1,version=AndroidVersion1 \ --device model=TestDevice2,version=AndroidVersion2 \ --environment-variables coverage=true,coverageFile="/sdcard/coverage.ec" \ --directories-to-pull /sdcard --timeout 3m ``` ### Option: iOS Package your application and prepare it for upload to Firebase Test Lab as described [here](https://firebase.google.com/docs/test-lab/ios/run-xctest#package-app). Use the generated `MyTests.zip` to start testing: ```yaml workflows: ios-workflow: environment: groups: - firebase_credentials scripts: # ... - name: Run Firebase Test Lab tests script: | set -ex echo $GCLOUD_KEY_FILE > ./gcloud_key_file.json gcloud auth activate-service-account --key-file=gcloud_key_file.json gcloud --quiet config set project $FIREBASE_PROJECT gcloud firebase test ios run --test PATH/TO/MyTests.zip \ --device model=MODEL_ID_1,version=VERSION_ID_1,locale=LOCALE_1,orientation=ORIENTATION_1 \ --device model=MODEL_ID_2,version=VERSION_ID_2,locale=LOCALE_2,orientation=ORIENTATION_2 --timeout 3m ``` In `codemagic.yaml` file the script called `Create debug and test APK` will create two .apk files. One is the debug version of your app, and the other is the .apk that is used to run the integration tests. The script called `Run Firebase Test Lab tests` will use the gcloud CLI tools to authenticate with Firebase and then run the test passing in the debug apk, the test .apk, and specifying a build timeout. Check out [this sample Flutter project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter/flutter-integration-tests-demo-project) and the relevant [codemagic.yaml](https://github.com/codemagic-ci-cd/codemagic-sample-projects/blob/main/flutter/flutter-integration-tests-demo-project/codemagic.yaml) file for setting up integration tests in Firebase. ================================================================================ source: https://docs.codemagic.io/yaml-testing/emulator-wtf/ title: Testing with emulator.wtf description: How to run tests using emulators from emulator.wtf last_modified: 2026-06-26 ================================================================================ # Testing with emulator.wtf > How to run tests using emulators from emulator.wtf ## Configuring emulator.wtf API token In order to use [emulator.wtf](https://emulator.wtf) service for app testing, you need to obtain an emulator.wtf API token and save it as an environment variable in Codemagic. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `EW_API_TOKEN`. 3. Copy and paste the content of the token as **_Variable value_**. 4. Enter the variable group name, e.g. **_emulatorwtf_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. You can then import the token in your workflow: ```yaml workflows: android-build: environment: groups: - emulatorwtf # adds EW_API_TOKEN to the workflow ``` ## Running tests Add the following snippet under your workflow _after_ the Gradle build step. Update the `--app` and `--test` paths according to your build if necessary. ```yaml scripts: - name: Test script: | ew-cli \ --app app/build/outputs/apk/debug/app-debug.apk \ --test app/build/outputs/apk/androidTest/app-debug-androidTest.apk \ --outputs-dir results test_report: results/**/*.xml ``` ## Capturing logcat Add the following to your workflow to capture logcat output from the emulator during the test run: ```yaml artifacts: - results/**/logcat.txt ``` ## Running tests with coverage Add `--with-coverage` to the `ew-cli` script to capture coverage during the test run: ```yaml scripts: - name: Test script: | ew-cli \ --app app/build/outputs/apk/debug/app-debug.apk \ --test app/build/outputs/apk/androidTest/app-debug-androidTest.apk \ --with-coverage \ --outputs-dir results test_report: results/**/*.xml ``` ## Running tests in parallel Add `--num-shards ` to run tests in parallel shards, here's an example to shard tests to 4: ```yaml scripts: - name: Test script: | ew-cli \ --app app/build/outputs/apk/debug/app-debug.apk \ --test app/build/outputs/apk/androidTest/app-debug-androidTest.apk \ --num-shards 4 \ --outputs-dir results test_report: results/**/*.xml ``` ## Running tests with orchestrator Add `--use-orchestrator` to run tests with Android Test Orchestrator (more info [here](https://docs.emulator.wtf/integrations/cli/#run-tests-with-orchestrator-while-clearing-package-data)): ```yaml scripts: - name: Test script: | ew-cli \ --app app/build/outputs/apk/debug/app-debug.apk \ --test app/build/outputs/apk/androidTest/app-debug-androidTest.apk \ --use-orchestrator \ --outputs-dir results test_report: results/**/*.xml ``` ## Further information There are more options available like pulling directories from the emulator after tests have finished, running on various device models, etc. Check the [emulator.wtf docs](https://emulator.wtf) for more `ew-cli` options to customize your test run. ================================================================================ source: https://docs.codemagic.io/getting-started/about-codemagic/ title: Welcome to Codemagic description: Introduction to Codemagic CI/CD last_modified: 2026-06-26 ================================================================================ # Welcome to Codemagic > Introduction to Codemagic CI/CD Codemagic is a cloud-based Continuous Integration/Continuous Delivery (CI/CD) product specifically designed for mobile developers building apps with Flutter, React Native, native iOS, native Android, Unity, Kotlin Multiplatform Mobile, .NET MAUI and Ionic. Codemagic's API and versatile workflow configurations also provide a great platform for mobile development teams who are White labeling their apps. ## Automatic build and deployment Codemagic automates the process of app building, testing, and deployment to app stores such as the Apple App Store, Google Play, Microsoft Store, and Huawei App Gallery. New builds can be triggered when code is pushed to your repository, tags are added, or pull requests are merged. You can configure multiple workflows to make the app available to your dev team, distribute the latest build to your test team, or publish your app to production. ## Repository Access To build your apps, Codemagic needs read-only access to your cloud-based GitHub, GitLab, or Bitbucket repository. It’s also possible to connect to self-hosted repositories using an SSH key pair and configuring the appropriate rules in your firewall. ## Security At the beginning of each build, your source code is cloned to a new virtual machine instance where the build is run. It is destroyed immediately after the build has completed, leaving no trace of your source code or secret variables. To access API keys, certificates, tokens, and other sensitive values during your build, an unlimited number of encrypted secrets can easily be added to the Codemagic dashboard. Only the build history log and build artifacts will be available in the Codemagic dashboard after the build finishes. Codemagic employees do not have access to your source code or any encrypted secrets you have added to the dashboard. Please see our [Security statement](https://codemagic.io/security-statement/) for more information. ## Integrations Application workflows can also be configured to run unit and integration tests as well as integrate with services that test your apps on real devices, check the quality of your code and scan for vulnerabilities, or update your development progress in your project management system. Your team can be notified by email or Slack notifications when new builds are available. ## Configuration as code Workflows are configured in code using a YAML configuration file which can be checked into version control to track changes made by your team. If you need to add a new workflow, simply copy and paste an existing workflow and modify it as required. Configurations can be easily extended with Bash or Python scripts in addition to Codemagic’s open-source CLI tools that make tasks such as build versioning, publishing, and code signing much simpler. You can find out more about working with the `codemagic.yaml` configuration file [here](https://docs.codemagic.io/yaml-basic-configuration/yaml-getting-started/). Flutter developers can also choose to set up their workflows using a graphical user interface called the “Workflow Editor”. ## Infrastructure Codemagic’s infrastructure is centered around the powerful Apple silicon M2 (arm64) machines allowing for faster builds than the previous generation of macOS machines. Linux and Windows machines are also available for all customers. The following documentation pages show the hardware specifications for each instance type: - [Linux hardware specifications](https://docs.codemagic.io/specs/versions-linux/) - [macOS hardware specifications](https://docs.codemagic.io/specs/versions-macos/) - [Windows hardware specifications](https://docs.codemagic.io/specs/versions-windows/) Our data centers are located in the US, but it is possible to set up dedicated macOS hosts in the EU on request. ## Pre-installed software All the virtual machines come preloaded with the most common software you would need for building mobile apps such as Xcode, Android Studio, and a variety of CLI tools and frameworks. Codemagic’s engineers continuously monitor system availability and take care of updating software like Xcode and checking everything works when building with new versions so you don’t have to worry about running and maintaining your own systems. Please refer to the following documentation to see the software pre-installed on each instance type: - [Linux pre-installed software](https://docs.codemagic.io/specs/versions-linux/#pre-installed-tools) - [macOS pre-installed software](https://docs.codemagic.io/specs/versions-macos/#:~:text=Free%20Space%3A%2048GB)-,Pre%2Dinstalled%20tools,-Android%20tools%20/usr) - [Windows pre-installed software](https://docs.codemagic.io/specs/versions-windows/#pre-installed-tools) ## Scalability If you need to run parallel builds you can add additional concurrencies as your needs grow. The free tier and pay-as-you-go plan includes one concurrency to begin with but can be increased to a total of three. The Annual plan and Enterprise plans start with three concurrencies and an unlimited number of concurrencies can be added at any time during your subscription period. ## Pricing Individuals and hobbyists can get started with Codemagic using its free tier which offers 500 free build minutes per month and lets you build on Apple silicon M2 machines. This quota is reset at the beginning of each month. For development teams with limited budgets, the Codemagic pay-as-you-go plan offers an affordable way to get started with CI/CD. You only pay for the minutes you consume and the additional concurrencies you add. An annual subscription with access to Mac mini M2 VMs comes with 2 months of free usage. Enterprise plans are also available for customers who require additional services such as SSO Login (OpenID, OAuth2 or SAML 2.0), registration with procurement systems, invoicing and payment by bank transfer, signed NDA, DPA, and other account management services such as collaborating with infosec teams. Full pricing details can be found on our pricing page [here](https://docs.codemagic.io/billing/pricing/). ## Blog The [Codemagic blog](https://blog.codemagic.io/) is a great resource that covers a multitude of technical subjects related to CI/CD ranging from code signing and publishing to general application development. ================================================================================ source: https://docs.codemagic.io/flutter-configuration/creating-workflows/ title: Workflows description: How to configure workflows in the Flutter workflow editor last_modified: 2021-08-17 ================================================================================ # Workflows > How to configure workflows in the Flutter workflow editor Have full control over your CI/CD pipeline with workflows. A workflow is a set of settings that determines how your app is to be built, tested and published. You can create several workflows for building different configurations of your app. For example, you can use workflows to build different branches of the project, separate your debug and release builds, run builds for different projects or flavors in the repository, test your app with different software versions, and so on. ## Creating workflows New workflows can be created by duplicating existing ones. Navigate to **App settings > Right sidebar > Workflow settings** and click **Duplicate workflow**. This creates a new workflow with the exact same settings as you had configured for the original workflow. All your environment variables and scripts, build settings and signing files will be duplicated into the new workflow. You can then click on the name of the workflow to edit it and configure the workflow settings as you like. Now that you have more than one workflow, you can also delete workflows. To switch between workflows, click on the workflow name below the app name in app settings. > > Note that while your workflows started out as duplicates, they become separate entities once created. Any changes made to one workflow won't affect any of the others. > ================================================================================ source: https://docs.codemagic.io/flutter-code-signing/android-code-signing/ title: Android code signing description: How to set up Android code signing in the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # Android code signing > How to set up Android code signing in the Flutter workflow editor Code signing is required for distributing your Android app to the Google Play store. It enables you to identify who developed the app and ensure that all updates to the app come from you. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured with **codemagic.yaml** please go to [Signing Android apps using codemagic.yaml](../code-signing-yaml/signing-android). > ## Requirements To receive a signed release .apk of your app on Codemagic, you will have to: 1. [Prepare your Flutter project for code signing](#preparing-your-flutter-project-for-code-signing) 2. [Set up Android code signing in the Flutter workflow editor](#setting-up-android-code-signing-on-codemagic) For code signing, you need to upload the **keystore** containing your **certificate** and **key**. See the instructions for generating the keystore [here](#generating-a-keystore). As a keystore can hold multiple keys, each key in it must have an **alias**. Both the keystore file and the key alias are protected by **passwords**. > > **Note:** Please note that every app must be signed using the same key throughout its lifespan. > > If you're building Android App Bundles, you additionally need to [enroll your app into app signing by Google Play](https://support.google.com/googleplay/android-developer/answer/7384423). > > ## Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```bash keytool -genkey -v -keystore keystore_name.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias alias_name ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **keystore_name.jks** in the directory you're in. The key is valid for 10,000 days. You need to upload the keystore and provide the keystore password, key alias and key password to have Codemagic sign your Android app on your behalf. ## Preparing your Flutter project for code signing There are several approaches you can use to prepare your Flutter project for code signing. We have described two of these in this section. Note that whichever approach you use, you still need to [set up Android code signing](#setting-up-android-code-signing-on-codemagic) in the Flutter workflow editor. ### Option 1. Configure signing following Flutter's documentation You can follow the instructions in [Flutter's documentation](https://flutter.dev/docs/deployment/android#signing-the-app) to configure code signing in Gradle. It's vital that you use the variable names suggested in Flutter documentation as Codemagic will reference them during the build. However, make sure to not commit your `key.properties` file to the repository. Codemagic will generate and populate the `key.properties` file during the build based on the input you provide in the workflow editor. ### Option 2. Configure signing using environment variables Alternatively, you can use [environment variables](../building/environment-variables/ 'Environment variables') to prepare your app for code signing. Set your signing configuration in app level `build.gradle` or `build.gradle.kts` as follows: ### Option: build.gradle ```Groovy ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` ### Option: build.gradle.kts ```groovy import java.io.File import java.util.* val keystoreProperties = Properties().apply { var file = File("key.properties") if (file.exists()) load(file.reader()) } plugins { ... } android { ... val appVersionCode = (System.getenv()["NEW_BUILD_NUMBER"] ?: "1")?.toInt() defaultConfig { ... versionCode = appVersionCode ... } signingConfigs { create("release") { if (System.getenv()["CI"].toBoolean()) { // 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 { storeFile = file(keystoreProperties.getProperty("storeFile")) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } } } buildTypes { getByName("release") { isMinifyEnabled = false signingConfig = signingConfigs.getByName("release") } } } dependencies { ... } ``` > > **Warning:** Keep the `key.properties` file private; don’t check it into public source control. > ## Setting up Android code signing on Codemagic You are required to upload your keystore file and provide details about your key in order to receive signed builds on Codemagic. 1. Navigate to the **Distribution** section in app settings. 2. Click **Android code signing**. 3. Upload your release keystore file. 4. Enter the **keystore password**, **key alias** and **key password**. 5. Select **Enable Android code signing** at the top of the section to enable code signing. {{< youtube lYp9MAfouXE >}} ================================================================================ source: https://docs.codemagic.io/rest-api/artifacts/ title: Artifacts API description: Authenticated and public access to build artifacts last_modified: 2023-03-14 ================================================================================ # Artifacts API > Authenticated and public access to build artifacts ## Step 1: Get authenticated download URL `GET /artifacts/:secureFilename` This URL can be obtained using the [Builds API](/rest-api/builds) or copied directly from the Codemagic UI. A typical URL looks like this: `https://api.codemagic.io/artifacts/ef45fb91-4c89-4395-8f7d-9368b97490de/2dd0b3d6-ae58-4894-b470-8bc2b24e259a/mayapp.ipa` ## Step 2: Create a public download URL using the URL obtained in step 1 > > **Important!** Please take extra care when sharing public download URLs so as to not expose them. Anyone with access to a public download URL will be able to download your build artifact. > `POST /artifacts/:secureFilename/public-url` #### Parameters | **Name** | **Type** | **Description** | | ----------- | --------- | ---------------------------------------- | | `expiresAt` | `integer` | URL expiration UNIX timestamp in seconds. | The response contains the public artifact download URL under the `url` key. #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ -d '{"expiresAt": 1675419345}' \ -X POST https://api.codemagic.io/artifacts/ef45fb91-4c89-4395-8f7d-9368b97490de/2dd0b3d6-ae58-4894-b470-8bc2b24e259a/mayapp.ipa/public-url ``` #### Response ```json { "url": "https://api.codemagic.io/artifacts/.eJwVwcmSQ0AAANB_yV2VpTGOhC5b0GJLX5Ql1WFoa9Li66fmvQvR_xm9qPqQHYO_lvuDnFxjObE6lmuYcQTxAFwZP2ph5ryPBzSnvDfSuiCsHKNm_GLDj9tWeg9phO7RzqitqMdNEoKRwAkNWxcru_HKZ3nOAMMzoY5S8e0mFSY9Kad7VKBfzQy8Z2SXHHAdIdWT71K6ORUPFP76t2XQ7vB51VnRVARBY_NeFgv3I127U_yoddsTBM7VxURG25lXmLqT48tDBekA8L55ccObEEiBa0lyh2weJbhbPqBiipskoKZ9inCh_lz-AAvOWp0.TtMPNvwHXeoH3yrFr6JvuT8NMRQ", "expiresAt": "2023-02-03T10:15:45+00:00" } ``` ================================================================================ source: https://docs.codemagic.io/integrations/browserstack-integration/ title: BrowserStack integration description: How to integrate your workflows with BrowserStack using codemagic.yaml last_modified: 2025-06-30 ================================================================================ # BrowserStack integration > How to integrate your workflows with BrowserStack using codemagic.yaml **BrowserStack** is a cloud-based mobile testing platform that provides the ability to test your applications on real mobile devices. BrowserStack can be used as a part of your Codemagic CI/CD pipeline to test your applications. BrowserStack offers two testing environments: **App Live** and **App Automate**. You can submit your applications to both testing environments via Codemagic using `cURL` requests. You can find sample projects both for the [App Live](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/browserstack_app_live_demo_project) and the [App Automate](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/browserstack_app_automate_demo_project) options of BrowserStack in our Sample projects repository. ## Configuring BrowserStack in Codemagic Signing up with BrowserStack is required in order to be able to get the **username** and **access token**. You can sign up for free [here](https://www.browserstack.com/). 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `BROWSERSTACK_USERNAME`. 3. Enter the required value as **_Variable value_**. 4. Enter the variable group name, e.g. **_browserstack_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the process to add the token as `BROWSERSTACK_ACCESS_TOKEN` 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - browserstack_credentials ``` ## App Live To use **App Live** and test your **.ipa** and **.apk** artifacts directly on real devices rather than simulators, add the following script to your `codemagic.yaml file: ```yaml scripts: - name: Submitting app to Browserstack: script: | curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_TOKEN" -X POST "https://api-cloud.browserstack.com/app-live/upload" -F "file=@build/ios/ipa/your_app_release.ipa" ``` > > **Note:** Make sure that you add this cURL request after building the **.ipa** and **.apk**, otherwise you cannot attach their paths to the cURL request. > ## App Automate In order to use BrowserStack **App Automate** service through Codemagic, you need to add scripts to your `codemagic.yaml` file to perform these three steps using REST API endpoints: 1. Upload your app 2. Upload test suite 3. Start testing In order to upload test suites for android apps, you need to run `./gradlew assembleAndroidTest` in your build script. Make sure that your **app/build.gradle** file includes **Instrumentation Runner**: ```Groovy defaultConfig { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } ``` If you are building your app in **release mode**, then you also need to build your test suite .apk in release mode by adding the following in app/build.gradle: ```Groovy testBuildType "release" ``` Your `codemagic.yaml` file will look similar to this: ```yaml scripts: - name: Build Android Test release script: | cd android # change folder if necessary ./gradlew assembleAndroidTest - name: BrowserStack upload script: | APP_URL=$(curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_TOKEN" \ -X POST "https://api-cloud.browserstack.com/app-automate/upload" \ -F "file=@android/app/build/outputs/apk/release/app-release.apk" \ | jq -r '.app_url') TEST_URL=$(curl -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_TOKEN" \ -X POST "https://api-cloud.browserstack.com/app-automate/espresso/test-suite" \ -F "file=@android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk" \ | jq -r '.test_url') curl -X POST "https://api-cloud.browserstack.com/app-automate/espresso/build" \ -d '{"devices": ["Google Pixel 3-9.0"], "app": "'"$APP_URL"'", "deviceLogs" : true, "testSuite": "'"$TEST_URL"'"}' \ -H "Content-Type: application/json" -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_TOKEN" ``` ================================================================================ source: https://docs.codemagic.io/flutter-distributing/build-dashboards/ title: Build dashboards description: Use Build dashboards for sharing builds last_modified: 2026-04-01 ================================================================================ # Build dashboards > Use Build dashboards for sharing builds Build dashboards make it possible for teams to share the list of team's builds, release notes (if passed) and build artifacts with people outside Codemagic using a public link (build logs will not be exposed). This is a convenient option for distributing builds to testers or sharing build artifacts with stakeholders. The artifact download links in build dashboards are valid for 24 hours. Download links are recreated on each dashboard refresh. > > **Note:** The build dashboards feature is available for teams only. It is not possible to create build dashboards for apps on personal accounts. > ## Enabling build dashboards To use build dashboards, team admins will have to enable the feature in team settings. In team settings, expand the **Build dashboards** section and click **Enable sharing**. This will allow any team member to create dashboards and generate public links to share them. Build dashboards can be disabled anytime by clicking **Disable sharing**. ## Creating and sharing a build dashboard 1. Open the **Builds** page via the left navigation bar. 2. Click the **Share dashboard** button at the top right of the page and use the **application**, **workflow**, **build status**, **labels**, **branch** and **tag** filters to configure a build dashboard. 3. Then click **Create dashboard** at the bottom of the right configuration sidebar to generate a public link. A generated link will appear, and you can copy the link to the clipboard. The generated link will be also saved to the **Build dashboards** section in team settings. > > **Note:** **Share dashboard** will be available only when the currently selected team has build dashboards enabled. > > > **Note:** Please note that anyone with the public link can access the build dashboard and download build artifacts. > ## Managing links All generated links to build dashboards are listed in the **Build dashboards** section in team settings. Links can be revoked by deleting them or when a team admin disables sharing by clicking **Disable sharing**. When sharing is re-enabled, the available links become active again. ================================================================================ source: https://docs.codemagic.io/yaml-distributing/tester-groups/ title: Build distribution to tester groups description: Distribute app builds to groups of testers last_modified: 2026-06-26 ================================================================================ # Build distribution to tester groups > Distribute app builds to groups of testers Tester groups are a convenient way to manage testers for your app in the Codemagic UI and distribute app builds to a group of email addresses outside of Codemagic. Testers who have confirmed their email addresses will receive an email with the app artifacts after every successful build of the workflow. > > Note that tester groups are only available for **teams** and apps using the `codemagic.yaml` configuration. > ## How to distribute builds to tester groups Two steps are required to automate build distribution to tester groups. ### Step 1. Create a tester group On the **Tester groups** tab in your app settings, create a new tester group and invite testers by entering their email addresses. You can invite many testers at once, provided that email addresses are separated by a comma or a new line. Note the name of the tester group as you will have to use it in the `codemagic.yaml` file. ### Step 2. Update the codemagic.yaml file In order to send testers publishing emails with app artifacts, the names of the tester groups must be specified in the `publishing` section of `codemagic.yaml` as follows: ```yaml publishing: tester_groups: - tester_group_1 - tester_group_2 ``` This allows you to configure which workflows publish to tester groups and have different workflows publish to different groups. Tester groups receive an email only when the workflow builds successfully. If the build fails, tester groups are not notified. ## Testers management Each invited tester will receive an email to confirm their consent to receive build emails with app artifacts. Only confirmed testers will receive emails with app artifacts. In the UI, testers will have one of the following statuses: * **"Active"** -- tester is eligible to receive emails on successful app builds. * **"Pending"** -- tester has not confirmed the invitation and will not receive any further emails until they confirm. * **"Rejected"** -- delivery to that email has failed (e.g. email bounced) and the tester will not receive any further emails. You can add new testers and remove existing ones anytime. ## Limit on the number of testers By default, the number of testers is limited to 20 across all applications in the team. Please get in touch with us should you require a higher limit. ================================================================================ source: https://docs.codemagic.io/knowledge-codemagic/build-inputs/ title: Build inputs description: Specify optional inputs that are passed to the workflow when starting a build last_modified: 2025-05-26 ================================================================================ # Build inputs > Specify optional inputs that are passed to the workflow when starting a build

> > The Build inputs feature is only available for workflows configured using `codemagic.yaml`. > ## Overview Build inputs are customizable parameters you can define within your workflow to make it more adaptable to different scenarios. With build inputs, you can create a single workflow and run it with different configurations by providing the values for inputs when starting a build for the workflow. For example, you can use build inputs to determine whether to build the workflow for test or release purposes or which app flavor to build. This eliminates the need to create multiple similar workflows with specific hardcoded values, making the workflow more reusable and dynamic. Inputs are workflow-specific and are defined in `codemagic.yaml` under the `inputs` mapping (see the [example](#minimal-example) below). The started workflow receives specified input values in the `inputs` context, i.e. `${{ inputs.inputId }}` is replaced with the value passed to input with identifier `inputId`. ### Minimal example This example configures one input with the ID `name`. Unless given another value when starting a build, `name` defaults to `Codemagic`. ```yaml workflows: my-workflow: inputs: name: # input ID description: Who is greeted? default: Codemagic scripts: - echo "Hello, ${{ inputs.name }}" ``` ## Starting builds with Inputs manually When starting a build for a workflow that contains inputs via the Codemagic UI, you will be prompted to enter the inputs. Inputs that have predefined default values will be prefilled with those values from configuration file. All other inputs must be manually entered before the build can be started. > > Not entering anything for a string input will result in an empty string, i.e. `""`. > ## Starting builds with Inputs automatically Only workflows that do not require user input for values can be started with webhook events. If you want to use Git events or scheduled builds to automatically trigger builds for workflows with inputs, ensure that all inputs in those workflows have default values. Otherwise, the build will fail due to undefined inputs. ## YAML schema for inputs Build inputs are defined in `codemagic.yaml` as a mapping `workflows..inputs` where keys are input IDs and values are inputs that have the following fields. If `default` is omitted, value for input must be specified when starting the build. ```yaml workflows: my-workflow: inputs: number_input: description: Number input type: number default: 1 # Optional string_input: description: String input type: string default: "hello" # Optional boolean_input: description: Boolean input type: boolean default: true # Optional choice_input: description: Choice input type: choice default: option 2 # Optional. If set, must be one of defined options. options: # Required for choice input - option 1 - option 2 - option 3 ``` ### `description` **Required**. A **string** description for this build input. Description is displayed in Codemagic when manually starting a build for this workflow and user is prompted to provide values for the inputs. ### `type` **This must be one of: `boolean`, `choice`, `number` or `string`. By default, `string` is assumed.** Defines the data type of the input parameter. Input values for the `choice` type are resolved to strings and must be defined in the `options` field. Values for inputs with types `boolean` and `number` are persisted as booleans and integers or floating point numbers respectively, instead of converting them to strings as long as they are not directly used in string interpolations. ### `options` Provide a list of values as options for the `choice` input. Values are all implicitly cast to strings. Inputs with type `choice` must define additional field `options` where valid choices are listed. **Required if type is `choice` and prohibited otherwise**. ### `default` Provide a default value for the input parameter. If type is `choice`, then it must be one of the defined `options`, otherwise value type must match with the `type` definition. ## Examples Below are some example use cases for leveraging different types of build inputs in your workflows. ### Using input values in scripts You can use inputs in scripts by referencing the ID of the input. ```yaml workflows: my-workflow: inputs: name: description: Who is greeted? scripts: - echo "Hello, ${{ inputs.name }}" ``` As no `default` value is provided in the above example, then name must be specified when starting builds for this workflow, or otherwise it will be left blank. ### Using inputs to conditionally run scripts Boolean inputs can be useful to control whether some build steps are enabled or disabled, or they can be used to turn some features on or off. When given boolean values are substituted into the workflow, then their type is kept as boolean as long as they are not directly used within other values that are already strings (such as scripts). ```yaml workflows: ios: inputs: submitToTestFlight: description: Enable testflight submission type: boolean default: false runTests: description: Run tests before build type: boolean default: true integrations: app_store_connect: MY_ASC_KEY scripts: - name: Run tests script: xcode-project run-tests --project "project.xcodeproj" --scheme "App" test_report: build/ios/test/*.xml when: condition: ${{ inputs.runTests }} - ./setup_code_signing.sh - xcode-project build-ipa --project "project.xcodeproj" --scheme "app" artifacts: - build/**/*.ipa publishing: app_store_connect: auth: integration submit_to_testflight: ${{ inputs.submitToTestFlight }} ``` In the above workflow user is prompted with two options when starting a build: 1. whether to run tests before build, which controls the first script step using `when` condition, 2. whether to submit the built ipa to TestFlight as part of App Store Connect publishing. Defaults are provided for both inputs and a standard build can be started without choosing anything. > > **Note**: When using booleans in textual context, such as in scripts, truthy and falsy values are interpolated as strings `"true"` and `"false"` respectively. For example, > ``` > echo "My boolean: ${{ inputs.myTruthValue }}" > ``` > would be resolved to > ``` > echo: "My boolean: true" > ``` > if build is started with `myTruthValue: true`. > ### Using inputs for publishing You can use number inputs for build versioning or to control other release parameters, such as rollout fraction or in-app update priority. As with booleans, number types are also persisted when substitutions are being made to workflows unless the value is not directly used within a string. Both integers and floating point numbers are accepted as valid values. ```yaml workflows: ios: inputs: googlePlayInAppUpdatePriority: description: Google Play publisher priority type: number default: 4 buildNumber: description: Build number for artifact versioning type: number rolloutFraction: description: Rollout fraction for Google Play release promotion type: number default: 0.25 environment: groups: - google_credentials scripts: - flutter build apk --build-number="${{ inputs.buildNumber }}" --release publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS in_app_update_priority: ${{ inputs.googlePlayInAppUpdatePriority }} release_promotion: track: alpha rollout_fraction: ${{ inputs.rolloutFraction }} ``` ### Using inputs for determining build distribution type Inputs with type `choice` provide a way to limit the user to choose only specific predefined values for inputs, such as distribution type. Choice options are shown to user in a dropdown. ```yaml workflows: ios: inputs: distributionType: description: iOS distribution type type: choice options: ["ad_hoc", "app_store", "development", "invalid"] default: development integrations: app_store_connect: MY_ASC_KEY environment: ios_signing: distribution_type: ${{ inputs.distributionType }} bundle_identifier: com.example.app scripts: - xcode-project use-profiles - flutter build ipa --debug --export-options-plist "${HOME:?}/export_options.plist" ``` ## Viewing inputs values To better distinguish builds based on their input values, you can display the chosen value in the Build overview or on the builds page by using [labels](https://docs.codemagic.io/yaml-basic-configuration/yaml-getting-started/#labels). The following sample snippet can be referenced to achieve it: ```yaml inputs: xcode_version: description: Set Xcode version type: number publish_to_appstore: description: App Store publishing type: boolean ``` Then, assign the input to a label: ```yaml labels: - Xcode_version ${{ inputs.xcode_version }} - App_Store_Publishing ${{ inputs.publish_to_appstore }} ``` ================================================================================ source: https://docs.codemagic.io/yaml-notification/status-badges/ title: Build status badges description: How to add build status badges using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Build status badges > How to add build status badges using codemagic.yaml Adding Codemagic status badges to repositories helps to keep the latest build status visible. The build status badge is workflow-specific and displays whether the build passed or failed. ## Adding status badges to your repository The build status badge URL can be constructed as follows: `https://api.codemagic.io/apps///status_badge.svg` 1. To find the ``, navigate to your application in the Codemagic UI and copy the ID shown in the URL after `https://codemagic.io/app/`. 2. In the URL, replace `` with the ID (workflow name defined in `codemagic.yaml`) of the workflow whose build status you want to display. Based on the following YAML example, the right substitute for `` would be `release-workflow`. ```yaml workflows: release-workflow: name: Release ``` Thus, the final URL should look something like `https://api.codemagic.io/apps/5fcd4dc959d78f8de3d0af97/release-workflow/status_badge.svg`. To use the build status badge with markdown, e.g. when adding it to a repository's README, it should be formatted in the following way: ```markdown [![Codemagic build status](https://api.codemagic.io/apps///status_badge.svg)](https://codemagic.io/app///latest_build) ``` > > > **Note:** If builds are set to public (or the user has logged in and has access to the build), then clicking on the link will open up the build page on Codemagic. > > ================================================================================ source: https://docs.codemagic.io/rest-api/builds/ title: Builds API description: API for starting and managing app builds last_modified: 2025-09-03 ================================================================================ # Builds API > API for starting and managing app builds APIs for managing builds are currently available for developers to preview. During the preview period, the API may change without advance notice. > > **Note:** Using REST API will not fetch information about workflows when configuring with **codemagic.yaml**. It is because only workflows from the Workflow Editor are defaulted as no accessible data is present from **codemagic.yaml** until a repository is cloned, which means that there is no way to retrieve workflow IDs from **codemagic.yaml** before triggering a build. > ## Start a new build `POST /builds` > > **Note:** The workflow and branch information is passed with the curl request when starting builds from an API request. Any configuration related to triggers or branches in Flutter workflow editor or codemagic.yaml is ignored. > #### Parameters | **Name** | **Type** | **Description** | |---------------| -------- |---------------------------------------------------------------------------------------------------------------------------------------------------------| | `appId` | `string` | **Required.** The application identifier. | | `workflowId` | `string` | **Required.** The workflow identifier as specified in YAML file. | | `branch` | `string` | Optional. The branch name. Either `branch` or `tag` is **required**. | | `tag` | `string` | Optional. The tag name. Either `branch` or `tag` is **required**. | | `environment` | `object` | Optional. Specify environment variables, variable groups, and software versions to override or define in workflow settings. | | `labels` | `list` | Optional. Specify labels to be included for the build in addition to existing labels. | #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ --data '{ "appId": "", "workflowId": "", "branch": "" }' \ -X POST https://api.codemagic.io/builds ``` #### Pass custom build parameters ```json { "appId": "5c9c064185dd2310123b8e96", "workflowId": "release", "branch": "master", "labels": ["foo", "bar"], "environment": { "variables": { "ENVIRONMENT_VARIABLE_1": "...", "ENVIRONMENT_VARIABLE_2": "..." }, "groups": [ "variable_group_1", "variable_group_2" ], "softwareVersions": { "xcode": "11.4.1", "flutter": "v1.12.13+hotfix.9" } }, "instanceType": "mac_mini_m2" } ``` #### Response ```json { "buildId":"5fabc6414c483700143f4f92" } ``` ## Cancel build `POST /builds/:id/cancel` #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ --request POST https://api.codemagic.io/builds//cancel ``` The request will return `208 Already Reported` if the build has already finished. > > **Note:** If you have multiple similar workflows for the same project, you can configure your workflows dynamically using API calls, read more about it here. > ================================================================================ source: https://docs.codemagic.io/troubleshooting/common-ios-issues/ title: Common iOS issues description: How to overcome common issues building iOS mobile apps on Codemagic last_modified: 2026-06-26 ================================================================================ # Common iOS issues > How to overcome common issues building iOS mobile apps on Codemagic ### Getting **Not uploaded** message under the code signing identities for iOS provisioning profiles. ###### Description When uploading a provisioning profile by opening the **Code signing identities** section in personal account or team settings, you are seeing a red cross ❌. {{}} ###### Cause It happens when the certificate that is uploaded under the **iOS certificates** tab is not included in that particular provisioning profile that is giving you a red cross warning. ###### Solution Find that exact profile in your Apple Developer account > [Profiles](https://developer.apple.com/account/resources/profiles) page and click to edit it. Then choose the certificate that you have uploaded in the Codemagic UI under **Code signing identities** and click to save it. After downloading it to your local machine, you need to upload it to **Code signing identities** in your team settings. {{< /collapsible >}} ### Error creating authentication sessions ###### Description When App Store Connect is not correctly set up, users might encounter an error message similar to the following: altool[xxx:xxx] *** Error: Unable to validate archive '/Users/builder/ipas/xxx'. altool[xxx:xxx] *** Error: code -22020 (Unable to validate your application. We are unable to create an authentication session.) {{}} ###### Cause The most common reason for this error message is using your Apple ID password instead of an [app-specific password](https://support.apple.com/en-us/HT204397) in App Store Connect publishing settings. ###### Solution Publishing iOS apps with **app-specific-password** is deprecated, refer to the documentation [here](https://docs.codemagic.io/yaml-publishing/app-store-connect/) that explains how to publish iOS apps to App Store Connect. {{< /collapsible >}} ### Errors with code signing This is the list of the most common issues that may cause iOS code signing errors during a CI build. #### The uploaded certificate is in a wrong format or corrupt ###### Description Codemagic looks for a certificate in **Personal Information Exchange** (`.p12`) format. {{}} ###### Solution See [how to export the certificate](../code-signing/ios-code-signing/#exporting-signing-certificate-and-provisioning-profile). {{< /collapsible >}} #### The uploaded certificate and provisioning profile do not match ###### Description For example, you're using a **development** certificate with a **distribution** profile to sign the build, or the certificate used for signing is not included in the provisioning profile. {{}} ###### Solution Make sure the certificate and the provisioning profile types match. {{< /collapsible >}} #### Missing entitlements in the Apple Developer portal ###### Description In case of getting errors about an existing provisioning profile's missing entitlements, you can add or update the entitlements by finding and editing the profile in **Apple Developer portal > Certificates, identifier & profiles > Identifiers**. Alternatively, it can be done in Xcode under **Signing & Capabilities** of the given target. When building a Flutter project, a similar error could be thrown due to a couple of other reasons: > Code Signing Error: "Runner" requires a provisioning profile with the Push Notifications feature. Select a provisioning profile in the Signing & Capabilities editor. {{}} ###### Solution 1. Setting up code signing settings on Xcode project step is missing. Double check if **xcode-project use-profiles** step is missing in **codemagic.yaml** before executing the build command. 2. Export options are not valid in the project. It can be configured by adding **--export-options-plist=/Users/builder/export_options.plist** to the build command in **codemagic.yaml**. {{< /collapsible >}} #### iOS scheme not specified for the `archive` action of an Xcode build ###### Description This applies when your app has custom iOS schemes. By default, Codemagic builds the `Runner` scheme. {{}} ###### Solution You can use the `CM_FLUTTER_SCHEME` [environment variable](../building/environment-variables) to specify another scheme. {{< /collapsible >}} #### Bundle ID mismatch ###### Description Make sure that the bundle ID entered in automatic code signing setup on Codemagic matches the bundle ID in the build configuration that is used for archiving the app with Xcode. Codemagic assigns provisioning profiles to build targets and configurations before building the iOS app. That assignment is based on the bundle ID match in both provisioning profile and the build configuration. If a signing configuration is not assigned to the build target/configuration that is used for archiving, the build will fail. If bundle identifiers are not properly set for your project, you will often see an error message similar to this one: ``` ❌ error: Runner has conflicting provisioning settings. Runner is automatically signed, but code signing identity Apple Push Services has been manually specified. Set the code signing identity value to "iPhone Developer" in the build settings editor, or switch to manual signing in the Signing & Capabilities editor. (in target 'Runner' from project 'Runner') ``` {{}} ###### Solution * Confirm that you have set the correct bundle identifiers for all targets in Xcode. * Verify that the bundle identifier set in Xcode matches the bundle identifier set in the Flutter workflow editor under code signing. {{< /collapsible >}} #### Outdated Provisioning profile that does not include Associated Domains ###### Description In such cases, you will often see an error message similar to this one: ``` ❌ error: Provisioning profile "CodeMagic" doesn't support the Associated Domains capability. (in target 'Runner' from project 'Runner'). ❌ error: Provisioning profile "CodeMagic" doesn't include the com.apple.developer.associated-domains entitlement. (in target 'Runner' from project 'Runner'). ``` {{}} ###### Solution Log in to your Apple Developer account and verify: * That you are using the correct bundle identifier. * If missing, add the Associated Domain Entitlement from there. * Update the provisioning profile and use it to configure your project. {{< /collapsible >}} #### iOS deployment target issue ###### Description A common error message with regard to deployment target is the following: ``` The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.4.99 ``` The error usually occurs if the deployment target set in Podfile is lower than required or when the Podfile is missing. {{}} ###### Solution * Confirm if a Podfile exists in the repository. If not, create a Podfile in the `ios` directory and insert the following manually in there: ```bash # Uncomment the next line to define a global platform for your project platform :ios, '13.0' target 'Runner' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! # Pods for Runner end ``` * Check the Podfile and make sure that `platform :ios, '13.0'` is set to `13.0` or above as required by dependencies. * Confirm if `IPHONEOS_DEPLOYMENT_TARGET` is set to 9.0 or above {{< /collapsible >}} ### Build hangs at `Xcode build done` ###### Description When building for iOS, the build gets stuck after showing `Xcode build done` in the log but does not finish and eventually times out. Log output look similar to this example == Building for iOS == == /usr/local/bin/flutter build ios --release --no-codesign == Warning: Building for device with code signing disabled. You will have to manually codesign before deploying to device. Building net.butterflyapp.trainer for device (ios-release)... Running pod install... 3.7s Running Xcode build... Xcode build done. 203.6s **Flutter**: `1.7.8+hotfix.3`, `1.7.8+hotfix.4`, `1.9.1+hotfix.2`, `1.9.1+hotfix.4`, `1.9.1+hotfix.5` {{}} ###### Solution This is a known issue that occurs randomly and can be traced back to Flutter: * https://github.com/flutter/flutter/issues/28415 * https://github.com/flutter/flutter/issues/35988 This issue is known to be fixed on the `master` channel. {{< /collapsible >}} ### Mac M2 issues #### Builds not starting ###### Description Builds not starting at all even though the team has access to the `mac_mini_m2` instance. {{}} ###### Solution This error occurs on M2 machines when the `xcode` property is set to a version that is not supported. Please configure your workflow to use a supported Xcode version. See the available versions on the [Codemagic macOS build machine specs](../specs/versions-macos/) page. {{< /collapsible >}} #### Builds failing intermittently ###### Description Builds are intermittently failing without a clear reason. {{}} ###### Solution This issue can be caused by an outdated version of Xcode. Please use the latest Xcode version available on Codemagic, if possible. {{< /collapsible >}} #### Error when using an adhoc profile ###### Description When building iOS apps with an adhoc profile you might get this error: ``` error: Provisioning profile "XXXX" doesn't include the currently selected device "builder's Virtual Machine" (identifier XXXXXXXX-XXXXXXXXXXXXXXXX). (in target 'XXXXXXX' from project 'App'). ``` {{}} ###### Solution Add the following to the end of your `xcode-project build-ipa` command: ```yaml --archive-flags="-destination 'generic/platform=iOS'" ``` {{< /collapsible >}} ### XCode 14 known issues #### Signing for "XXX" requires a development team ###### Description Error (Xcode): Signing for "XXX" requires a development team. Select a development team in the Signing & Capabilities editor {{}} ###### Solution This issue has been fixed on the stable channel in **Flutter 3.3.3**. However, if you would like to continue using previous versions of Flutter you can open `ios/Podfile` and add the following at the end of it: ```yaml post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) target_is_resource_bundle = target.respond_to?(:product_type) && target.product_type == 'com.apple.product-type.bundle' target.build_configurations.each do |build_configuration| if target_is_resource_bundle build_configuration.build_settings['CODE_SIGNING_ALLOWED'] = 'NO' build_configuration.build_settings['CODE_SIGNING_REQUIRED'] = 'NO' build_configuration.build_settings['CODE_SIGNING_IDENTITY'] = '-' build_configuration.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = '-' end end end end ``` In XCode 13 `CODE_SIGNING_ALLOWED` was set to `NO` by default for resource bundles. While in Xcode 14 they changed this to default to `YES`, which might be causing the problems. {{< /collapsible >}} ### A required agreement is missing or has expired ###### Description Builds are failing with the following message: A required agreement is missing or has expired. - This request requires an in-effect agreement that has not been signed or has expired. {{}} ###### Cause Apple has updated Apple Developer Program License Agreement and it needs to be reviewed ###### Solution In order to update your existing apps and submit new apps to the App Store, the Account Holder must review and accept the updated agreement by signing in to their [account](https://appstoreconnect.apple.com/agreements/#/) on the Apple Developer website. {{< /collapsible >}} ### Certificate will no longer be valid in 30 days ###### Description You received e-mail from Apple stating that: Your Distribution Certificate will no longer be valid in 30 days. To generate a new certificate, sign in and visit Certificates, Identifiers & Profiles. {{}} ###### Cause Distribution certificates issued by Apple have a validity period of one year from the date of issuance. After one year, they expire, which means they can no longer be used to sign and distribute apps. ###### Solution Rest assured, Codemagic simplifies the certificate management process for you. Here's how it works: - By providing your **App Store Connect API key ID**, **issuer ID**, and API key as a **.p8 file** (more info about how to add environment variables can be found [here](https://docs.codemagic.io/yaml-basic-configuration/configuring-environment-variables/)), Codemagic takes care of your certificate and provisioning profile management, including the automatic renewal of certificates, except in the case where you are using a private RSA key associated with an iOS Distribution certificate previously generated within your Apple Developer Program account. You can find additional information on how to update an RSA key (CERTIFICATE_PRIVATE_KEY) for a certificate [here](https://docs.codemagic.io/yaml-code-signing/alternative-code-signing-methods/#:~:text=Obtaining%20the%20Certificate%20private%20key). - If you're using `manual code signing` or `Codemagic signing identities (CSI)`, you will need to create and upload your certificates and profiles that you generated on the Apple Developer UI manually to Codemagic. Alternatively, using code signing identities, you can also fetch or create resources directly from the Codemagic UI. Navigate to **Settings** > **Code signing identities** > **iOS certificates** to do so. {{< /collapsible >}} ### Did not find xcodeproj from /Users/builder/clone/ios ###### Description Builds are failing with the following message: Did not find xcodeproj from /Users/builder/clone/ios {{}} ###### Cause Codemagic is not able to locate the Xcode project file (xcodeproj) in the expected directory. This could be due to the project structure being different from the script's assumptions, most likely because the project is a mono repo. ###### Solution The solution is to update the path to your project. In order to target apps inside your monorepo app, **working_directory** key is used. For example, the following sample snippet shows how it works: ```yaml workflows: default-workflow: name: Default workflow instance_type: mac_mini_m2 max_build_duration: 120 # Specify path to the app folder like this working_directory: ios/path-to-your-project ``` If you are using the Workflow Editor, specify the project path inside the Build step by selecting your project from the Project path dropdown. {{< /collapsible >}} ### Failed to set code signing settings for **/*.xcodeproj ###### Description When building a React Native iOS project, you may encounter an error similar to the following, often referencing a dependency inside the `node_modules` directory: Searching for files matching /Users/builder/clone/**/*.xcodeproj Failed to set code signing settings for node_modules/react-native-fast-image/ios/FastImage.xcodeproj For example, this error may appear for packages such as `react-native-fast-image`, `react-native-camera-kit`, or other dependencies that include their own `.xcodeproj` files. {{}} ###### Cause By default, Codemagic's `xcode-project use-profiles` command searches recursively for all `.xcodeproj` files in the repository to apply code signing settings. In React Native projects, several dependencies inside the `node_modules` directory (e.g. `react-native-fast-image`) include their own `.xcodeproj` files. As a result, Codemagic may attempt to apply signing settings to these dependency projects instead of the actual application project. ###### Solution Explicitly specify your app's .xcodeproj file when running the `xcode-project use-profiles` command to ensure that code signing settings are applied only to the main project. For example, update your script as follows: ```yaml scripts: - name: Set up code signing script: | xcode-project use-profiles --project ios/.xcodeproj ``` Alternatively, if your iOS directory contains a single `.xcodeproj` file, you can use a wildcard: ```yaml xcode-project use-profiles --project ios/*.xcodeproj ``` {{< /collapsible >}} ### Scheme "xxx" not found from repository! Please reconfigure your project. ###### Description When building a Flutter app using the Workflow Editor, you may encounter the following error during the Installing dependencies step: Scheme "xxx" not found from repository! Please reconfigure your project. {{}} ###### Cause This issue usually occurs when the iOS project files (such as schemes or workspace definitions) are not fully generated before the automatic dependency installation starts. Even though flutter pub get is automatically executed by Codemagic later in the build process, it might happen too late, before the Xcode project is properly set up. In some cases, the problem can also occur if the specified scheme name is incorrect or if the scheme has not been shared in Xcode. ###### Solution 1. Verify your scheme configuration in Xcode locally. Open your project in Xcode and go to Product > Scheme > Manage Schemes and make sure the scheme name matches exactly (case-sensitive) and that the Shared checkbox is enabled for that scheme. 2. Regenerate project files before dependencies are installed If the scheme is correct and shared, add the following command to the Post-clone script section of your workflow: ```yaml flutter pub get ``` This ensures that all necessary iOS project files are properly generated before dependency installation begins. {{< /collapsible >}} ### No matching profiles found for bundle identifier "io.example.test" and distribution type "app_store" ###### Description When building an iOS app in Codemagic, you may encounter the following error when starting a build: No matching profiles found for bundle identifier "io.example.test" and distribution type "app_store" This means that in the ios_signing section of your YAML configuration, you are referencing a provisioning profile that has not yet been uploaded to Codemagic. ```yaml ios-workflow: name: iOS Workflow instance_type: mac_mini_m2 environment: ios_signing: # This part indicates manual code signing distribution_type: app_store bundle_identifier: io.example.test ``` {{}} ###### Solution Go to **Settings** > **Code signing identities** > **iOS Provisioning profiles** and make sure a valid profile for your bundle identifier and distribution type exists. {{< /collapsible >}} ================================================================================ source: https://docs.codemagic.io/yaml-distributing/firebase-app-distribution/ title: Firebase App Distribution with codemagic.yaml description: How to deploy an app to Firebase App Distribution using codemagic.yaml last_modified: 2026-06-18 ================================================================================ # Firebase App Distribution with codemagic.yaml > How to deploy an app to Firebase App Distribution using codemagic.yaml

> > **Note:** This guide only applies to workflows configured with the **codemagic.yaml**. If your workflow is configured with **Flutter workflow editor**, please go to [Publishing an app to Firebase App Distribution with Flutter workflow editor](../flutter-distributing/firebase-app-distribution). > ### Requirements For distributing an iOS application to [Firebase Console](https://console.firebase.google.com/), your application must use a development, Ad Hoc or Enterprise distribution profile. To authenticate with Firebase, Codemagic requires either a **Firebase token** or a service account with **Firebase App Distribution Admin** role, as shown below: #### 1. Authenticating via service account Service accounts are useful for setting up App Distribution in a CI environment. Authenticating with a [service account](https://cloud.google.com/iam/docs/creating-managing-service-accounts) allows you to use client libraries (e.g., the Firebase CLI or fastlane) to distribute your builds. When you use a service account to authenticate, Firebase uses [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/production) to locate your app's credentials, which you can provide by setting the `GOOGLE_APPLICATION_CREDENTIALS` environment variable. 1. On the Firebase project page, navigate to **Project settings** by clicking on the cog button. Select the **Service accounts** tab. Click on the **X service accounts** button as shown on the screenshot.

![Firebase service accounts](../uploads/firebase_service_accounts_button.png) 2. This will lead you to the Google Cloud Platform. In step 1, fill in the **Service account details** and click **Create**. The name of the service account will allow you to identify it among other service accounts you may have created. 3. In step 2, click the **Select a role** dropdown menu and choose the role. Note that **Editor** role is required for Firebase Test Lab and **Firebase App Distribution Admin** for Firebase App Distribution. 4. In step 3, you can leave the fields blank and click **Done**. 5. In the list of created service accounts, identify the account you have just created and click on the menu in the **Actions** column, then click **Manage keys**.

![Google cloud key](../uploads/google_cloud_three.png) 6. In the Keys section, click **Add Key > Create new key**. Make sure that the key type is set to `JSON` and click **Create**. Save the key file in a secure location to have it available.

![Google cloud json](../uploads/google_cloud_four.png) 7. Configure variables in codemagic.yaml: 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `FIREBASE_SERVICE_ACCOUNT`. 3. Copy and paste the content of the service account JSON file as **_Variable value_**. 4. Enter the variable group name, e.g. **_firebase_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to add a variable named `GOOGLE_APPLICATION_CREDENTIALS` and set its value to a path where the credentials file will be placed during build. Suggested value is "$CM_BUILD_DIR/firebase_credentials.json" 8. Add variables in your `codemagic.yaml` ```yaml environment: groups: - firebase_credentials ``` #### 2. Authenticating via token > > **Warning:** Firebase has marked authentication via token as deprecated and might disable it in future versions of `firebase tool`. Please authenticate using a service account, as described above. > To retrieve your Firebase token, follow the instructions in [Firebase documentation](https://firebase.google.com/docs/cli#cli-ci-systems). 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `FIREBASE_TOKEN`. 3. Enter the token value as **_Variable value_**. 4. Enter the variable group name, e.g. **_firebase_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. ### Distribution to Firebase Example configuration for publishing Android and iOS artifacts to Firebase: ```yaml publishing: firebase: # use this line to authenticate via service account firebase_service_account: $FIREBASE_SERVICE_ACCOUNT # or this line to authenticate via token: # firebase_token: $FIREBASE_TOKEN android: # Add your Android app id retrieved from Firebase console app_id: x:xxxxxxxxxxxx:android:xxxxxxxxxxxxxxxxxxxxxx # Add one or more groups that you wish to distribute your Android application to. # You can create groups in the Firebase console groups: - androidTesters - ... ios: # Add your iOS app id retrieved from Firebase console app_id: x:xxxxxxxxxxxx:ios:xxxxxxxxxxxxxxxxxxxxxx # Add one or more groups that you wish to distribute your iOS application to. # You can create groups in the Firebase console groups: - iosTesters - ... ``` If you wish to pass release notes with your build, create a `release_notes.txt` file and add it to the project working directory, which is either the repository root directory or the Project path specified in the Build section in your workflow settings. Codemagic will fetch the content of that file and publish it with the build. In order to distribute an `.aab` to testers via Firebase App Distribution, your Firebase project must be linked to your Google Play account. More information is available [here](https://firebase.google.com/docs/app-distribution/android/distribute-console?apptype=aab#before_you_begin) #### Publishing only the Android app bundle or APK artifact to Firebase App Distribution If you are building both an Android app bundle and an APK in your workflow, Codemagic will, by default, try to publish the bundle to Firebase App Distribution. If you wish to publish the APK, specify the artifact type as `apk` using the `artifact_type` field. ```yaml publishing: firebase: firebase_service_account: $FIREBASE_SERVICE_ACCOUNT android: app_id: x:xxxxxxxxxxxx:android:xxxxxxxxxxxxxxxxxxxxxx groups: - androidTesters - ... artifact_type: 'apk' # Replace with 'aab' to only publish the Android app bundle ``` ## Publishing to Firebase App Distribution with Fastlane Before running a lane, you should install Fastlane Firebase app distribution plugin. ```yaml - name: Install fastlane-plugin-firebase_app_distribution script: | gem install bundler sudo gem install fastlane-plugin-firebase_app_distribution --user-install ``` Then you need to call a lane. This code is similar for Android and iOS. ### Option: Android %!s() ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-native-ios-app/ title: iOS native apps description: How to build an iOS app with codemagic.yaml last_modified: 2026-03-24 ================================================================================ # iOS native apps > How to build an iOS app with codemagic.yaml This guide will illustrate all of the necessary steps to successfully build and publish a native iOS app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-native-quick-start). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. #### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ##### Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > ## Configure scripts to build the app Add the following scripts to your `codemagic.yaml` file in order to prepare the build environment and start the actual build process. In this step you can also define the build artifacts you are interested in. These files will be available for download when the build finishes. For more information about artifacts, see [here](../yaml/yaml-getting-started/#artifacts). ```yaml ios-native: environment: vars: BUNDLE_ID: "io.codemagic.sample.iosnative" XCODE_WORKSPACE: "CodemagicSample.xcworkspace" # <-- Name of your Xcode workspace XCODE_SCHEME: "CodemagicSample" # <-- Name of your Xcode scheme scripts: # ... - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "$CM_BUILD_DIR/$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM ``` > > **Note**: If you don't have a workspace, use `--project "MyXcodeProject.xcodeproj"` instead of the `--workspace "MyXcodeWorkspace.xcworkspace"` option. > ## Build versioning If you are going to publish your app to App Store, each uploaded artifact must have a new version. Codemagic allows you to easily automate this process and increment the version numbers for each build. For more information and details, see [here](../configuration/build-versioning). In order to get the latest build number from App Store or TestFlight, you will need the App Store credentials as well as the **Application Apple ID**. This is an automatically generated ID assigned to your app and it can be found under **General > App Information > Apple ID** under your application in App Store Connect. 1. Add the **Application Apple ID** to the `codemagic.yaml` as a variable 2. Add the script to get the latest build number using `app-store-connect` and configure the new build number using `agvtool`. 3. Your `codemagic.yaml` will look like this: ```yaml workflows: ios-workflow: name: iOS Workflow integrations: app_store_connect: environment: vars: APP_STORE_APPLE_ID: 1555555551 scripts: - name: Increment build number script: | #!/bin/sh cd $CM_BUILD_DIR LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number "$APP_STORE_APPLE_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build ipa for distribution script: | # build command ``` ## Publishing Codemagic offers a wide array of options for app publishing and the list of partners and integrations is continuously growing. For the most up-to-date information, check the guides in the **Configuration > Publishing** section of these docs. To get more details on the publishing options presented in this guide, please check the [Email publishing](../yaml-publishing/email) and the [App Store Connect](../yaml-publishing/app-store-connect) publishing docs. #### Email publishing If the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to App Store Codemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: ```yaml workflows: ios-native-workflow: name: iOS Native max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: codemagic environment: ios_signing: distribution_type: app_store bundle_identifier: io.codemagic.sample.iosnative vars: BUNDLE_ID: "io.codemagic.sample.iosnative" XCODE_WORKSPACE: "CodemagicSample.xcworkspace" # <-- Put the name of your Xcode workspace here XCODE_SCHEME: "CodemagicSample" # <-- Put the name of your Xcode scheme here APP_STORE_APPLE_ID: 1555555551 xcode: latest cocoapods: default scripts: - name: Install CocoaPods dependencies script: | pod install - name: Set up provisioning profiles settings on Xcode project script: xcode-project use-profiles - name: Increment build number script: | cd $CM_BUILD_DIR LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number "$APP_STORE_APPLE_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "$CM_BUILD_DIR/$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false app_store_connect: auth: integration # Configuration related to TestFlight (optional) # Note: This action is performed during post-processing. submit_to_testflight: true beta_groups: # Specify the names of beta tester groups that will get access to the build once it has passed beta review. - group name 1 - group name 2 # Configuration related to App Store (optional) # Note: This action is performed during post-processing. submit_to_app_store: false ``` ## Next steps While this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. ================================================================================ source: https://docs.codemagic.io/flutter-publishing/publishing-to-microsoft-store/ title: Microsoft Store publishing with Flutter workflow editor description: Deploy a Flutter desktop app to Microsoft Store using the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # Microsoft Store publishing with Flutter workflow editor > Deploy a Flutter desktop app to Microsoft Store using the Flutter workflow editor Codemagic enables you to automatically publish your desktop app to the Microsoft Store. The application submission is automatically submitted to the review/certification process in the Partner Center. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured with **codemagic.yaml** please go to [Publishing to Microsoft Store using codemagic.yaml](../yaml-publishing/microsoft-store). > ## Requirements To publish your Windows desktop app to Microsoft Store, you will have to have the application set up on Partner Center and have a prior successful submission to the Microsoft Store. It is also essential that your application is packaged as a [MSIX package](../building/building-for-desktop/#building-msix-packages). Codemagic uses the [Microsoft Store submission API](https://docs.microsoft.com/en-us/windows/uwp/monetize/create-and-manage-submissions-using-windows-store-services) to handle publishing to the Microsoft Store. Thus details for generating temporary Azure AD access tokens on the user's behalf are required. To fetch these details, the application has to be set up in Azure AD and linked to the users' Partner Center account. ## Setting up publishing to Microsoft Store on Codemagic This section gives step-by-step instructions on how to configure publishing to Microsoft Store using Flutter workflow editor. ### Step 1. Setting up Azure AD with your Partner Center account Follow the instructions [here](../knowledge-base/partner-center-authentication) to get your tenant ID, client ID, and client secret which are required for generating temporary access tokens to manage submissions in the Partner Center. ### Step 2. Connecting the Microsoft Partner Center integration for your team/account The Microsoft Partner Center integration can be enabled in **Personal Account > Settings > Integrations** for personal projects and in **[Your team] > Settings > Team integrations** for projects shared in the team (if you're a team admin). This allows you to conveniently use the same access credentials for publishing across different apps and workflows. 1. In the list of available integrations, click the **Connect** button for **Partner Center**. 2. In the **Tenant name** field, provide a name for the set of credentials you are going to set up the integration with. This is for identifying the set of credentials in Codemagic. 3. Enter the **Tenant ID** related to your Azure AD account. 4. Enter the **Client ID** related to your application in Azure AD. 5. Enter the value of your **Client secret** from your Certificates & secrets section under your application in Azure AD. 6. Click **Save** to finish the setup. You can add additional sets of credentials by clicking **Add another tenant** right after adding the first tenant and repeating the steps described above. You can delete existing tenants or add new ones when you click **Manage tenants** next to the Partner Center integration. ### Step 3. Enabling Microsoft Store publishing for workflow Once you configure publishing to Microsoft Store, Codemagic will automatically distribute the app to Microsoft Store every time you build the workflow. > > **Note:** The very first version of the app must be submitted in the Partner Center manually. You can download the **MSIX** package from the build artifacts. > 1. Navigate to the Distribution section in app settings. 2. Click **Microsoft Partner Center** to expand the option. 3. Choose the **tenant** you have configured in your team or personal account settings. 4. Provide the **Store ID** of the application that has been set up in the Partner Center. 5. Provide the necessary package arguments for publishing (**Package name**, **Publisher ID**, **Publisher name**) These values can be found in [Microsoft Partner Center](https://partner.microsoft.com/en-us/dashboard/home) when navigating to **Apps and games > [Your application] > Product Identity**. 6. Set a version for your package by configuring the **Package version** field, to see how to increment this number automatically check the **Version your package** section below. 7. If you want to publish the .msix even when one or more tests fail, mark the **Publish even if tests fail** checkbox. 8. Select **Enable publishing to Microsoft Store** at the top of the section to enable publishing. #### Version your package Check out how to version your package in the [Microsoft documentation](https://docs.microsoft.com/en-us/windows/uwp/publish/package-version-numbering). Note that per Microsoft Store requirements applications are not allowed to have a version with a revision number (last digit of the version) other than zero. To version your `MSIX package` for Microsoft Store Submission with Codemagic, you can either set the value as a string, such as `1.0.0.0`, or use Codemagic's read-only environment variables (`$PROJECT_BUILD_NUMBER`, `$BUILD_NUMBER`) to automatically increment versions on every release. In order to do so, you can simply set the `Package version` field as `1.0.$BUILD_NUMBER.0`, for example, which will use the Codemagic build number for the given workflow to set the package version. Note that this is one of many possible approaches to versioning your application and is used only as an example. ================================================================================ source: https://docs.codemagic.io/rn-codepush/releasing-updates/ title: Releasing updates description: Publish and promote CodePush updates last_modified: 2026-06-05 ================================================================================ # Releasing updates > Publish and promote CodePush updates This guide explains how to publish and manage over-the-air (OTA) updates using the CodePush CLI. > > **Important**: > CodePush updates are not managed through the Codemagic UI. All releases, promotions, and rollbacks are performed using CLI commands — locally, in CI/CD pipelines, or any environment with the CLI installed and authenticated. > ## Overview After integrating the CodePush SDK into your React Native app as explained in the [previous section](http://localhost:1313/rn-codepush/setup/#add-codepush-to-a-react-native-app), you can ship updates without rebuilding or resubmitting your app to the App Store or Google Play. CodePush delivers: * Updated JavaScript bundles * App assets (e.g. images, fonts) These updates are downloaded silently by users’ devices (depending on your install mode). ## Recommended Workflow Use a **Staging → Production** promotion flow for all releases. This ensures every update is tested before reaching end users and keeps production stable. **Step 1: Release to Staging** Publish the update to the Staging deployment first. This makes it available only to internal users, QA, or testers. ```bash code-push release-react --deployment-name Staging ``` At this stage: * The update is not visible to production users * You can safely validate functionality and stability * Multiple iterations can be released without impact **Step 2: Validate in Staging** Test the update thoroughly before promoting it. Typical checks include: * App launch and navigation flow * New features and UI changes * Regression testing of existing functionality * Crash-free behavior on target devices * Compatibility with supported app versions Only proceed once the update is confirmed stable. **Step 3: Promote to Production** After successful validation, promote the exact same update from Staging to Production. No rebuild is required. ```bash code-push promote Staging Production ``` This ensures: * The tested build is what users receive * No discrepancies between test and production releases * Faster and safer rollout to all users **Summary Flow:** ```bash Release to Staging -> Internal Testing & QA -> Promote to Production ``` Think of this as a single pipeline with two decision points: * Release → Staging: publish a new update for validation * Test: verify the update is safe to ship * Promote → Production: make it live for users ## What gets uploaded CodePush delivers only JavaScript runtime assets and the files required by the application’s JS layer. A typical update includes only changed files and assets, such as: * JavaScript bundle * Static assets (images, fonts, etc.) * Release metadata (deployment and version information) CodePush does not include native binaries such as **.apk** or **.ipa** files. OTA updates are limited to changes in the JavaScript layer only. Any modification involving native code (e.g. Swift, Objective-C, Java, Kotlin, or native modules) must be released through the App Store or Google Play. ### Delta updates CodePush uses delta updates (file-level diffs) for each release and delivers only the files or assets that changed. This means users download a lightweight delta package instead of the full JavaScript bundle and all assets every time, resulting in faster updates and smaller downloads for users. ## Version control CodePush uses a two-layer versioning model that separates native app versions from JavaScript update versions. This ensures updates are only delivered to compatible app binaries while still allowing fast OTA iteration. **1. Native App Version (Binary Version)** This is the version of the app installed from the App Store / Google Play. It defines the native code baseline that a CodePush update must be compatible with. It maps to **CFBundleShortVersionString (e.g. 1.2.0)(for iOS)** and **versionName (e.g. 1.2.0)(for Android)** This is the version you configure in CodePush as the target binary version. **2. CodePush Update Version** Each CodePush release is a **JavaScript + asset bundle update** applied on top of a native binary. These updates: * Do not change the native app version * Are stored and ordered within a deployment history * Can be rolled back independently of app store releases **Target Binary Version (Compatibility Control)** To ensure updates are only delivered to compatible app builds, CodePush uses `--target-binary-version` This flag determines which native app versions are eligible to receive the update. It directly matches: * CFBundleShortVersionString on iOS * versionName on Android For an example, if you specify: ```bash --target-binary-version "1.2.0" ``` Then only apps running version 1.2.0 will receive the update. You can also define ranges: ```bash --target-binary-version "~1.2.0" ``` This includes compatible patch versions like **1.2.1**, **1.2.2**, etc., depending on semantic versioning rules. ## Next steps After the first release workflow is working, teams typically add additional controls to manage production updates. The next section covers: - staged rollouts - version targeting strategies - rollbacks - update safety mechanisms For rollout monitoring and release analytics, see [Analytics](/rn-codepush/analytics/). For troubleshooting failed installs, see [Debugging and common issues](/rn-codepush/debugging-and-common-issues/). For commands only, see [CLI quick reference](/rn-codepush/cli-quick-reference/). ================================================================================ source: https://docs.codemagic.io/yaml-code-signing/signing-android/ title: Signing Android apps description: How to set up Android code signing in codemagic.yaml last_modified: 2026-08-26 ================================================================================ # Signing Android apps > How to set up Android code signing in codemagic.yaml All Android applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. > > **Note:** This guide covers Android code signing using Codemagic's **Code Signing Identities** — uploading keystore files to the Codemagic UI once and reference them in `codemagic.yaml`. > > If you prefer to use CLI tools in your build scripts to manage code signing resources, see [Alternative code signing methods](../yaml-code-signing/alternative-code-signing-methods). >
{{< youtube wPpGTY6Sis0 >}} ## Managing and uploading files Team admin permissions are required to upload and edit files under the **Code signing identities** section. However, all team members can view the file info for any of the uploaded files. ### Generating a keystore If you need to create a new keystore file for signing your release builds, you can do so with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. ### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystore, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > ## Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. #### Fetching a single keystore file Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` #### Fetching multiple keystore files When fetching multiple keystores during a build, it is necessary to explicitly set names for environment variables that will point to the file paths on the build machine. ```yaml environment: android_signing: - keystore: keystore_reference_1 keystore_environment_variable: THIS_KEYSTORE_PATH_ON_DISK_1 keystore_password_environment_variable: THIS_KEYSTORE_PASSWORD_1 key_alias_environment_variable: THIS_KEY_ALIAS_1 key_password_environment_variable: THIS_KEY_PASSWORD_1 - keystore: keystore_reference_2 keystore_environment_variable: THIS_KEYSTORE_PATH_ON_DISK_2 keystore_password_environment_variable: THIS_KEYSTORE_PASSWORD_2 key_alias_environment_variable: THIS_KEY_ALIAS_2 key_password_environment_variable: THIS_KEY_PASSWORD_2 ``` ## Signing Android apps using Gradle To sign your Android app, simply modify your **`android/app/build.gradle`** as follows: ```Groovy ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` ## Signing Android apps using user-specified keys After modifying the `build.gradle` file, you can use a script to re-create a keystore file on the build machine and use default signing method via `key.properties` file: ```kotlin scripts: # ... - name: Set up key.properties script: | cat >> "$CM_BUILD_DIR/project_directory/android/key.properties" < How to sign up for Codemagic You can sign up for Codemagic using a [GitHub](https://github.com/), [Bitbucket](https://bitbucket.org/) or [GitLab](https://about.gitlab.com/) account, or by using your email address. SSO integrations for enterprises are available on request. After signing up, you can easily add repositories from the above Git providers or any self-hosted or cloud-based Git repository. ## Sign up via GitHub, Bitbucket or GitLab When signing up via GitHub, you will be asked to authorize Codemagic to authenticate yourself without giving any access to your repositories. To add apps from GitHub, you also need to install the Codemagic CI/CD GitHub App, read more about it [here](../getting-started/github). When authenticating using a Bitbucket or GitLab account via OAuth, Codemagic asks for access to your account and repositories so they can be listed when you're adding applications. You will need to authorize Codemagic to connect the Bitbucket/GitLab account to your Codemagic account. ## Sign up via email Enter your email address and name and click **Create your account** to get started. Codemagic will then send a six-character authentication key to the provided email address. Enter the authentication key and click **Continue** to verify the email address and finish signup. Note that an unused key expires in **10 minutes**. You will be sent a new authentication key every time you need to log in again. ## Codemagic Authentication Overview When using email authentication, Codemagic uses an additional verification factor requiring a One Time Password to be sent to the user's email address. It's also possible to enable multi-factor authentication (MFA) on the OAuth provider side. For example, one can enable MFA on GitHub and sign up via Github on Codemagic. Enterprise users can use SSO for enhanced authentication control, limiting access based on geolocation, device, and time range. ## Connecting several repository integrations You can connect several repository accounts (GitHub, GitLab, Bitbucket) with one Codemagic account or Codemagic team (read more about managing team integrations [here](../getting-started/teams/#managing-team-integrations)). 1. Log in to Codemagic with the account you signed up with. 2. Make sure that you have **Personal account** selected from the left navigation bar team selection, then click **Settings**. 3. In the **Integrations** section, click **Connect** next to the account you would like to connect to Codemagic. Once you have connected another account to your Codemagic account, you can log in to Codemagic with either of these accounts. Email notifications with build status reports will be sent to the email address that's connected with the repository from which you build. ================================================================================ source: https://docs.codemagic.io/flutter-testing/testing-widgets/ title: Testing widgets description: How to configure running only widget tests last_modified: 2022-05-19 ================================================================================ # Testing widgets > How to configure running only widget tests Instead of building the entire app, you can separately run tests on your widgets. To test widgets, the following is required: - A Flutter project without `ios` and `android` folders. - A `test` folder containing at least one test. Your widget repository is detected automatically like any other repository, but there are differences in the build process. Technically, Codemagic will only fetch the sources, install the dependencies and run the tests. If there are failing tests, you will receive the test report in your email. After the first build, you can change the Flutter version and configure email publishing and Slack for receiving status reports. ================================================================================ source: https://docs.codemagic.io/yaml-basic-configuration/using-environment-variables/ title: Using environment variables with codemagic.yaml description: How to use environment variables in scripts in codemagic.yaml last_modified: 2024-08-27 ================================================================================ # Using environment variables with codemagic.yaml > How to use environment variables in scripts in codemagic.yaml To access a variable during build time, add the `$` symbol in front of its name. For example, you can access the value of `API_TOKEN` variable by referencing it as `$API_TOKEN`. > > **Note:** It is required to use quotation marks with multi-line variables when you are referencing them in custom scripts. > ## Setting environment variables at build time and accessing them across shell scripts By default, if you define an environment variable inside your script, you can only use it within that particular script itself. However, you can make an environment variable available to any subsequent step of your workflow by writing it to the `CM_ENV` environment file. Specifically, you can do this by writing a `"KEY=value"` pair to the `CM_ENV` environment file. `CM_ENV` can contain multiple environment variables separated by newlines. The following commands show how to write variables to the `CM_ENV` file, depending on the `instance type` of the build machine you are using: ### Option: macOS ```yaml scripts: - name: Save variable to ENV file script: | echo "KEY=value" >> $CM_ENV ``` You can then reference the variable in subsequent parts of your workflow by using `$KEY`. ### Option: Linux ```yaml scripts: - name: Save variable to ENV file script: | echo "KEY=value" >> $CM_ENV ``` You can then reference the variable in subsequent parts of your workflow by using `$KEY`. ### Option: Windows ```yaml scripts: - name: Save variable to ENV file script: | Add-Content -Path $env:CM_ENV -Value "KEY=value" ``` You can then reference the variable in subsequent parts of your workflow by using `$env:KEY`. #### Setting a multiline environment variable To add a multiline environment variable, you need to use `<<` instead of an `=` to mark the end of the key in the key-value pair. In addition, set a delimiter to mark the start and the end of the variable. In the following example, the `DELIMITER` keyword can be replaced by any word of your choice, however, make sure that the delimiter at the beginning and at the end match. ```yaml scripts: - name: Save variable to ENV file script: | echo 'MULTILINE_VAR<> $CM_ENV echo 'line_one\nline_two' >> $CM_ENV echo 'DELIMITER' >> $CM_ENV ``` Note that the example is specific to Linux and macOS machines but the same principles apply when building on Windows. ## Accessing environment variables from apps Environment variables can also be accessed from within your apps. One of the great advantages is that you are able to use sensitive data such as API keys without having to store them in your repository. The following examples show how to place your Google Maps API key into an Android or iOS application from an environment variable. ### Option: Android 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. Reference the environment variable in the `build.gradle` ```Groovy defaultConfig { // Other values set here resValue "string", "maps_api_key", "$System.env.MAPS_API_KEY" } ``` 3. Reference the value from `build.gradle` in the `AndroidManifest.xml` ```xml ``` ### Option: Flutter 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. In the build step, add `--dart-define` to your build script ```yaml scripts: - name: Flutter build ipa script: | flutter build ipa --release \ --dart-define=MAPS_API_KEY=$MAPS_API_KEY ``` 3. Within your Flutter Application, use `String.fromEnvironment` to retrieve these variables in your Dart Code. ```Dart void main() { final secret = String.fromEnvironment('MAPS_API_KEY'); print(secret); } ``` ### Option: iOS (Swift) 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. Reference the environment variable in the `Info.plist` ```xml MAPS_API_KEY $(MAPS_API_KEY) ``` 3. Reference the value from `Info.plist` in the `AppDelegate.swift` ```Swift GMSServices.provideAPIKey(Bundle.main.object(forInfoDictionaryKey: "MAPS_API_KEY") as? String ?? "") ``` ### Option: iOS (Objective-C) 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. Reference the environment variable in the `AppDelegate.m` as in the following [example](https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m). ```Objective-C [GMSServices provideAPIKey:[[NSProcessInfo processInfo] environment][@"MAPS_API_KEY"]]; ``` ================================================================================ source: https://docs.codemagic.io/flutter-running-builds/webhooks/ title: Webhooks configuration with Flutter workflow editor description: Set up webhooks for automatic builds using Flutter workflow editor last_modified: 2022-11-03 ================================================================================ # Webhooks configuration with Flutter workflow editor > Set up webhooks for automatic builds using Flutter workflow editor Webhooks are necessary in order to be able to trigger builds automatically in response to events in the repository. The payload URL has the following format: `https://api.codemagic.io/hooks/`. You can find your app ID in the browser URL after `app/` when you open the app on Codemagic: `https://codemagic.io/app/` All received webhooks are visible in the Codemagic UI when navigating to your application and selecting the **Webhooks** tab. After configuring **Webhooks**, automatic build triggering can be set up as explained [here](https://docs.codemagic.io/flutter-configuration/automatic-build-triggering/). More information about how to set up automatic build triggering in the **yaml** file can be found [here](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering). ## Setting up webhooks for Github Open your project and navigate to **Settings** > **Webhooks** > **Add webhook**, paste the **payload URL** from above (both `application/json` or `application/x-www-form-urlencoded` are supported as the **Content type**), and select the following events: **Branch or tag creation**, **Pull requests**, **Pushes**. ## Setting up webhooks for GitLab Navigate to **Settings** > **Webhooks**, paste the **payload URL** and check the following boxes in the **Trigger** section: **Push events**, **Tag push events**, **Merge request events**. Also, be sure to enable **SSL verification**. ## Setting up webhooks for Bitbucket Open your application repository, go to **Settings** > **Webhooks** (in **Workflow** section) > **Add webhook**, then enter an arbitrary title for the webhook and paste the **payload URL** in the **URL** field. For **Triggers**, select **Choose from a full list of triggers** and select the following events: **Push** in the **Repository** section and **Created**, **Updated**, **Merged** in the **Pull Request** section. ## Setting up webhooks for AWS CodeCommit To start using webhooks with **AWS CodeCommit**, it is first necessary to create a subscription with the **AWS Simple Notification Service**. ### Configuring the subscription 1. Open up **AWS Simple Notification Service** in the **AWS Console**. 2. Navigate to **Topics** > **Create topic**. 3. Set the type to **Standard**, give the topic a name and click on **Create topic**. 4. Navigate to **Subscriptions** > **Create subscription**. 5. Select the previously configured topic, set the protocol to `HTTPS`, and set the Codemagic **payload URL** as the endpoint. 6. Confirm that **Enable raw message delivery** is unticked. 7. Proceed by clicking **Create subscription**. 8. In the Codemagic UI, navigate to your application and select the **Webhooks** tab. 9. Under **Recent deliveries**, choose the most recent webhook, and copy the subscription link under the **Results** tab to your browser. ### Configuring webhook events Open your application repository and navigate to **Notify** > **Create notification rule** and enter a name for your Notification rule. Under **Events that trigger notifications**, select the **Source updated** and **Created** events in the **Pull request** section and the **Created** and **Updated** events in the **Branches and tags** section. Set the target type to **SNS topic**, select a configured target and click on **Submit**. If, after triggering a build, the SNS Notification target status shows as **Unreachable**, navigate to the topic settings and modify the access policy to match the following structure: ```json { "Version": "2008-10-17", "Statement": [ { "Sid": "CodeNotification_publish", "Effect": "Allow", "Principal": { "Service": "codestar-notifications.amazonaws.com" }, "Action": "SNS:Publish", "Resource": "arn:aws:sns:REGION:ACCOUNT_ID:REPOSITORY" } ] } ``` The **Resource** field should match the ARN of the topic. ## Setting up webhooks for Azure DevOps Open your application repository, go to **Project Settings** > **Service Hooks**, click on **Create a new subscription...** and select **Web Hooks**. Under **Trigger on this type of event**, choose the event you wish to trigger builds for. Codemagic supports **Code pushed**, **Pull request created**, and **Pull request updated** events. In Azure, each of the events requires its own webhook. Once the event has been selected, choose your repository under filters and configure any additional settings. ================================================================================ source: https://docs.codemagic.io/yaml-running-builds/webhooks/ title: Webhooks configuration with codemagic.yaml description: Set up webhooks for automatic builds last_modified: 2022-11-03 ================================================================================ # Webhooks configuration with codemagic.yaml > Set up webhooks for automatic builds Webhooks are necessary in order to be able to trigger builds automatically in response to events in the repository. The payload URL has the following format: `https://api.codemagic.io/hooks/`. You can find your app ID in the browser URL after `app/` when you open the app on Codemagic: `https://codemagic.io/app/` All received webhooks are visible in the Codemagic UI when navigating to your application and selecting the **Webhooks** tab. After configuring **Webhooks**, automatic build triggering can be set up as explained [here](https://docs.codemagic.io/flutter-configuration/automatic-build-triggering/). More information about how to set up automatic build triggering in the **yaml** file can be found [here](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering). ## Setting up webhooks for Github Open your project and navigate to **Settings** > **Webhooks** > **Add webhook**, paste the **payload URL** from above (both `application/json` or `application/x-www-form-urlencoded` are supported as the **Content type**), and select the following events: **Branch or tag creation**, **Pull requests**, **Pushes**. ## Setting up webhooks for GitLab Navigate to **Settings** > **Webhooks**, paste the **payload URL** and check the following boxes in the **Trigger** section: **Push events**, **Tag push events**, **Merge request events**. Also, be sure to enable **SSL verification**. ## Setting up webhooks for Bitbucket Open your application repository, go to **Settings** > **Webhooks** (in **Workflow** section) > **Add webhook**, then enter an arbitrary title for the webhook and paste the **payload URL** in the **URL** field. For **Triggers**, select **Choose from a full list of triggers** and select the following events: **Push** in the **Repository** section and **Created**, **Updated**, **Merged** in the **Pull Request** section. ## Setting up webhooks for AWS CodeCommit To start using webhooks with **AWS CodeCommit**, it is first necessary to create a subscription with the **AWS Simple Notification Service**. ### Configuring the subscription 1. Open up **AWS Simple Notification Service** in the **AWS Console**. 2. Navigate to **Topics** > **Create topic**. 3. Set the type to **Standard**, give the topic a name and click on **Create topic**. 4. Navigate to **Subscriptions** > **Create subscription**. 5. Select the previously configured topic, set the protocol to `HTTPS`, and set the Codemagic **payload URL** as the endpoint. 6. Confirm that **Enable raw message delivery** is unticked. 7. Proceed by clicking **Create subscription**. 8. In the Codemagic UI, navigate to your application and select the **Webhooks** tab. 9. Under **Recent deliveries**, choose the most recent webhook, and copy the subscription link under the **Results** tab to your browser. ### Configuring webhook events Open your application repository and navigate to **Notify** > **Create notification rule** and enter a name for your Notification rule. Under **Events that trigger notifications**, select the **Source updated** and **Created** events in the **Pull request** section and the **Created** and **Updated** events in the **Branches and tags** section. Set the target type to **SNS topic**, select a configured target and click on **Submit**. If, after triggering a build, the SNS Notification target status shows as **Unreachable**, navigate to the topic settings and modify the access policy to match the following structure: ```json { "Version": "2008-10-17", "Statement": [ { "Sid": "CodeNotification_publish", "Effect": "Allow", "Principal": { "Service": "codestar-notifications.amazonaws.com" }, "Action": "SNS:Publish", "Resource": "arn:aws:sns:REGION:ACCOUNT_ID:REPOSITORY" } ] } ``` The **Resource** field should match the ARN of the topic. ## Setting up webhooks for Azure DevOps Open your application repository, go to **Project Settings** > **Service Hooks**, click on **Create a new subscription...** and select **Web Hooks**. Under **Trigger on this type of event**, choose the event you wish to trigger builds for. Codemagic supports **Code pushed**, **Pull request created**, and **Pull request updated** events. In Azure, each of the events requires its own webhook. Once the event has been selected, choose your repository under filters and configure any additional settings. ================================================================================ source: https://docs.codemagic.io/knowledge-white-label/white-label-branching-strategies/ title: White label branching and workflow strategies description: White label branching and workflow strategies last_modified: 2026-06-26 ================================================================================ # White label branching and workflow strategies > White label branching and workflow strategies There are many different ways you can set up your branching strategy and workflows for white labeling apps. What follows is a recommendation for getting started which you can use as the basis of your own strategy. ## Dev branch and workflow This "dev" branch is for developing and fixing the core version of the app. The app is built using the default “dev” icons, colors, fonts, bundle id etc. and no white label automation scripts are run to change this app. When new code is committed to this branch, it triggers a "dev-release" workflow that runs unit or integration tests. If the tests pass, the core app is built and developers can download it directly from the Codemagic build page or shared dashboard, via email or Slack notifications, Testflight, Google Play, or other distribution channels. If any of the integration or unit tests fail, the developers should review the code, fix any issues and commit new code to trigger a new build. {{< mermaid >}} flowchart TD %% Colors %% classDef red fill:#ed2633,stroke:#FFF,stroke-width:1px,color:#fff BRANCH(DEV Branch) ---> COMMIT(Commit code) ---> TRIGGER(Trigger build) ---> ANALYSIS(Code analysis) ANALYSIS ---> UNIT(Unit or E2E tests) UNIT ---- PASS(Pass) UNIT ---- FAIL(Fail):::red FAIL --> REVIEW(Review) ---> BRANCH PASS --> BUILD BUILD(Build core app) ---> DISTRIBUTE(Distribute Dev build) ---- CM_BUILD(Codemagic build page/dashboard) & CM_NOTIFICATION(Slack/Email notification) & OTHER(TestFlight/Google Play/Other) {{< /mermaid >}} ## QA branch and workflow If you are happy with the build from the "dev" branch, you can now proceed to raise a PR request to merge this into the "QA" branch. This triggers a "qa-release" workflow that runs the white label automation scripts to change the icons, images, fonts, etc. to something other than the default dev version of the app. The resulting build can be distributed directly to your QA testers. {{< mermaid >}} flowchart TD %% Colors %% classDef red fill:#ed2633,stroke:#000,stroke-width:2px,color:#fff DEV(Dev Branch) ---> PR(Pull Request) ---> BRANCH(QA Branch) BRANCH ---> TRIGGER(Trigger workflow) TRIGGER ---> ANALYSIS(Code analysis) ANALYSIS ---> UNIT(Unit or E2E tests) UNIT ---- PASS(Pass) UNIT ---- FAIL(Fail):::red FAIL --> REVIEW(Review) ---> DEV PASS --> ASSETS(Get assets & config) ---> SCRIPTS(Run white label scripts) ---> BUILD(Build QA app) BUILD ---> DISTRIBUTE(Distribute QA build) ---- TESTFLIGHT(TestFlight) & GOOGLE(Google Play) & FAD(Firebase app distribution) & OTHER(Other) {{< /mermaid >}} ## Trigger branch and workflow The "trigger" branch and workflow serve one purpose; to trigger the builds for each client version. When a pull request is merged into this branch from the "QA" branch it will trigger a "trigger" workflow which is configured to trigger all your client builds using the Codemagic REST API. {{< mermaid >}} flowchart TD QA(QA Branch) ---> PR(PR merge into Trigger branch) PR ---> API(REST API call) API ---> BUILD(Trigger client builds) ---- C1(Client '001') & C2(Client '002') & C3(Client '003') {{< /mermaid >}} ## Client build triggered by Codemagic REST API Each client version build is triggered by the Codemagic REST API. The payload of the API request contains the client version to build and the workflow downloads the required assets and configuration for that version. This means that a **single workflow** is required to build multiple client versions. The workflow runs the white label automation scripts, builds the app, and automatically distributes the app to the channel of your choice. {{< mermaid >}} flowchart TD C1(Build Client 001) ---> ASSETS(Get assets & config) ---> SCRIPTS(Run white label scripts) SCRIPTS ---> BUILD(Build app) BUILD ---> DISTRIBUTE(Distribute build) ---- TESTFLIGHT(TestFlight) & GOOGLE(Google Play) & OTHER(Other) {{< /mermaid >}} Check out the final white-label sample project that shows these strategies [here](https://github.com/codemagic-ci-cd/white-label-demo-project/tree/strategies). ================================================================================ source: https://docs.codemagic.io/getting-started/adding-apps/ title: Adding apps to Codemagic description: How to add an app to Codemagic last_modified: 2023-05-25 ================================================================================ # Adding apps to Codemagic > How to add an app to Codemagic ## Connecting a Git repository Adding applications to Codemagic is a simple and straightforward process of connecting your Git repository and selecting the repository root for the application. ### Option: GitHub For the best integration with the Git provider, it’s recommended to connect your GitHub repositories using the repository integration built in to Codemagic. Adding apps from GitHub requires authorizing Codemagic and installing the Codemagic CI/CD GitHub App to a GitHub account or an organization to be able to load the repositories. 1. Click **Add application** in the top right corner of the Applications page. 2. You can only add an application to a team with billing enabled where you have the **Admin role**. If you don’t have the Admin role in any teams, this step is skipped and the application will be added to your personal account. 3. Select **GitHub** as the Git provider. If you have already set up the integration, click **Next: Select repository** and skip to step 4. If the GitHub integration has not been set up, you'll see **Next: Authorize integration** instead. A new window appears for you to authorize Codemagic. Confirm the authorization by clicking **Authorize Codemagic CI/CD**. 4. In the next step, click **Install GitHub App** to set up the integration. A GitHub page opens in a new window. Select the account or an organization where to install the app and choose whether to give Codemagic access to all the repositories from this account or only selected ones. Finish the installation by clicking **Install & Authorize**. 5. Finally, set up the application by selecting the repository from the dropdown menu and specifying the project type. Click **Finish: Add application**. You will be then redirected to the app settings. >See the getting started guides and [sample projects](../sample-projects/codemagic-sample-projects/) configured with [codemagic.yaml](../getting-started/yaml/) to set up your project. Alternatively, Flutter apps can be also configured using the [Flutter workflow editor](../flutter-configuration/flutter-projects/). ## Configuring the GitHub App integration Codemagic uses the [Codemagic CI/CD GitHub App](https://github.com/apps/codemagic-ci-cd) to integrate with GitHub. To share your GitHub repositories with Codemagic, Codemagic GitHub App will have to be installed on the account or organization in GitHub from which you would like to build applications. > > **Note:** The GitHub App integration can be connected separately for your personal account and each team. The integrations configured for your personal account apply to the apps that are not part of a team in Codemagic. While teams inherit the integrations from the team admin's personal account, it is highly recommended to set up repository integrations separately in team settings. >

> > **Note:** If a repository is transferred to an organization, then the organization should be configured with [Codemagic CI/CD GitHub App](https://github.com/apps/codemagic-ci-cd) in order to show the repository in the dropdown. > 1. In your user or team settings in Codemagic, navigate to the Integrations section and locate the GitHub App integration. The next steps may vary slightly depending on whether you have already authorized Codemagic or have the Codemagic GitHub App installed. 2. Click **Connect** next to the GitHub App integration, and when redirected to GitHub, click **Authorize Codemagic**. 3. Back in the Integrations section, click **Finish installation** and then **Install app**. Note that at this stage you can also revoke your authorization of the app by clicking **Disconnect**. 4. A popup window opens for you to select the organization or account where to install the app. Pick the installation location. You can later install the app to additional accounts. 5. Then choose whether to share **All repositories** from the account or select the repositories to share by choosing **Select repositories only**. 6. Click **Install & Authorize** to finish installation (you may be asked to confirm that action by entering your password). If you do not have permission to install the app under an organization, you will see the button **Authorize & Request** instead. An approval from the organization owner or app manager is needed to authorize the installation. ## Managing connected GitHub accounts and organizations In the Integrations section in your user or team settings, click **Manage integration > Configure**. You can then select an account to configure or install Codemagic GitHub App to additional accounts. The accounts that already have Codemagic GitHub App installed are marked with "Configure". ![Integrations > GitHub App > Manage integration > Configure](../uploads/gh-app-conf.png) You can also access the same settings in GitHub by going directly to [https://github.com/apps/codemagic-ci-cd](https://github.com/apps/codemagic-ci-cd) and clicking **Configure**. These settings allow you to revisit your repository access configuration should you want to share access to additional repositories or revoke access to a previously shared repository. In addition, you can disconnect an account by clicking **Uninstall** in the danger zone. If you revoke access to previously shared repositories, you will still see all your apps and build history but won't be able to build the apps to which Codemagic no longer has access. Such apps will be grayed out and will show up on the Applications page with the **Removed from repository** filter. ## Disconnecting Codemagic GitHub App integration Disabling the GitHub App integration deletes the GitHub access token stored by Codemagic, revoking access to the connected GitHub account. **Personal account**: Expand the **Integrations** section in your personal account settings and click **Manage integration** > **Disconnect** next to GitHub. **Team**: Expand the **Team integrations** section in your team settings and click **Manage integration** > **Disconnect** next to GitHub. To completely remove the integration, **uninstall** the Codemagic CI/CD app and revoke the authorization in GitHub. Visit [https://github.com/settings/installations](https://github.com/settings/installations) for personal accounts or github.com/organizations/your-organization/settings/installations for organization accounts to check whether Codemagic CI/CD is listed both under installed and authorized GitHub Apps. ## Repository is unavailable Here are some tips on what to check if you can't see your repository listed in Codemagic or it's shown as unavailable. * If you chose to grant access to **select repositories only** as opposed to all repositories when setting up the GitHub App, make sure you have also granted access to the repository in question. Click **Manage integration > Configure** in team or user integrations to configure repository access settings. * Your personal Codemagic account and each team have separate integrations. Make sure you have connected the GitHub App integration to the right team. * If you build apps from different GitHub accounts or organizations, make sure that you have installed the GitHub App on the account that has the repository available. Click **Manage integration > Configure** to see which accounts have been connected. You can also visit [https://github.com/settings/installations](https://github.com/settings/installations) for personal accounts or github(dot)com/organizations/your-organization/settings/installations for organization accounts to check whether Codemagic CI/CD is listed both under installed and authorized GitHub Apps. * Private GitHub repositories can be shared with Codemagic only when the GitHub App is installed on the account that owns the repository. If you are a collaborator to a private repository, please ask the repository owner to install Codemagic GitHub App in GitHub: [https://github.com/apps/codemagic-ci-cd](https://github.com/apps/codemagic-ci-cd) ### Option: GitLab For the best integration with the Git provider, it’s recommended to connect your GitLab repositories using the repository integration built in to Codemagic. Adding apps from GitLab requires granting access to your GitLab account to enable the integration and load repositories. 1. Click **Add application** in the top right corner of the Applications page. 2. You can only add an application to a team with billing enabled where you have the **Admin role**. If you don’t have the Admin role in any teams, this step is skipped and the application will be added to your personal account. 3. Select **GitLab** as the Git provider and click **Next: Authorize integration**. A new window appears for you to authorize Codemagic. Confirm the authorization by clicking **Authorize**. If you have already authorized GitLab, click **Next: Select repository** instead. 4. Set up the application by selecting the repository from the dropdown menu and specifying the project type. Click **Finish: Add application**. You will be then redirected to the app settings. >See the getting started guides and [sample projects](../sample-projects/codemagic-sample-projects/) configured with [codemagic.yaml](../getting-started/yaml/) to set up your project. Alternatively, Flutter apps can be also configured using the [Flutter workflow editor](../flutter-configuration/flutter-projects/). %!s() ### Option: Bitbucket For the best integration with the Git provider, it’s recommended to connect your Bitbucket repositories using the repository integration built in to Codemagic. Adding apps from Bitbucket requires granting access to your Bitbucket account to enable the integration and load repositories. 1. Click **Add application** in the top right corner of the Applications page. 2. You can only add an application to a team with billing enabled where you have the **Admin role**. If you don’t have the Admin role in any teams, this step is skipped and the application will be added to your personal account. 3. Select **Bitbucket** as the Git provider and click **Next: Authorize integration**. A new window appears for you to authorize Codemagic. Confirm the authorization by clicking **Grant access**. If you have already authorized Bitbucket, click **Next: Select repository** instead. 4. Set up the application by selecting the repository from the dropdown menu and specifying the project type. Click **Finish: Add application**. You will be then redirected to the app settings. >See the getting started guides and [sample projects](../sample-projects/codemagic-sample-projects/) configured with [codemagic.yaml](../getting-started/yaml/) to set up your project. Alternatively, Flutter apps can be also configured using the [Flutter workflow editor](../flutter-configuration/flutter-projects/). %!s() ### Option: Others Apps that cannot be added via a repository integration can be cloned from a URL. Authentication for private repositories can be set up via HTTPS or SSH. ## Connecting repository via SSH 1. Click **Add application** in the top right corner of the Applications page. 2. You can only add an application to a team with billing enabled where you have the **Admin role**. If you don’t have the Admin role in any teams, this step is skipped and the application will be added to your personal account. 3. Select **Other** and click **Next: Select repository**. 4. Enter the **Repository URL** for **cloning** the repository. You can find the URL from your repository by clicking **Clone** / **Clone or download**. Usually, the URL is in this format: `git@example.com:username/repo.git`. 5. Upload the **SSH private key** file. If your key is password-protected, enter the **Private key passphrase**. **Alternatively**, you can click **Generate key pair** and have Codemagic create an SSH key pair for you, read more about it [below](#generating-a-key-pair-in-codemagic). 6. Finish setting up the application by selecting the project type and clicking **Finish: Add application**. You will be then redirected to the app settings. >See the getting started guides and [sample projects](../sample-projects/codemagic-sample-projects/) configured with [codemagic.yaml](../getting-started/yaml/) to set up your project. Alternatively, Flutter apps can be also configured using the [Flutter workflow editor](../flutter-configuration/flutter-projects/). ### Generating a key pair in Codemagic On clicking **Generate key pair**, Codemagic creates a secure 4096 bit SSH key pair. The private key will be used in Codemagic and the public key must be added to your repository settings. Click **Copy to clipboard** to copy the public key. - If your repository is hosted on [GitHub](https://developer.github.com/v3/guides/managing-deploy-keys/#setup-2), [GitLab](https://www.deployhq.com/support/projects/updating-your-project-repository/uploading-your-public-key-to-gitlab-manually) or [Bitbucket](https://confluence.atlassian.com/bitbucket/use-access-keys-294486051.html), add the public key to your repository's access/deployment keys. - For self-hosted repositories, request your git server admins to allow access to the provided public key. After you have added the public key to your repository settings, finish adding the app by clicking **Finish: Add application**. > **Note:** Don't close the module before you have finished adding the app, otherwise, you'll need to start over and generate a new SSH key. ## Connecting repository via HTTP/HTTPS 1. Click **Add application** in the top right corner of the Applications page. 2. Select **Other** and click **Next: Select repository**. 3. Enter the **Repository URL** for **cloning** the repository. You can find the URL from your repository by clicking **Clone** / **Clone or download**. Usually, the URL is in this format: `https://example.com/path/to/repository.git`. 4. If the repository is private, then enter your **Username** and **Password**, or **Username** and [**Personal access token**](https://docs.github.com/en/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token) if it's a GitHub repository. In the case of a public repository, select **Public repository**. 5. Finish setting up the application by selecting the project type and clicking **Finish: Add application**. You will be then redirected to the app settings. >See the getting started guides and [sample projects](../sample-projects/codemagic-sample-projects/) configured with [codemagic.yaml](../getting-started/yaml/) to set up your project. Alternatively, Flutter apps can be also configured using the [Flutter workflow editor](../flutter-configuration/flutter-projects/). ## Modifying access Navigate to **App settings > Repository settings** to update repository access settings, change the app name or icon in Codemagic, archive or delete the app. Note that if the app is part of a team, only team admins can update repository access settings or delete the app. ## Updating access to the repository If Codemagic no longer has access to your repository, you may need to update your repository access settings. This can happen for several reasons, for example: * the repository has been renamed * the repository has been moved to a different organization or Git provider * the username and password used to authenticate have changed * you want to update your SSH key after rotation To update repository access settings, navigate to **App settings > Repository settings > Repository URL** and click **Change repository**. This opens a modal for reconfiguring the repository. Select a suitable authentication method and follow the steps to set up access to the repository. To confirm the changes and exit the flow, click **Confirm changes** in the modal. Before saving the changes, Codemagic will verify that it has access to the repository. ## Firewall configuration for privately hosted repositories If your repositories are within an internal network / behind a firewall, which is usually the case with enterprises, the network configuration of these repositories must be configured for external access. Codemagic requires direct access to the repositories for the following use cases: - For retrieving the repository information such as the branches and the commits. - For cloning the repository to the build machine during the build. The following IP addresses must be allowed through the firewall (whitelisted):

    Fetching IP addresses...
  
Since Codemagic needs to access the Git service, please allow ports that your service uses - usually the default SSH or HTTPS ports. ## Configuring Monorepo repositories A **Monorepo** is a version-controlled code repository that holds many projects in a single repository. Codemagic supports working with monorepo apps. The very first step is creating a Codemagic account and adding your monorepo app from its codebase such as GitHub, Gitlab, Bitbucket, or self-hosted repositories. More information about how to sign up can be found here. To begin with, **codemagic.yaml** file must be created in the root directory of the repository. By default, the working directory is the root of the repository. The basic structure looks like this: ```yaml workflows: default-workflow: name: Default workflow instance_type: mac_mini_m2 max_build_duration: 60 environment: flutter: stable xcode: latest cocoapods: default scripts: # Add scripts here artifacts: - build/**/outputs/**/*.apk - build/ios/ipa/*.ipa publishing: email: recipients: - name@example.com ``` In order to target apps inside your monorepo app, **working_directory** key is used. For example, the following sample snippet shows how it works: ```yaml workflows: default-workflow: name: Default workflow # Specify path to the app folder like this working_directory: my_first_app ``` By defining **working_directory**, every command that is defined in the scripts section will run inside that particular directory which is "my_first_app" in our sample above. In order to manage your working directories easily, it is recommended to create multiple workflows and configure them accordingly: ```yaml workflows: my-first-app-workflow: name: Drivers app workflow working_directory: my_first_app # ... my-second-app-workflow: name: Passengers app workflow working_directory: my_second_app ``` A sample project can be found [here](https://github.com/codemagic-ci-cd/codemagic-sample-projects/blob/main/codemagic.yaml). You can also checkout the blog article [How to manage your Flutter monorepo](https://blog.codemagic.io/flutter-monorepos/). %!s() ================================================================================ source: https://docs.codemagic.io/flutter-configuration/env-variables/ title: Adding environment variables in Flutter workflow editor description: How to add environment variables in the Flutter workflow editor last_modified: 2025-05-27 ================================================================================ # Adding environment variables in Flutter workflow editor > How to add environment variables in the Flutter workflow editor Environment variables are useful for making available for Codemagic the credentials, configuration files or API keys that are required for successful building or integration with external services. For more information about the use of environment variables and a list of Codemagic read-only environment variables, refer [here](../yaml-basic-configuration/environment-variables). ## Adding environment variables You can add environment variables to your Flutter projects in **App settings > Environment variables**. 1. Enter the name and the value of the variable. 2. Check **Secret** if you wish to hide the value both in the UI and in build logs and disable editing of the variable. Such variables can be accessed only by the build machines during the build. 3. Click **Add**. ## Storing binary files In order to store **_binary files_** as environment variables, they first need to be **_base64 encoded_** locally. To use the files, you will have to decode them during the build. Commonly used binary files that need to be base64 encoded include: - Android keystore (.jks or .keystore) - Provisioning profiles when manual code signing (.mobileprovision) - iOS distribution certificate (.p12) when manual code signing. The following examples show how to save a file named `codemagic.keystore` depending on your OS: ### Option: Linux For Linux machines, we recommend installing xclip: ```Shell sudo apt-get install xclip cat codemagic.keystore | base64 | xclip -selection clipboard ``` Alternatively, you can run the following command and carefully copy/paste the output: ```Shell openssl base64 -in codemagic.keystore ``` > > **Tip**: When copying file contents always include any tags. e.g. Don't forget to copy `-----BEGIN PRIVATE KEY-----` and `-----END PRIVATE KEY-----` too. > ### Option: macOS On macOS, running the following command base64 encodes the file and copies the result to the clipboard: ```Shell cat codemagic.keystore | base64 | pbcopy ``` ### Option: Windows For Windows, the PowerShell command to base64 encode a file and copy it to the clipboard is: ```powershell [Convert]::ToBase64String([IO.File]::ReadAllBytes("codemagic.keystore")) | Set-Clipboard ``` After running these command lines, you can paste the automatically copied string into the Variable value field in Codemagic UI. > > **Tip**: A convenient way to check if a file is binary is to try to peek into the file using `less filename.extension`. If it is binary, you'll be asked "**_filename maybe is a binary file. See it anyway?_**" > #### Using binary files In order to use binary files during the build time, you need to `base64` decode them and generate the file again. This can be performed with a simple `echo` command in a script. ```bash echo $YOUR_ENVIRONMENT_VARIABLE | base64 --decode > /path/to/decode/to/codemagic.keystore ``` ## Commonly used variable examples #### Android builds The following variable groups and variables are commonly used in Android builds. **Variable name** | **Variable value** | **Group** --- | --- | --- CM_KEYSTORE_PATH | /tmp/keystore.keystore | keystore_credentials CM_KEYSTORE | contents of keystore - [`base64 encoded`](#storing-binary-files) | keystore_credentials CM_KEYSTORE_PASSWORD | Put your keystore password here | keystore_credentials CM_KEY_PASSWORD | Put your key alias password here | keystore_credentials CM_KEY_ALIAS | Put your key alias here | keystore_credentials GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS | Put your Google Play service account credentials here | google_play_credentials GOOGLE_PLAY_TRACK | Any default or custom track that is not in ‘draft’ status | google_play_credentials PACKAGE_NAME | Put your package name here | other #### iOS builds The following variable groups and variables are commonly used in iOS builds. **Variable name** | **Variable value** | **Group** --- | --- | --- APP_STORE_CONNECT_ISSUER_ID | Put your App Store Connect Issuer Id here | appstore_credentials APP_STORE_CONNECT_KEY_IDENTIFIER | Put your App Store Connect Key Identifier here | appstore_credentials APP_STORE_CONNECT_PRIVATE_KEY | Put your App Store Connect Private Key here | appstore_credentials CERTIFICATE_PRIVATE_KEY | Put your Certificate Private Key here | appstore_credentials BUNDLE_ID | Put your bundle id here | ios_config APP_STORE_ID | Put your TestFlight Apple id number (General > App Information > Apple ID) | ios_config XCODE_WORKSPACE | Put the name of your workspace here | ios_config XCODE_SCHEME | Put the name of your scheme here | ios_config ================================================================================ source: https://docs.codemagic.io/yaml-code-signing/alternative-code-signing-methods/ title: Alternative code signing methods description: How to set up code signing without using code signing identities last_modified: 2026-08-26 ================================================================================ # Alternative code signing methods > How to set up code signing without using code signing identities All iOS, macOS and Android applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. > > **Note:** This guide covers an alternative approach to code signing that manages certificates and provisioning profiles through CLI tools in build scripts, instead of Codemagic's Code Signing Identities UI. If you prefer using Code Signing Identities, see [Signing iOS apps](../yaml-code-signing/signing-ios) and [Android apps](../yaml-code-signing/signing-android). >
This document will guide you through the necessary steps to sign your app if your workflows are configured to use the `codemagic.yaml` file. If you are using our `Flutter workflow editor`, please consult the relevant guides for [iOS](../flutter-code-signing/ios-code-signing), [Android](../flutter-code-signing/ios-code-signing) or [macOS](../flutter-code-signing/macos-code-signing). ### Option: iOS ### Automatic vs Manual code signing > > Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. > Signing iOS apps requires a `signing certificate` (App Store **development** or **distribution** certificate in `.p12` format) and a `provisioning profile`. In **manual code signing** you save these files as Codemagic `environment variables` and manually reference them in the appropriate build steps. In **Automatic code signing**, Codemagic takes care of Certificate and Provisioning profile management for you. Based on the `Certificate private key` that you provide, Codemagic will automatically fetch the correct certificate from the App Store or create a new one if necessary. ### Automatic code signing When automatic code signing is used, then most up-to-date signing files are obtained directly from Apple during the build time. This requires that Codemagic has access to your Apple Developer portal account, which is achieved by using App Store Connect API key. #### Creating the App Store Connect API key It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Obtaining the Certificate private key To sign iOS apps, you can use the private key of an iOS Distribution certificate that has already been created in your Apple Developer Program account. Alternatively, you can create a new private key on your Mac and the Codemagic CLI will create a new iOS Distribution certificate in your Apple Developer Program account for you. ### Option: Create a new key You can create a new 2048 bit RSA key by running the command below in your terminal: ```Shell ssh-keygen -t rsa -b 2048 -m PEM -f ~/Desktop/ios_distribution_private_key -q -N "" ``` This new private key will be used to create a new iOS Distribution certificate in your Apple Developer Program account if there isn't one that already matches this private key. ### Option: Use an existing key"%}} 1. On the Mac which created the iOS distribution certificate, open the **Keychain Access**, located in the **Applications and Utilities** folder. 2. Select the certificate entry which should be listed as `iPhone Distribution: company_name (team_id)`. 3. Right-click on it to select "Export." 4. In the export prompt window that appears, make sure the file format is set to **Personal Information Exchange (.p12)**. 5. Give the file a name such as "IOS_DISTRIBUTION", choose a location and click **Save**. 6. On the next prompt, leave the password empty and click **OK**. 7. Use the following `openssl` command to export the private key: ```Shell openssl pkcs12 -in IOS_DISTRIBUTION.p12 -nodes -nocerts | openssl rsa -out ios_distribution_private_key ``` 8. When prompted for the import password, just press enter. The private key will be written to a file called **ios_distribution_private_key** in the directory where you ran the command. #### Configuring environment variables Provisioning profiles and code signing certificates are obtained from Apple Developer portal with the command [`app-store-connect fetch-signing-files`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#fetch-signing-files). App Store Connect API key information can be passed to it via environment variables [`APP_STORE_CONNECT_KEY_IDENTIFIER`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--key-idkey_identifier), [`APP_STORE_CONNECT_ISSUER_ID`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--issuer-idissuer_id), [`APP_STORE_CONNECT_PRIVATE_KEY`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--private-keyprivate_key). %!s() ### Option: Use App Store Connect integration The Apple Developer Portal integration can be enabled in the **Team integrations** section in your team settings (if you're a team admin). This allows you to conveniently use the same access credentials for automatic code signing and publishing across different apps and workflows. 1. In the list of available integrations, click the **Connect** button for **Developer Portal**. 2. In the **App Store Connect API key name**, provide a name for the key you are going to set up the integration with. This is for identifying the key in Codemagic. 3. Enter the **Issuer ID** related to your Apple Developer account. You can find it above the table of active keys on the Integrations tab of the [Users and Access](https://appstoreconnect.apple.com/access/integrations/api) page. 4. Enter the **Key ID** of the key to be used for code signing. 5. In the **API key** field, upload the private API key downloaded from App Store Connect. 6. Click **Save** to finish the setup. If you work with multiple Apple Developer teams, you can add additional keys by clicking **Add another key** right after adding the first key and repeating the steps described above. You can delete existing keys or add new ones when you click **Manage keys** next to the Developer Portal integration in personal account or team settings. Integration will take care of the App Store Connect API authentication part, but additionally the certificate private key has to be exported too. For this additional environment variable [`CERTIFICATE_PRIVATE_KEY`](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/fetch-signing-files.md#--certificate-keyprivate_key) has to be defined. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter `CERTIFICATE_PRIVATE_KEY` as the **_Variable name_**. 3. Open the file `ios_distribution_private_key` with a text editor and copy the **entire contents** of the file, including the `-----BEGIN RSA PRIVATE KEY-----` and `-----END RSA PRIVATE KEY-----` tags. Alternatively, you can run the following command on the file: ```Shell cat ios_distribution_private_key | pbcopy ``` 4. Paste into the **_Variable value_** field. 5. Enter a variable group name, e.g. **_code-signing_**. Click the button to create the group. 6. Make sure the **Secret** option is selected so that the variable can be protected by encryption. 7. Click the **Add** button to add the variable. In your workflow you can now simply use the following to ensure that all variables are readily available during build: ```yaml workflows: ios-workflow: environment: groups: - code-signing integrations: app_store_connect: ``` This will expose necessary environment variables during the build. ### Option: Define environment variables by yourself %!s() ================================================================================ source: https://docs.codemagic.io/yaml-basic-configuration/environment-variables/ title: Built-in environment variables in codemagic.yaml description: Useful variables exported during builds last_modified: 2026-06-26 ================================================================================ # Built-in environment variables in codemagic.yaml > Useful variables exported during builds Codemagic exports several built-in environment variables during the build that you can use in scripts to customize the build process. Environment variables added by the user will override Codemagic defaults. You can check which environment variables are exported by inserting the following script before or after any of the default build steps: ```yaml scripts: - name: Set up app/build.gradle script: | #!/bin/sh set -ex printenv ``` Here is a list of the built-in environment variables with brief explanations: | **Environment variable** | **Value** | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ANDROID_SDK_ROOT | Absolute path to Android SDK and tools | | CI | true | | CONTINUOUS_INTEGRATION | true | | BUILD_NUMBER | Number of the build for this project in Codemagic for the given workflow | | PROJECT_BUILD_NUMBER | Number of the build for this project in Codemagic | | FLUTTER_ROOT | Absolute path to Flutter SDK | | CM_BRANCH | The current branch being built, for pull requests it is the source branch | | CM_TAG | The tag being built if started from a tag webhook, unset otherwise | CM_REPO_SLUG | The slug of the repository that is currently being built in the form `owner_name/repository_name`. Unset for repositories added from custom source | | CM_COMMIT | Commit hash that is currently being built by Codemagic, for pull request builds it is the hash of the source commit | | CM_PREVIOUS_COMMIT | Commit hash of the previous successfully built commit in the same branch, (current excluded), unset if there is no previous successful commit | | CM_PULL_REQUEST | `true`, if the current build is building a pull request, `false` otherwise | | CM_PULL_REQUEST_NUMBER | Set to Integer ID of the pull request for the Git provider (Bitbucket, Github etc) if the current build is building a pull request, unset otherwise | | CM_PULL_REQUEST_DEST | The destination branch, if the current build is building a pull request, unset otherwise | | CM_CLONE_DEPTH | Number of commits to be cloned. Overwrites the following defaults: branch builds and destination branch for PR builds - 50, tag builds - 1 | | CM_CLONE_UNSHALLOW | Set `true` to clone full commit history | | CM_RECURSIVE_SUBMODULE_INIT | If set to `false`, recursive submodule cloning is disabled | | CM_PROJECT_ID | UUID of the project that is being built | CM_BUILD_ID | UUID of the build | | CM_TEST_STEP_STATUS | Test step status, success or failure | | CM_BUILD_STEP_STATUS | Build step status, success, failure or skipped. Only available when using Workflow Editor, unavailable with codemagic.yaml | | CM_BUILD_DIR | Absolute path to the root directory of the cloned repository in Codemagic builders | | CM_BUILD_OUTPUT_DIR | Contains the artifact files generated during the build | | CM_EXPORT_DIR | The files added to this directory will be added to a zip file and made available as build artifacts | | CM_FLUTTER_SCHEME | Name of the iOS scheme to be used | | CM_KEYSTORE_PASSWORD | Password of Android keystore as configured in the UI | | CM_KEY_PASSWORD | Password of Android key as configured in the UI | | CM_KEY_ALIAS | Alias of the key as configured in the UI | | CM_KEYSTORE_PATH | Path of the file in our VM | | CM_ARTIFACT_LINKS | Information about generated build artifacts that is available in post-publishing step. Read more about it below. | | CM_WORKFLOW_NAME | Name of the workflow that is currently being built | CM_ENV | Environment file that sets/overrides environment variables at build time | CM_TRIGGER_SOURCE | The source that triggered the build. Possible values are `webhook`, `schedule`, or `api` (started manually from the UI or via the REST API). | CM_BUILD_STARTED_BY | The email of the user who started the build. Used only with builds triggered by `api` (see `CM_TRIGGER_SOURCE`). ### Artifact links `$CM_ARTIFACT_LINKS` environment variable value is a JSON encoded list in the following form: ```json [ { "name": "Codemagic_Release.ipa", "type": "ipa", "url": "https://api.codemagic.io/artifacts/2e7564b2-9ffa-40c2-b9e0-8980436ac717/81c5a723-b162-488a-854e-3f5f7fdfb22f/Codemagic_Release.ipa", "md5": "d2884be6985dad3ffc4d6f85b3a3642a", "versionName": "1.0.2", "bundleId": "io.codemagic.app" } ] ``` ================================================================================ source: https://docs.codemagic.io/rest-api/caches/ title: Caches API description: API to manage app storage cache last_modified: 2022-11-03 ================================================================================ # Caches API > API to manage app storage cache ## Retrieve a list of caches for an application `GET /apps/:id/caches` List caches information for the specified application. #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ -X GET https://api.codemagic.io/apps//caches ``` #### Response ```json { "caches": [ { "_id": "620f9f218ab90da6b1b22e0e", "appId": "60ddd0b747960e00124747cb", "lastUsed": "2022-02-18T13:29:05.541+0000", "size": 127793163, "workflowId": "build-ipa" }, { "_id": "620f9e948ab90da6b1b2217d", "appId": "60ddd0b747960e00124747cb", "lastUsed": "2022-02-18T13:26:44.676+0000", "size": 59377366, "workflowId": "build-apk" } ] } ``` ## Delete all application caches `DELETE /apps/:id/caches` Remove all stored caches for the specified application. #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ -X DELETE https://api.codemagic.io/apps//caches ``` #### Response Response for successful cache deletion request is `202 Accepted` and contains identifiers of the caches that are to be deleted. Actual deletion is completed asynchronously. ```json { "caches": [ "620f9f218ab90da6b1b22e0e", "620f9e948ab90da6b1b2217d" ], "message": "Cache deletion was started asynchronously, it will be completed in a moment" } ``` ## Delete a specific cache from an application `DELETE /apps/:id/caches/:cacheId` Remove stored cache from the specified application for a single workflow. #### Example ```bash curl -H "Content-Type: application/json" \ -H "x-auth-token: " \ -X DELETE https://api.codemagic.io/apps//caches/ ``` #### Response Response for successful cache deletion request is `202 Accepted` and contains identifier of the cache that is to be deleted. Actual deletion is completed asynchronously. ```json { "caches": ["620f9f218ab90da6b1b22e0e"], "message": "Cache deletion was started asynchronously, it will be completed in a moment" } ``` ================================================================================ source: https://docs.codemagic.io/knowledge-codemagic/caching/ title: Caching description: How to configure caching for your builds last_modified: 2026-06-26 ================================================================================ # Caching > How to configure caching for your builds Caching can improve the efficiency of your build and deployment processes on Codemagic by reusing components that are generated or fetched during the build, such as packages, libraries, and compiled code. When you have enabled caching for a workflow, Codemagic will automatically generate a cache based on the output of the first successful build. This cache is stored for a maximum of 14 days. After 14 days, the cache expires and is no longer accessible for subsequent builds. When this occurs, your workflow will fetch all dependencies and artifacts again and generate a new cache. This new cache is then uploaded and can be used for the next 14 days, following the same process. For example, you may consider caching the following paths: | **Path** | **Description** | | ------------------------------------------- | ------------------------------------------------ | | `$HOME/.pub-cache` | Dart cache | | `$HOME/.gradle/caches` | Gradle cache. Note: do not cache `$HOME/.gradle` | | `$HOME/Library/Caches/CocoaPods` | CocoaPods cache | A great article on Unity caching can be found in [our blog](https://blog.codemagic.io/unity-caching/). > > **Note:** Caching `$HOME/Library/Developer/Xcode/DerivedData` won't help to speed up iOS builds. > ## Enabling dependency caching ### Option: codemagic.yaml To use caching, simply add a `cache` section to workflows you would like to have caching enabled for in the `codemagic.yaml` file and list the paths you would like to cache. ```yaml workflows: example-workflow: cache: cache_paths: - ~/.gradle/caches - ... ``` ### Option: Flutter WFE 1. In your app settings, open the **Dependency caching** section. 2. Check the **Enable dependency caching** option. By default, caching is disabled. 3. Enter the path(s) to the dependencies to be cached and click **Add**. Note that you can delete added paths anytime. > > **⚠️ Note:** If your dependencies have any warnings or errors when trying to cache them, the caching process will not complete successfully even though you will see a cache for the workflow listed under the Caching tab in the UI. You should reset the cache by deleting the workflow cache under the Caching tab and deal with any errors or warnings. > ## Cache usage limits Maximum cache size is limited to - **10GB** per workflow for teams, and - **3GB** per workflow for personal accounts. Note that installing dependencies without using caching could be faster than retrieving or updating cached data. ## Removing cached dependencies In order to clear the collected cache, navigate to the **Dependency caching** section in app settings and click **Clear cache**. During the next build, dependencies will be downloaded afresh. ## Xcode compilation caching Starting with Xcode 26 it is possible to use **compilation caching**. This is a new build system feature designed to make builds significantly faster by caching and reusing compilation outputs across different builds. On macOS, the compilation cache can usually be found in `~/Library/Developer/Xcode/DerivedData/CompilationCache.noindex`. For Codemagic to reuse the compilation cache you should add its path to your cache paths in your `codemagic.yaml` configuration file as follows: ```yaml cache: cache_paths: - ~/Library/Developer/Xcode/DerivedData/CompilationCache.noindex ``` When building and exporting your `.ipa` with Codemagic's CLI tools you can ensure the compilation cache is used during builds by adding the `COMPILATION_CACHE_ENABLE_CACHING=True` flag as follows: ```yaml - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "${XCODE_SCHEME}.xcworkspace" \ --scheme "${XCODE_SCHEME}" \ --archive-xcargs "COMPILATION_CACHE_ENABLE_CACHING=True" ``` The first build will generate the cache which will be uploaded to Codemagic's cache server. On subsequent builds Codemagic restores the directory containing the compilation cache which should speed up the build. You can see if the compilation cache is being used by looking at the Xcode build logs. ```bash CompilationCacheMetrics note: 85 hits / 85 cacheable tasks (100%) ``` Xcode build logs can be gathered as artifacts by setting the path to the logs in the `artifacts` section of your `codemagic.yaml` configuration file. ```yaml artifacts: - /tmp/xcodebuild_logs/*.log ``` ## Swift Package Manager caching Swift Package Manager (SPM) is Apple's official dependency manager for Swift projects. By caching SPM dependencies in your workflow, subsequent builds can reuse previously fetched packages rather than downloading them again, resulting in faster build times. You can cache the **global SPM cache** which is shared across all projects on the machine ```yaml cache: cache_paths: - ~/Library/Caches/org.swift.swiftpm ``` Alternatively, when building and exporting your `.ipa` with Codemagic's CLI tools you can cache **project level SPM dependencies** by setting the path to the `SourcePackages` directory as follows: ```yaml - name: Build ipa for distribution script: | xcode-project build-ipa \ --project "$XCODE_PROJECT" \ --scheme "$XCODE_SCHEME" \ --archive-flags "-clonedSourcePackagesDirPath $CM_BUILD_DIR/SourcePackages" ``` You can then set your cache paths as follows: ```yaml cache: cache_paths: - $CM_BUILD_DIR/SourcePackages ``` ================================================================================ source: https://docs.codemagic.io/integrations/capawesome-cloud-integration/ title: Capawesome Cloud integration description: How to integrate your workflows with Capawesome Cloud using codemagic.yaml last_modified: 2025-06-30 ================================================================================ # Capawesome Cloud integration > How to integrate your workflows with Capawesome Cloud using codemagic.yaml [Capawesome Cloud](https://capawesome.io/cloud/) is a powerful platform that provides a suite of tools to help you deploy [Live Updates](https://capawesome.io/blog/announcing-the-capacitor-live-update-plugin/) to your [Capacitor](https://capacitorjs.com/) apps after they have been published to the App Store or Google Play. ## Configure access to Capawesome Cloud Follow these steps to configure access to Capawesome Cloud: 1. Sign up with [Capawesome Cloud](https://cloud.capawesome.io) and generate a new token via the [Settings](https://cloud.capawesome.io/settings/tokens) page 2. Open your Codemagic app settings, and go to the **Environment variables** tab. 3. Enter the desired **_Variable name_**, e.g. `CAPAWESOME_TOKEN`. 4. Copy and paste the Capawesome Cloud token string as **_Variable value_**. 5. Enter the variable group name, e.g. **_capawesome_credentials_**. Click the button to create the group. 6. Make sure the **Secret** option is selected. 7. Click the **Add** button to add the variable. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - capawesome_credentials ``` ## Install the Capawesome Cloud CLI In order to deploy live updates to Capawesome Cloud, you need to install the Capawesome Cloud CLI: ```yaml scripts: - name: Install Capawesome Cloud CLI script: | npm install @capawesome/cli ``` After that, you need to log in to Capawesome Cloud using the token you generated: ```yaml scripts: - name: Log in to Capawesome Cloud script: | npx capawesome login --token $CAPAWESOME_TOKEN ``` ## Deploy a Live Update to Capawesome Cloud Now you can deploy a live update to Capawesome Cloud: ```yaml scripts: - name: Deploy to Capawesome Cloud script: | npx capawesome apps:bundles:create --appId --path ``` Make sure to replace `` with the ID of your app on Capawesome Cloud and `` with the path to the bundle you want to upload (e.g. `www`). We recommend that you also specify a [Channel](https://capawesome.io/cloud/live-updates/channels/) when uploading the bundle: ```yaml scripts: - name: Deploy to Capawesome Cloud script: | npx capawesome apps:bundles:create --appId --path --channel ``` This way you can easily restrict live updates to specific versions of your app and prevent incompatible updates. The Capawesome Cloud CLI then automatically creates a zip archive of the bundle and uploads it to the Capawesome Cloud where it becomes immediately available for download. ================================================================================ source: https://docs.codemagic.io/flutter-distributing/shorebird/ title: Code Push with Shorebird description: Deploy app updates to users' devices using Shorebird in Flutter workflow editor last_modified: 2026-04-01 ================================================================================ # Code Push with Shorebird > Deploy app updates to users' devices using Shorebird in Flutter workflow editor Code push for Flutter is a cloud service by [Shorebird](https://shorebird.dev/) that allows developers to push over-the-air (OTA) app updates directly to users' devices without publishing each update on app stores. With Codemagic, you can use Shorebird to build and publish a release or a patch for Android and iOS. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured using **codemagic.yaml**, you can follow the guide [here](https://docs.shorebird.dev/code-push/ci/codemagic/). > ## Prerequisites In order to configure a Shorebird workflow in Codemagic, the following is needed: - Shorebird needs to be [initialized](https://docs.shorebird.dev/code-push/initialize/) for your Flutter project; - A token for authentication with Shorebird; - Code signing files. ## Creating a Shorebird API key token Most Shorebird functionality, like creating releases and patches, requires authentication. To authenticate in Codemagic, create an API key in the [Shorebird Console](https://console.shorebird.dev/): 1. Go to **Account** -> **API Keys**. 2. Click **Create API Key**. 3. Give the key a name, choose an expiration, and select a permission level. 4. Copy the key value (it is shown only once). Use this key as your `SHOREBIRD_TOKEN` in Codemagic. > > **Note:** `shorebird login:ci` is deprecated. Existing tokens generated by `shorebird login:ci` continue to work until September 2026, but new tokens should be created from the Shorebird Console. The `SHOREBIRD_TOKEN` environment variable name has not changed, so you only need to update the secret value in Codemagic. > Note that the Shorebird token is a secret and should not be shared publicly or checked in to source control. ### Option: Building a release Release builds can be published to app stores and patched once they've been distributed. Read more about Shorebird [releases](https://docs.shorebird.dev/code-push/release/). 1. In workflow editor, select the platforms for which you want to build. Only **Android** and **iOS** are supported with Shorebird for now. 2. Under **Publish updates to user devices using Shorebird**, select **Release**. 3. Scroll to the **Shorebird** section and specify the Flutter version and the Xcode version (if you selected **iOS**) to be used for building the app. 4. Copy-paste your token generated from **Shorebird Console -> Account -> API Keys** in the **Shorebird token** field. Once you save it, the token can no longer be viewed, only modified or deleted. 5. If your Flutter project is not in the root of the repository, update the **Project path** to point to the right directory. 6. You can add additional **build arguments** to the `shorebird release` build command, e.g. to specify the flavor or target for your app. See more info [here](https://docs.shorebird.dev/code-push/release/). 7. Scroll down to the **Distribution** section to set up code signing. You can follow the guides for [iOS code signing](../flutter-code-signing/ios-code-signing) and [Android code signing](../flutter-code-signing/android-code-signing) respectively. 8. Save the settings and start a new build. On successful build, the release artifact will be uploaded to your Shorebird console. > > > **Please note:** > > * If you also wish to distribute the same artifact to the stores, you can configure publishing to [App Store](../flutter-publishing/publishing-to-app-store) or [Google Play](../flutter-publishing/publishing-to-google-play) as part of the workflow. > > * Every release must have a unique version. Read how to set up [automatic build versioning](../knowledge-codemagic/build-versioning) with Codemagic. > ### Option: Building a patch Once you have published a release of your app, you can patch it by pushing an app update directly to users' devices. Read more about Shorebird [patches](https://docs.shorebird.dev/code-push/patch/). 1. In workflow editor, select the platforms for which you want to build. Only **Android** and **iOS** are supported with Shorebird for now. 2. Under **Publish updates to user devices using Shorebird**, select **Patch**. 3. Scroll to the **Shorebird** section and specify the Xcode version (if you selected **iOS**) to be used for building the app. Note that it is recommended to use the same Xcode version that was used to build the app version you are going to patch so as to avoid warnings about the app containing native changes. 4. Specify the **Android release version** and/or the **iOS release version** to patch. To patch the latest release, set the value to `latest`. 5. Copy-paste your token generated from **Shorebird Console -> Account -> API Keys** in the **Shorebird token** field. Once you save it, the token can no longer be viewed, only modified or deleted. 6. If your Flutter project is not in the root of the repository, update the **Project path** to point to the right directory. 7. You can add additional **build arguments** to the `shorebird patch` build command, e.g. to specify the flavor or target for your app. See more info [here](https://docs.shorebird.dev/code-push/patch/). 8. Scroll down to the **Distribution** section to set up code signing. You can follow the guides for [iOS code signing](../flutter-code-signing/ios-code-signing) and [Android code signing](../flutter-code-signing/android-code-signing) respectively. 9. Save the settings and start a new build. On successful build, the patch artifact will be uploaded to your Shorebird console. ================================================================================ source: https://docs.codemagic.io/troubleshooting/common-google-play-errors/ title: Common Google Play errors description: Troubleshooting common Google Play errors last_modified: 2026-06-26 ================================================================================ # Common Google Play errors > Troubleshooting common Google Play errors Codemagic enables you to automatically publish your app to the internal, alpha, beta, production or custom tracks on Google Play. While publishing to Google Play you may encounter errors if the application does not meet the release criteria. You can see the explanations of some of the common errors: ### Code: 403, The caller does not have permission. status: PERMISSION_DENIED ###### Description This could be due to an invalid JSON file or permission issues with the service account. {{}} ###### Solution Please make sure you have done the following: 1. Created a service account in the Google Play console 2. Set the service account access to **Service Account User** 3. Created a JSON private key 4. Added the JSON key to Codemagic 5. Navigated to your Google Play Console API access and granted access to the service account 6. Given the service account access to your application 7. Invited users to the service account Checkout [this guide](https://docs.codemagic.io/yaml-publishing/google-play/) for codemagic.yaml or this guide for [Workflow editor](../flutter-publishing/publishing-to-google-play). {{< /collapsible >}} ### The current user has insufficient permissions to perform the requested operation. status: PERMISSION_DENIED ###### Description This error may have been caused by Account permission issues. {{}} ###### Solution - Try setting admin access for Account permissions on google play console. - After granting access, Google may take 24-48 hours to propagate all access rights for all APIs or new users. {{< /collapsible >}} ### Google Play failed to upload artifacts. This Edit has been deleted. ###### Description This error usually occurs when there are parallel builds running, as in 2 builds triggered at the same time. {{}} ###### Solution Set `cancel_previous_builds: true` in your triggers, but it doesn't work when builds are triggered using API. {{< /collapsible >}} ### Cannot replace a bundle of version code X with an APK. ###### Description This usually indicates that you have already published a .aab with version code 'x', and now you are trying to publish the .aab with the same version code. {{}} ###### Solution Try to upload .aab by incrementing the version code. {{< /collapsible >}} ### APK specifies a version code that has already been used ###### Description This error is possible when your version code is the same as the `.aab` already uploaded on google play. {{}} ###### Solution Check version and version code. {{< /collapsible >}} ### Cannot update a published APK ###### Description If an app has already been sent to a specific track, you cannot re-upload it. This error is possible when your version or version code is the same as the apk/aab already uploaded on google play. {{}} ###### Solution You can change its track or increment the version code. {{< /collapsible >}} ### Your scoped storage permission declaration needs to be updated ###### Description Google requires you to declare your [storage permissions](https://developer.android.com/about/versions/11/privacy/storage). {{}} ###### Solution You will have to update your app accordingly to be able to publish to Google Play Store. {{< /collapsible >}} ### You cannot rollout this release because it does not allow any existing users to upgrade to the newly added APKs ###### Description The error message is because your new APK has a lower version code than the previous APK. Newer APKs must always have a higher version code than the previous version. {{}} ###### Solution Check your version code and upgrade it to a higher version code. {{< /collapsible >}} ### Package not found: com.xxxxx.app ###### Description The error 'Package not found' means that an application with the package name from the artifact generated during the builds doesn't exist in your Google Play account. {{}} ###### Cause This happens when either you haven't uploaded the first artifact to your Google Play application manually, or the generated artifact package name has some suffixes or changes and doesn't correspond to the one in Google Play. ###### Solution Ensure the package name matches exactly with the one in Google Play, or upload the first artifact manually to create the application. {{< /collapsible >}} ### APK has not been signed with the upload certificate ###### Description The APK was not signed with the correct upload certificate. {{}} ###### Solution Check code signing. Use the same keystore while uploading your artifacts. {{< /collapsible >}} ### For uploading an AppBundle you must be enrolled in Play Signing ###### Description As per the error, you need to upload your keystore to [Play App Signing](https://support.google.com/googleplay/android-developer/answer/9842756?visit_id=637769761748201384-2647523405&rd=1). {{}} ###### Solution Enroll your app into app signing by Google Play to have Google sign the .aab that are generated from the app bundle during installation. {{< /collapsible >}} ### You uploaded an APK or Android App Bundle that was signed in debug mode ###### Description You need to sign your APK or Android App Bundle in **release mode** instead of debug mode. {{}} ###### Solution Set your signing configuration in `build.gradle` in release mode. Refer to [this](../code-signing/android-code-signing/#option-2-configure-signing-using-environment-variables) for more information. {{< /collapsible >}} ### APKs are not allowed for this application ###### Description It is no longer possible to submit new apps to Google Play using the APK format. Instead, generate Android App Bundles(.aab). Check [this](https://android-developers.googleblog.com/2021/06/the-future-of-android-app-bundles-is.html) out. {{}} ###### Solution You should use `./gradlew bundleRelease` to generate .aab file. And don't forget to mention the artifact path `app/build/outputs/bundle/**/*.aab` in the `artifacts:` section in your codemagic.yaml. {{< /collapsible >}} ### Only releases with status draft may be created on draft app ###### Description `400` error is related to the app being in draft status. The very first version of the app must be added to Google Play manually. {{}} ###### Solution In case you want to upload the artifacts generated in the build to Google Play as a draft release, select **Submit release as draft** in the workflow editor or `submit_as_draft: true` in your yaml configuration. {{< /collapsible >}} ### changesNotSentForReview Errors ###### Description changesNotSentForReview means (from Google Play API docs): Indicates that the changes in this edit will not be reviewed until they are explicitly sent for review from the Google Play Console UI. These changes will be added to any other changes that are not yet sent for review. {{}} ###### Solution - Beware, this parameter should not always be true. - If an app/track is in a "rejected" state, then you need to submit the app with changesNotSentForReview: true, otherwise, you should send without specifying changesNotSentForReview(or setting it to false). ```yaml publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal # Optional boolean To be used ONLY if your app cannot be sent for review automatically changes_not_sent_for_review: true ``` - If you are getting a **400 error** related to the app being in draft status, either enable publishing to draft by setting the value of **submit_as_draft** to **true** or promote the draft build up by a level to one of the testing tracks. Play Console will show you how to do this. You'll need to go through the steps, fill out questionnaires, upload various screenshots, and then after approval, you can move to the Alpha testing track, and Codemagic will successfully publish. - Depending on your app's update status, it may not be sent for review automatically. - If your changes are sent to review automatically, but the field is still set to `true`, you may get the error _**Changes are sent for review automatically. The query parameter changesNotSentForReview must not be set.**_ - Also, it might be that the actual cause of the error is getting swallowed and is surfaced by changesNotSentForReview error. In that case, try to re-run it by adding `--stacktrace` that will print out a full stack trace. - Check [this](https://docs.codemagic.io/yaml-publishing/google-play/) out. {{< /collapsible >}} ### Error 502 (Server Error) ###### Description `5xx` errors are from the Google Play servers. {{}} ###### Solution The solution is to try again after some time. {{< /collapsible >}} ================================================================================ source: https://docs.codemagic.io/yaml-distributing/firebase-hosting/ title: Firebase Hosting description: How to deploy an app to Firebase Hosting using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Firebase Hosting > How to deploy an app to Firebase Hosting using codemagic.yaml

> > **Note:** This guide only applies to workflows configured with the **codemagic.yaml**. > Publishing to Firebase Hosting with Codemagic is a straightforward process as the Firebase CLI is already pre-installed on our virtual machines. Please note that you will have to set it up for your project locally before publishing it to Firebase Hosting. You can find more information in the official [Firebase documentation](https://firebase.google.com/docs/hosting/quickstart). ### Using Firebase Google Service Account 1. To get started you will need a Google service account user with `Cloud Build Service Account`, `Firebase Admin` and `API Keys Admin roles` as shown in the Firebase [docs](https://cloud.google.com/build/docs/deploying-builds/deploy-firebase#required_iam_permissions). 2. You can follow the step-by-step guide to create the service account user [here](../yaml-distributing/firebase-app-distribution/). 3. Configure the `JSON` key received from step 2 as an environment variable named `FIREBASE_SERVICE_ACCOUNT` . 4. Add an environment variable named GOOGLE_APPLICATION_CREDENTIALS and set its value to `$CM_BUILD_DIR/firebase_credentials.json`. Make sure to mark it as **Secret** and enter the variable group name, e.g. **_firebase_credentials_**. You can check the doc [here](../yaml-basic-configuration/configuring-environment-variables/) for more details. 5. In your workflow, use the below script to copy the contents of the JSON key in your project folder. ```yaml scripts: - name: Write Google credentials script: | echo $FIREBASE_SERVICE_ACCOUNT > $GOOGLE_APPLICATION_CREDENTIALS ``` 6. For publishing to Firebase Hosting, add the following script in **codemagic.yaml** right after executing the build script. ```yaml scripts: - name: Publish to Firebase Hosting script: | firebase deploy --only hosting ``` ### Using Firebase token 1. To get started with adding Firebase Hosting to Codemagic, you will need to obtain your Firebase token. In order to do that, run the following in your local terminal: ```bash firebase login:ci ``` 2. After running the command, your default browser should prompt for authorization to your Firebase project. When access is granted, the necessary token will appear in your terminal. 3. Open your Codemagic app settings, and go to the **Environment variables** tab. 4. Enter the desired **_Variable name_**, e.g. `FIREBASE_TOKEN`. 5. Copy and paste the content of the token displayed in your terminal as **_Variable value_**. 6. Enter the variable group name, e.g. **_firebase_credentials_**. Click the button to create the group. 7. Make sure the **Secret** option is selected. 8. Click the **Add** button to add the variable. 5. Create a new script for publishing to Firebase Hosting in your scripts section of the .yaml file and add it right after the build step ```yaml environment: groups: -firebase_credentials scripts: - name: Publish to Firebase Hosting script: | firebase deploy --token "$FIREBASE_TOKEN" ``` When the build is successful, you can see your application published to Firebase Hosting. You can find the direct URL to the deployed build also from the log output in Codemagic UI: ``` ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/your-project/overview Hosting URL: https://your-project.web.app ``` ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-flutter-app/ title: Flutter apps description: How to build a Flutter app with codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Flutter apps > How to build a Flutter app with codemagic.yaml This guide will illustrate all of the necessary steps to successfully build and publish a Flutter app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml `codemagic.yaml` is a highly customizable configuration file that you can use to build, test and publish Flutter apps, widgets, and Flutter or Dart packages. The Workflow Editor is a quick way to get started building standard Flutter applications. You can simultaneously set up workflows both in `codemagic.yaml` and the Workflow Editor. However, when a `codemagic.yaml` is detected in the repository, it is automatically used for configuring builds that are triggered in response to the events defined in the file and any configuration in the Flutter workflow editor is ignored. > > **Note:** For documentation on building Flutter projects using the workflow editor, please refer to [**Building Flutter apps via the workflow editor**](../flutter-configuration/flutter-projects). > In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Setting the Flutter version When building a Flutter application with Codemagic, you can customize your build environment by configuring various settings. One such setting is the option to choose the Flutter version or channel for the build process. Codemagic provides several options: defining a specific channel or version, or alternatively, you can leverage [Flutter Version Management (FVM)](https://fvm.app/documentation/getting-started) for version management. ### Option: Specific Flutter channel or version #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` #### Signing Android apps using Gradle To sign your Android app, simply modify your **`android/app/build.gradle`** or **`android/app/build.gradle.kts`** as follows: %!s() ### Option: build.gradle ```Groovy ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` ### Option: build.gradle.kts ```groovy import java.io.File import java.util.* val keystoreProperties = Properties().apply { var file = File("key.properties") if (file.exists()) load(file.reader()) } plugins { ... } android { ... val appVersionCode = (System.getenv()["NEW_BUILD_NUMBER"] ?: "1")?.toInt() defaultConfig { ... versionCode = appVersionCode ... } signingConfigs { create("release") { if (System.getenv()["CI"].toBoolean()) { // 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 { storeFile = file(keystoreProperties.getProperty("storeFile")) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } } } buildTypes { getByName("release") { isMinifyEnabled = false signingConfig = signingConfigs.getByName("release") } } } dependencies { ... } ``` ### Option: iOS #### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. %!s() ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ##### Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > ### Option: macOS #### Creating the App Store Connect API key Signing macOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > ### Automatic vs Manual code signing Signing macOS apps requires a `Signing certificate` (App Store **development** or **distribution** certificate in `.p12` format) and a `Provisioning profile`. In **Manual code signing** you save these files as Codemagic `Environment variables` and manually reference them in the appropriate build steps. In **Automatic code signing**, Codemagic takes care of Certificate and Provisioning profile management for you. Based on the `certificate private key` that you provide, Codemagic will automatically fetch the correct certificate from the App Store or create a new one if necessary. #### Certificate types There are several certificate types you can choose to sign your macOS app, depending on the distribution method you plan to use. - `MAC_APP_DEVELOPMENT` certificate allows you to build your app for internal testing and debugging. - `MAC_APP_DISTRIBUTION` certificate is used to sign a Mac app before submitting it to the Mac App Store - `MAC_INSTALLER_DISTRIBUTION` is used to sign and submit a Mac Installer Package to the Mac App Store - `DEVELOPER_ID_APPLICATION` is used to sign a Mac app before distributing it outside the Mac App Store - `DEVELOPER_ID_INSTALLER` is used to sign a Mac Installer Package before distributing it outside the Mac App Store For example, in order to publish to Mac App Store, the application must be signed with a `Mac App Distribution` certificate using a `Mac App Store` provisioning profile. If you want to create a `.pkg` Installer package, you must use a `Mac Installer Distribution` certificate. #### Obtaining the certificate private key To enable Codemagic to automatically fetch or create the correct signing certificate on your behalf, you need to provide the corresponding `certificate private key`. You then have to save that key as a Codemagic environment variable. %!s() ### Option: Create a new keyIf the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to Google Play and App Store %!s() ### Option: Android Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` %!s() ### Option: iOSCodemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: %!s() ### Option: AndroidWhile this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/yaml-publishing/microsoft-store/ title: Microsoft Store publishing with codemagic.yaml description: How to deploy an app to Microsoft Store using codemagic.yaml last_modified: 2025-05-27 ================================================================================ # Microsoft Store publishing with codemagic.yaml > How to deploy an app to Microsoft Store using codemagic.yaml Codemagic enables you to automatically publish your Windows desktop apps to the Microsoft Store. > > **Note:** This guide only applies to workflows configured with the `codemagic.yaml`. If your workflow is configured with **Flutter workflow editor** please go to [Publishing to Microsoft Store using Flutter workflow editor](../publishing/publishing-to-microsoft-store). > For publishing, Codemagic makes use of the [Microsoft Store submission API](https://docs.microsoft.com/en-us/windows/uwp/monetize/create-and-manage-submissions-using-windows-store-services). This requires linking your Partner Center account to the Azure AD application and providing Codemagic with information that can be used to generate temporary Azure AD access tokens for managing submissions. > > **Note:** The very first version of the app must be submitted to the Partner Center manually. You can download the **MSIX** package from the build artifacts. > To link your Microsoft Partner Center account with the Azure AD application and get the necessary details (`tenant_id`, `client_id`, `client_secret`), follow the instructions [here](../knowledge-base/partner-center-authentication). It is also necessary for you to provide your `store_id`, which can be found when you open the application in the [Partner Center apps dashboard](https://partner.microsoft.com/en-us/dashboard/apps). To safely store and use the `client_secret`, save it as an [environment variable](/variables/environment-variable-groups/#storing-sensitive-valuesfiles) in the Codemagic UI. Click **Secret** to encrypt the value. ```yaml publishing: partner_center: store_id: 1D4VKTPG38SA tenant_id: ab80a389-41e3-55a8-ae12-bb7430667e04 client_id: 52da6186-abce-14f4-b2e1-00018c16f3d1 client_secret: $CLIENT_SECRET ``` ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-native-app-with-flutter-module/ title: Native apps with a Flutter module description: How to build a native iOS or Android app with a Flutter module using codemagic.yaml last_modified: 2022-10-27 ================================================================================ # Native apps with a Flutter module > How to build a native iOS or Android app with a Flutter module using codemagic.yaml Flutter can be integrated into your existing application as a library to render a part of your app’s UI in Flutter. To add a Flutter module to an existing app, please refer to [the official Flutter documentation](https://flutter.dev/docs/development/add-to-app). Please follow the guides on [native Android](../yaml-quick-start/building-a-native-android-app) and on [native iOS](../yaml-quick-start/building-a-native-ios-app) to get you started with the project and then modify the workflow as described below to add Flutter modules. The examples below show how to build apps containing Flutter modules using `codemagic.yaml`. The examples provided here are inspired by [Flutter add-to-app samples](https://github.com/flutter/samples/tree/master/add_to_app) where the Flutter module directory (referred to as `my_flutter_module` in templates) is on the same level as the host app directory (referred to as `my_host_app`). ## Using a Flutter module (with dependencies) as a library Using a Flutter module as a library means that it will be built from the source each time the host app builds. Here are the sample build steps you can add to your `codemagic.yaml`: ### Option: Android ```yaml scripts: - name: Add Flutter and build script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/my_host_app/local.properties" cd my_flutter_module && flutter pub get cd my_host_app && ./gradlew assembleDebug ``` ### Option: iOS ```yaml scripts: - name: Build Flutter module from the source script: | cd my_flutter_module flutter pub get flutter build ios --release --no-codesign cd .ios pod install - name: Build host application script: | cd my_host_app pod install xcodebuild build -workspace "MyXcodeProject.xcworkspace" \ -scheme "MyXcodeScheme" \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO ``` > > **Note:** If you don't have a workspace, use > `-project "MyXcodeProject.xcodeproj"` instead of the > `-workspace "MyXcodeWorkspace.xcworkspace"` option. > ### Using a prebuilt Flutter module Using a prebuilt module means that you don't need to build it every time the host app is built if there are no changes to the module. You may speed up your overall building time by precompiling your Flutter module once, committing it to the repository and reusing it afterwards without the need to build it from the source. ### Option: Android ```yaml scripts: - name: Configure local properties script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/my_host_app/local.properties" - name: Precompile the Flutter module script: | cd my_flutter_module flutter pub get flutter build aar - name: Build host application script: | cd my_host_app ./gradlew assembleDebug ``` ### Option: iOS ```yaml scripts: - name: Precompile the Flutter module script: | cd my_flutter_module flutter packages get flutter build ios-framework \ --output=$CM_BUILD_DIR/my_host_app/Flutter - name: Build host application script: | cd my_host_app pod install xcodebuild build -project "MyXcodeProject.xcodeproj" \ -scheme "MyXcodeScheme" \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO ``` > > **Note:** If you don't have a workspace, use > `-project "MyXcodeProject.xcodeproj"` instead of the > `-workspace "MyXcodeWorkspace.xcworkspace"` option. > ================================================================================ source: https://docs.codemagic.io/flutter-distributing/app-preview/ title: Previewing apps in the browser description: Test your iOS or Android app in the browser with App Preview last_modified: 2026-04-01 ================================================================================ # Previewing apps in the browser > Test your iOS or Android app in the browser with App Preview App Preview is our iOS simulator and Android emulator running in your browser. Launch and interact with your iOS or Android app right in the browser, regardless of the operating system you are using. Test your app against different device and OS configurations, emulate GPS location or demo the latest app version without needing access to a physical device. {{< youtube l1VeZXtO0zQ >}} **Tip:** The following sections describe creating previewable artifacts using Flutter Workflow Editor. If you're using codemagic.yaml, follow the instructions [here](../yaml-distributing/app-preview). ## Enabling App Preview and Free Trial > > This feature is available for **teams** only. > Teams on the **Pay as you go** plan can enable the feature via the **App Preview** page on the left sidebar and will get 100 free trial minutes. Once used up, further app preview minutes will be billed at the rate of $0.095/min and included in your monthly invoice. Teams on annual plans can try out App Preview by [contacting us](https://codemagic.io/contact/). ## Creating iOS .app binaries for previewing on the simulator You can preview any `.app` artifact built in Codemagic that targets the `iPhoneSimulator`. 1. In the **Build** section of the Workflow Editor, set the **Mode** to **Debug**. 2. In the **Build arguments** field, add `--simulator` next to the iOS `--debug` section. 3. On a successful build, you will see the **Quick Launch** button available next to the `.app` artifact in the build overview. ## Creating Android .apk binaries for previewing on the emulator You can preview any `.apk` artifact built in Codemagic. In the **Build** section of the Workflow Editor, select an Android build format that outputs an `.apk` file. On a successful build, you will see the **Quick Launch** button available next to the `.app` artifact in the build overview. ## Previewing apps Clicking **Quick Launch** next to a suitable artifact launches an iOS simulator or an Android emulator respectively with your app installed on it, right in your browser. To use a different device and OS combination, click the three dots on the controls menu and select **Change device**. The preview session remains active for a maximum of **20 minutes** and is limited to one concurrent session by default. To end the ongoing session, select **Stop session** from the menu. ================================================================================ source: https://docs.codemagic.io/rn-codepush/production-control/ title: Production control description: Manage rollouts, targeting, and rollback behavior last_modified: 2026-06-26 ================================================================================ # Production control > Manage rollouts, targeting, and rollback behavior Once OTA updates are set up, the next step is controlling how changes are delivered to users in production. CodePush provides release controls that let teams: * roll out updates gradually * target specific app versions * enforce mandatory updates when required * quickly revert problematic releases These controls help minimize risk and ensure safe, predictable delivery of updates to production users. --- ## Rollouts (Gradual Release) Rollouts allow an update to be delivered to only a percentage of users instead of releasing it to everyone at once. This approach helps reduce risk by letting you monitor performance, crashes, and user feedback before increasing exposure. **1. How rollouts work** You start by releasing an update to a small percentage of users and gradually increase it as confidence grows: ```bash Release update → 10% Monitor behavior and stability Increase rollout → 25% Continue monitoring Increase rollout → 50% Finalize rollout → 100% ``` Example release with a rollout: ```bash code-push release-react MyApp-Android android --rollout 25 ``` This publishes an update that is initially delivered to approximately 25% of eligible users (i.e., users running a compatible app version). **2. Updating an existing rollout** You can adjust the rollout percentage without creating a new release using the patch command: ```bash code-push patch MyApp-Android Production --rollout 50 ``` This updates the existing release to be delivered to 50% of users. ### Rollout constraints There are several constraints to be aware of when using rollouts: * **Only one active rollout per deployment:** You cannot have multiple in-progress (partial) rollouts within the same deployment. * **A rollout must reach 100% before a new release can be created:** You need to either complete the rollout or stop it before publishing another update to the same deployment. * **Rollout values must be between 1 and 100:** The percentage must be a whole number within this range. These constraints ensure consistency and prevent conflicts between updates. Allowing multiple partially deployed releases at the same time could result in users receiving different or incompatible versions of the app, making behavior harder to predict and debug. ## Mandatory updates Updates can be marked as **mandatory**. Mandatory updates ensure that users install a specific update before continuing to use the app. This is useful when a release contains critical fixes or breaking changes that must be applied immediately. When an update is marked as mandatory, the app will install it and typically restart automatically, without waiting for user interaction. Example: ```bash code-push release-react --mandatory ``` This marks the update as mandatory, meaning all eligible users will be required to install it. You can also mark an already released update as mandatory using the patch command: ```bash code-push patch --mandatory true ``` Mandatory updates are best reserved for situations such as: * Critical bug fixes (e.g., crashes, data corruption) * Security issues * Breaking API changes * Urgent compliance or legal requirements On the client, **`mandatoryInstallMode`** controls *when* a mandatory update is applied (for example immediately versus on next resume). See [Advanced: sync options](/rn-codepush/advanced-sync-options/). ### Mandatory update propagation The mandatory flag can affect how updates are applied across multiple releases, but it does not literally “propagate” as a property to future releases. Example release sequence: ```bash v1 → optional v2 → mandatory v3 → optional ``` If a user is running **v1** and checks for updates, they will receive **v3**. However, the update will be treated as mandatory because the user has not yet installed the mandatory update **(v2)**. The system ensures that any later update containing those changes is still applied as mandatory. ## Rollbacks Rollbacks allow you to quickly revert users to a previous working update if a release introduces issues. This is a critical safety mechanism that helps minimize the impact of bugs, crashes, or broken functionality in production. There are two types of rollback mechanisms: **automatic and manual** ### Automatic rollback The CodePush client monitors whether an update is successfully applied. After an update is installed, it is considered pending until the app explicitly confirms it as successful (typically by calling **notifyAppReady**). If the app crashes or restarts before confirming the update, the client assumes the update is faulty and automatically rolls back to the previous working version. This prevents users from being stuck with a broken update. ### Manual rollback A manual rollback is triggered by explicitly reverting a release using the CLI: ```bash code-push rollback ``` This disables the latest release and restores the previous stable update for all users in that deployment. > > **📌 Important:** > * Automatic rollback is not based on generic **startup behavior** alone. > It specifically depends on whether the update is confirmed as successful > * You must ensure your app calls: > **notifyAppReady()** (or equivalent). Otherwise, even a healthy update may be rolled back unintentionally > ## Using these controls together In production environments, teams typically combine these controls to reduce risk. Example workflow: ``` release update → 10% rollout monitor crashes and metrics increase rollout gradually mark update mandatory if critical rollback if issues appear ``` This strategy allows teams to: * Limit impact of faulty updates through gradual exposure * Validate stability using real-world data before full release * Enforce critical fixes when necessary * Recover quickly using rollbacks For rollout monitoring and adoption metrics, see [Analytics](/rn-codepush/analytics/). For access control and signing, see [Security and access](/rn-codepush/security-and-access/). For `release-react`, `patch`, and `rollback` syntax, see [CLI quick reference](/rn-codepush/cli-quick-reference/). ================================================================================ source: https://docs.codemagic.io/flutter-testing/ios-provisioning/ title: Registering iOS test devices description: Automatically add new test devices to Apple Developer Portal last_modified: 2026-06-26 ================================================================================ # Registering iOS test devices > Automatically add new test devices to Apple Developer Portal To be able to test iOS builds on physical devices outside TestFlight, e.g. by downloading the app artifact from Slack or a [public link](/yaml-distributing/build-dashboards), the test devices have to be registered in Apple Developer Portal and included in the provisioning profile used for code signing the app. Codemagic enables you to send your trusted testers a device registration link to obtain their device UDIDs and automatically add them to the list of devices in Apple Developer Portal. > > **Note:** This feature is available for [teams](../teams/teams) only. If you are using a personal account, this has to be done manually by [Registering your devices using your Developer Account](https://developer.apple.com/documentation/xcode/distributing-your-app-to-registered-devices#Register-Devices-in-Your-Developer-Account). > > You can also check the [Register Devices](https://help.apple.com/developer-account/#/dev40df0d9fa) section using Your Developer Account. > ## Requirements * You have to be a team admin to manage iOS test devices. * The **Apple Developer Portal integration** must be connected in **Team integrations** to be able to register new devices. This requires creating an App Store Connect API key with **Developer** permissions, see how to create one [here](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). ## Creating a tester group 1. Navigate to **Teams > Your team > iOS test devices**. 2. Click **Create tester group**. A popup window appears with details about the tester group. 3. Enter the **Tester group name**. All the devices registered from this invitation will be added to this group in Codemagic. 4. Select the **Developer Portal API key**. The API key determines under which Apple Developer Portal account the devices will be registered. 5. Then enter the **Tester email addresses** that will receive the device registration link. Note that you can later send new invitations to add more devices to this group. 6. Finally, click **Send registration link**. To add devices to an existing group, find the group in the **Tester groups** section and click **Add new devices**. > > **Note:** It is important to choose the actual bundle identifier when building, and not use any XC Wildcards. Otherwise, the tester group will be unable to install the app and will get the error **_"This app cannot be installed because its integrity could not be verified_**" > ## Device registration Your testers will receive an email with instructions to register a device. The registration link in the email invitation is valid for 7 days. The email contains a QR code and the **Register device** button to download a configuration profile that must be installed on the device. The configuration profile collects the device UDID and forwards it to Codemagic for registration. On successful registration, the device will be added to Apple Developer Portal and listed in the tester group in Codemagic. ## Deleting test devices and groups To delete devices from a tester group, click the pencil icon next to the group to edit it and select the devices to be removed. To delete a tester group, click the bin icon next to the tester group. Deleting the group will also delete all registered devices in the group from Codemagic. Note that deleting a device or a tester group from Codemagic does not remove the devices from Apple Developer Portal. To remove devices from [Apple Developer Portal](https://developer.apple.com/), navigate to **Certificates, Identifiers & Profiles > Devices**, select a device and click **Disable**. ================================================================================ source: https://docs.codemagic.io/yaml-testing/ios-provisioning/ title: Registering iOS test devices description: Automatically add new test devices to Apple Developer Portal last_modified: 2026-06-26 ================================================================================ # Registering iOS test devices > Automatically add new test devices to Apple Developer Portal To be able to test iOS builds on physical devices outside TestFlight, e.g. by downloading the app artifact from Slack or a [public link](/yaml-distributing/build-dashboards), the test devices have to be registered in Apple Developer Portal and included in the provisioning profile used for code signing the app. Codemagic enables you to send your trusted testers a device registration link to obtain their device UDIDs and automatically add them to the list of devices in Apple Developer Portal. > > **Note:** This feature is available for [teams](../teams/teams) only. If you are using a personal account, this has to be done manually by [Registering your devices using your Developer Account](https://developer.apple.com/documentation/xcode/distributing-your-app-to-registered-devices#Register-Devices-in-Your-Developer-Account). > > You can also check the [Register Devices](https://help.apple.com/developer-account/#/dev40df0d9fa) section using Your Developer Account. > ## Requirements * You have to be a team admin to manage iOS test devices. * The **Apple Developer Portal integration** must be connected in **Team integrations** to be able to register new devices. This requires creating an App Store Connect API key with **Developer** permissions, see how to create one [here](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). ## Creating a tester group 1. Navigate to team settings > **iOS test devices**. 2. Click **Create tester group**. A popup window appears with details about the tester group. 3. Enter the **Tester group name**. All the devices registered from this invitation will be added to this group in Codemagic. 4. Select the **Developer Portal API key**. The API key determines under which Apple Developer Portal account the devices will be registered. 5. Then enter the **Tester email addresses** that will receive the device registration link. Note that you can later send new invitations to add more devices to this group. 6. Finally, click **Send registration link**. To add devices to an existing group, find the group in the **Tester groups** section and click **Add new devices**. > > **Note:** It is important to choose the actual bundle identifier when building and not use any XC Wildcards. Otherwise, the tester group will be unable to install the app and will get the error **_"This app cannot be installed because its integrity could not be verified_**" > ## Device registration Your testers will receive an email with instructions to register a device. The registration link in email invitation is valid for 7 days. The email contains a QR code and the **Register device** button to download a configuration profile that must be installed on the device. The configuration profile collects the device UDID and forwards it to Codemagic for registration. On successful registration, the device will be added to Apple Developer Portal and listed in the tester group in Codemagic. ## Deleting test devices and groups To delete devices from a tester group, click the pencil icon next to the group to edit it and select the devices to be removed. To delete a tester group, click the bin icon next to the tester group. Deleting the group will also delete all registered devices in the group from Codemagic. Note that deleting a device or a tester group from Codemagic does not remove the devices from Apple Developer Portal. To remove devices from [Apple Developer Portal](https://developer.apple.com/), navigate to **Certificates, Identifiers & Profiles > Devices**, select a device and click **Disable**. ================================================================================ source: https://docs.codemagic.io/yaml-notification/publish-release-notes/ title: Release notes publishing with codemagic.yaml description: How to publish release notes with successful builds last_modified: 2026-06-26 ================================================================================ # Release notes publishing with codemagic.yaml > How to publish release notes with successful builds Create custom release notes file(s) to notify users of the changes as you publish a new version of your app. Release notes can be published to: * **email**. The release notes will be included in the publishing email of a successful build if you have publishing to email configured in the `publishing` section of your workflow. * **Slack**. The release notes will be included in the Slack notification of a successful build if you have publishing to Slack configured in the `publishing` section of your workflow. * **App Store Connect**. The release notes will be published to the _"What to Test"_ field in the Test Details section in TestFlight if you have publishing to App Store Connect configured in the `publishing` section of your workflow. In case App Store review submission is enabled, then the release notes will be also used to fill in the _"What's New"_ field in the _Version Information_ section in App Store. Note that release notes are uploaded in the [post-processing step](/yaml-publishing/app-store-connect/#post-processing-of-app-store-connect-distribution-magic-actions). * **Google Play**. The release notes will be published to Google Play Console if you have publishing to Google Play configured in the `publishing` section of your workflow. * **Firebase App Distribution**. The release notes will be published to Firebase console if you have publishing to Firebase App Distribution configured in the `publishing` section of your workflow. ## Setting up release notes > > **Warning**: > Apple does not support `<` and `>` symbols in `release_notes` file. Uploading a file with such symbols will cause the App Store Connect API to return `409` error and description that text contains invalid characters. > There are three supported options to set up release notes: ### Single file 1. Create a `release_notes.txt` or `release_notes.json` file for **Play Store** and a `release_notes.json` file for **App Store Connect**. If your workflow is publishing to both the Play Store and the App Store then it is recommended that you use JSON. 2. Add the file to your project working directory, which is either the repository root directory or the `working_directory` specified in the root of your workflow configuration. Codemagic will fetch the content of that file and publish it with the build. * For email, Slack and Firebase it will be published as is. * For Google Play it will be published under `en-US` language localization code. ### One file per language used > > **App Store Connect** supported languages and codes are listed [here](https://developer.apple.com/documentation/appstoreconnectapi/betabuildlocalizationcreaterequest/data/attributes). > > **Google Play Console** supported languages and codes are listed [here](https://support.google.com/googleplay/android-developer/table/4419860?hl=en). > 1. Create a `release_notes_.txt` file for every language used, e.g. `release_notes_en-GB.txt`, `release_notes_it.txt`. 2. Add all of the files to your project working directory, which is either the repository root directory or the `working_directory` specified in the root of your workflow configuration. * Release notes with `en-US` language code will be published to email and Slack in case file with `en-US` language code exists. If not, the first found release notes file will be published. * For both App Store Connect and Google Play, only the release notes with the supported language codes will be published, omitting language codes that are not supported. * It is required to include `What's New` notes for the primary locale while setting up Release notes. ### Single file for multiple languages 1. Create a `release_notes.json` file containing the release notes in all supported languages: ```json [ { "language": "en-GB", "text": "British English release notes text" }, { "language": "en-US", "text": "The US English release notes text" } ] ``` 2. Add this file to your project working directory, which is either the repository root directory or the `working_directory` specified in the root of your workflow configuration. Notes with missing `language` or `text` fields will not be taken into account. * Release notes with `en-US` language code will be published to email, Slack and Firebase, given that an entry with `en-US` language code exists. If not, the first release notes will be published. * For both App Store Connect and Google Play, only the release notes with the supported language codes will be published, omitting language codes that are not supported. * For App Store review submission it is possible to also configure _Promotional Text, Description, Keywords, Support URL_ and _Marketing URL_ in addition to _What's New_ notes via `release_notes.json` file. In order to do so, those fields need to be defined as follows: ```json [ { "language": "en-GB", "text": "British English release notes text", "description": "Updated app description", // Optional for App Store review submission "keywords": "keyword, other keyword", // Optional for App Store review submission "promotional_text": "Promotional text", // Optional for App Store review submission "marketing_url": "https://example.com", // Optional for App Store review submission "support_url": "https://example.com" // Optional for App Store review submission } ] ``` ### Generating release notes with git commits If your Codemagic workflow is triggered when creating a `Git tag`, you may want to automate the process of generating release notes based on your Git commits. You can use the **git log** command to generate release notes with commit messages between two Git tags. Here's how you can do it: ```yaml scripts: name: Generating release notes with git commits script: | git fetch --all --tags prev_tag=$(git for-each-ref --sort=-creatordate --format '%(objectname)' refs/tags | sed -n 2p ) notes=$(git log --pretty=format:"\n- %s" "$prev_tag"..HEAD) echo "$notes" | tee release_notes.txt ``` If you use this script locally, it will generate release notes with all the commits between tags e.g v1.0.0 and v2.0.0 ```json v2.0.0 Fix bug A Fix bug B ``` However, when using Codemagic, you will also need to configure the `CM_CLONE_DEPTH` environment variable. By default, this variable is set to clone only one commit for builds triggered by tags. To capture all commits between tags, e.g. v1.0.0 and v2.0.0, you should set `CM_CLONE_DEPTH` to a value greater than the number of commits between those tags (e.g. 10 or more). This adjustment will ensure that all the commits are captured. In your YAML file, set the value for the CM_CLONE_DEPTH variable under the environment variable section as shown below; ```yaml workflows: workflow-name: environment: vars: CM_CLONE_DEPTH: 5 ``` Keep in mind that setting the CM_CLONE_DEPTH value to a greater number might increase the time it takes to clone the repository during the build, so consider the trade-off between clone depth and build performance. ================================================================================ source: https://docs.codemagic.io/flutter-running-builds/starting-builds-automatically/ title: Starting builds automatically with Flutter workflow editor description: How to setup builds to run on repository events or on schedule last_modified: 2023-01-17 ================================================================================ # Starting builds automatically with Flutter workflow editor > How to setup builds to run on repository events or on schedule In order to fully automate your CI/CD pipeline, you can set up automatic build triggering by configuring which branches to track and when to trigger builds. Build triggers can be configured in **App settings > Build triggers**. Codemagic automatically adds webhooks to the repositories added via GitHub app or from GitHub, GitLab or Bitbucket via the OAuth integration after you have enabled any of the triggers in this section. For repositories added via SSH or HTTP/HTTPS, you would have to [set up webhooks manually](../building/webhooks). Note that webhook triggers might not be supported for all repository providers. ## Build triggers Under **Automatic build triggering**, you can select when to trigger builds. > > **Note:** If you have a `codemagic.yaml` in your repository root, it is automatically used for configuring builds that are triggered in response to the events defined in the file and any configuration in the Flutter workflow editor is ignored. > **Trigger on push**. When checked, a build will be started every time you commit code to any of the tracked branches. **Trigger on pull request update**. When checked, your workflow is run when a pull request is opened or updated to verify the resulting merge commit. * For triggering pull requests, you can specify whether each branch pattern matches the **source** or the **target** branch of the pull request. * If you want to only run tests for pull requests and skip building for platforms, select **Run tests only** under **Build > Build for platforms**. **Trigger on tag creation**. When checked, Codemagic will automatically build the tagged commit whenever you create a tag for this app. Note that the watched branch settings do not affect tag builds. If enabled, you would be able to specify tag patterns to trigger builds. Similarly to **Watched branch patterns**, the first pattern in the list is applied first and each pattern will limit the set of tag labels further. In the case of conflicting patterns, the latter will prevail. Using wildcard symbols is supported, click **Show pattern examples** for more information. **Cancel outdated webhook builds**. When checked, Codemagic will automatically cancel all ongoing and queued builds triggered by webhooks on push or pull request commit when a more recent build has been triggered for the same branch. We recommend enabling this feature when you're making several commits, each of which triggers a build. If you don't enable any automatic build triggers, you can start builds only manually for this workflow. ## Tracking specific branches or tags Instead of watching all branches and tags, you can limit automatic build triggering to branches or tags whose name matches a specific pattern. The branches or tags tracked for building are selected by entering one or more patterns and including or excluding the matching branches or tags. Note that you can either enter the exact name of the branch or tag or use wildcard symbols to match multiple branches or tags. Click **Show pattern examples** in the UI for tips. Additionally, please refer to [Wildcard Match Documentation](https://facelessuser.github.io/wcmatch/fnmatch/) for more advanced matching patterns. The first (i.e. topmost) pattern in the list is applied first. Each following pattern will limit the set of values further. In the case of conflicting patterns, the latter will prevail. You can check the targeted branches by clicking the eye icon next to **Watched branch patterns**. To add a new branch pattern: 1. Navigate to **App settings > Build triggers > Watched branch patterns**. 2. Enter a pattern matching the name of one or more branches in the project. 3. Select **Include** or **Exclude** from the dropdown to limit the set of targeted branches by either including or excluding the matching branches. 4. For **pull request builds**, select whether the tracked branch is the **Source** or the **Target** branch of the pull request. This setting does not affect other types of builds. 5. Click **Add pattern** to save it. You can always edit or delete added patterns. To add a new tag pattern: 1. Navigate to **App settings > Build triggers > Watched tag patterns**. 2. Enter a tag pattern. 5. Click **Add pattern** to save it. You can always edit or delete added patterns. ## Exit or ignore build on certain commit message You can **skip building** automatically triggered workflows by adding `[skip ci]` or `[ci skip]` to your commit message. The workflow will still be started but it will exit without building. If you want to exit a build **when commit message does not include certain string**, then you can add the following script at the top of your scripts section and it will take care of exiting the build or moving forward. In the following example, builds will proceed only if the commit message includes **_buildcd_** string. ```yaml scripts: - name: Exit build if keyword not defined script: | set -e set -x export COMMIT_MSG=$(git log -1 --pretty=%B) echo COMMIT_MSG if [[ $COMMIT_MSG != *"buildcd"* ]] then echo "Commit needs to include 'buildcd' in it's message." exit 1 else echo "Commit message includes 'buildcd', moving forward..." fi ``` ================================================================================ source: https://docs.codemagic.io/yaml-running-builds/starting-builds-automatically/ title: Starting builds automatically with codemagic.yaml description: How to setup builds to run on repository events last_modified: 2026-08-26 ================================================================================ # Starting builds automatically with codemagic.yaml > How to setup builds to run on repository events In order to fully automate your CI/CD pipeline, you can set up automatic build triggering by configuring which branches to track and when to trigger builds. `triggering:` section in `codemagic.yaml` defines the events for automatic build triggering and watched branches. If no events are defined, you can start builds only manually. For repositories added via SSH or HTTP/HTTPS, or if you are configuring your builds using `codemagic.yaml`, you would have to [set up webhooks manually](../building/webhooks). In contrast, when using the Workflow Editor with Flutter, the webhook is added automatically to the repository settings. Note that webhook triggers might not be supported for all repository providers. > > **Note:** The team admin who added the repository can update the webhook by clicking the **Update webhook** button in the Codemagic UI. > ## Build triggers In the `events:` section, specify which events in the repository trigger builds. - **push** - a build will be started every time you commit code to any of the tracked branches. GitHub Merge Queue as a feature helps manage and automate the process of merging multiple pull requests (PRs) into a branch. Merge Queue allows you to automate and serialize merges, making sure that every pull request is tested not in isolation, but as it will be after it’s merged. More information can be found [here](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue). To configure it with Codemagic workflows, a branch name prefixed with *gh-readonly-queue/{base_branch}* needs to be added in **codemagic.yaml** as explained [here](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue#triggering-merge-group-checks-with-third-party-ci-providers) ```yaml triggering: events: - push branch_patterns: - pattern: 'gh-readonly-queue/main/*' ``` - **pull_request** - a build will be started when a pull request is opened or updated to verify the resulting merge commit. For triggering pull requests, you can specify whether each branch pattern matches the **source** or the **target** branch of the pull request. - **pull_request_labeled** - a build will be started every time you add a new label to a **GitHub** pull request. - **tag** - Codemagic will automatically build the tagged commit whenever you create a tag for this app. Note that the watched branch settings do not affect tag builds. If enabled, you would be able to specify `tag_patterns:` to trigger builds. Similarly to **Watched branch patterns**, the first pattern in the list is applied first and each pattern will limit the set of tag labels further. In the case of conflicting patterns, the latter will prevail. Using wildcard symbols is supported. To avoid running builds on outdated commits, you can set `cancel_previous_builds` to automatically cancel all ongoing and queued builds triggered by webhooks on push or pull request commit when a more recent build has been triggered for the same branch. > > **Note:** When starting workflows using webhooks, Codemagic uses the `codemagic.yaml` file from the source branch. If you are triggering builds on Pull requests, make sure the PR source branch has a valid `codemagic.yaml` file. Otherwise, the build will be skipped and the **Recent deliveries** section in **Apps > Webhooks** will show a message similar to _*"Webhook is skipped. There are no workflows configured to run on pull request from 'testing' to 'release'"*_. > ## Tracking specific branches and tags Instead of watching all branches and tags, you can limit automatic build triggering to branches or tags whose name matches a specific pattern. The branches tracked for building are selected by configuring the `branch_patterns` section. The tracked tags can be configured in the `tag_patterns` section. A pattern can match the name of a particular branch or tag. You can use wildcard symbols to create a pattern that matches several branches or tags, see the examples below. Note that for pull request builds, you have to specify whether the watched branch is the source or the target of the pull request. The first (i.e. topmost) pattern in the list is applied first. Each following pattern will limit the set of values further. In the case of conflicting patterns, the latter will prevail. ```yaml triggering: events: # List the events that trigger builds - push - pull_request - pull_request_labeled #GitHub only - tag branch_patterns: # Include or exclude watched branches - pattern: '*' include: true source: true - pattern: excluded-target include: false source: false - pattern: included-source include: true source: true tag_patterns: # Include or exclude watched tag labels - pattern: '*' include: true - pattern: excluded-tag include: false - pattern: included-tag include: true cancel_previous_builds: false # Set to `true` to automatically cancel outdated webhook builds ``` ### Pattern examples | Pattern | Explanation | |-|-| |`*`| Matches everything | |`*-dev`| Matches values with the suffix `-dev`, e.g. `v0.0.42-dev`| |`!(*-dev)`| Matches values without the suffix `-dev`, e.g. `v0.0.42`| |`{test,qa}/*`| Matches values with the prefix `test/` or `qa/`, e.g. `test/popup`| |`v+([0-9]).+([0-9]).+([0-9])`| Matches tags with three numbers, e.g. `v0.0.42`| Please refer to [Wildcard Match Documentation](https://facelessuser.github.io/wcmatch/fnmatch/) for more advanced matching patterns. ## Working with Pull Requests When dealing with pull requests, you have two options: you can either focus on the branch where the proposed changes are made, or you can target the destination branch after the pull request has been merged. **Example 1**. When creating pull requests on the `main` branch from a `feature` branch, which is a way to propose and review changes before they're integrated into `main`, remember to set `source:false` and `pattern:main`. This will ensure that the build runs on the proposed code changes within the `feature` branch when pull request is created or updated. ```yaml triggering: events: - pull_request branch_patterns: - pattern: 'main' include: true source: false ``` **Example 2**. Setting `source:true`, `pattern:main` will trigger the build on the `main` branch once the pull request has been merged from the `feature` branch into the `main` branch. ```yaml triggering: events: - push - pull_request branch_patterns: - pattern: 'main' include: true source: true ``` > > **Note:** The above pattern is set for the `main` branch but you can set similar patterns for any branch depending on your workflow. > **Example 3**. Trigger a build when adding a label to your pull request. ```yaml triggering: events: - pull_request_labeled ``` You will learn later in this page how to add a [condition](#using-condition-inside-when) to filter the added labels. ## Exit or ignore build on certain commit message You can **skip building** automatically triggered workflows by adding `[skip ci]` or `[ci skip]` to your commit message. The workflow will still be started but it will exit without building. If you want to exit a build **when commit message does not include certain string**, then you can add the following script at the top of your scripts section and it will take care of exiting the build or moving forward. In the following example, builds will proceed only if the commit message includes **_buildcd_** string. ```yaml scripts: - name: Exit build if keyword not defined script: | set -e set -x export COMMIT_MSG=$(git log -1 --pretty=%B) echo COMMIT_MSG if [[ $COMMIT_MSG != *"buildcd"* ]] then echo "Commit needs to include 'buildcd' in it's message." exit 1 else echo "Commit message includes 'buildcd', moving forward..." fi ``` ## Using `when` to run or skip builds In addition to [build triggers](#build-triggers) and [branch filtering](#tracking-specific-branches), you can further specify and automate workflow behavior by using `when` keyword to run or skip a build depending on the specified `changeset` and `condition` states. ### Using `changeset` inside `when` By using `changeset` setting, you can avoid unnecessary builds when functional components of your repository were not modified. > > **Note:** After `changeset` setting is configured in `codemagic.yaml`, the subsequent build will be triggered regardless of the condition and only after that successful build, builds will be skipped according to the `changeset` condition. > When using `changeset` filtering, a build will be run if any of the following is true: - `codemagic.yaml` file was modified - watched files/folders have changed **since the last successful build** You should specify the files to watch in `changeset` by using the `includes` and `excludes` keys. ```yaml workflows: sample-workflow: name: Sample App workflow triggering: events: - push when: changeset: includes: - '.' excludes: - '**/*.md' ``` In this case, the build would be skipped if there were changes only to Markdown files `.md`. Both the `includes` and `excludes` keys in `changeset` are *optional*. If the `includes` key is not specified, its value will default to `'.'` (track everything). The `excludes` key defaults to no exclusions. > > **Note:** Adding one or more `includes` keys will disable the default "include all" behavior. Remember to add the `'.'` pattern if needed. > If you use a monorepo, each workflow can be responsible for building a part of your application. Use conditional workflow triggering and specify the path to the application in the changeset as in the example below. ```yaml workflows: build-android: name: Build Android triggering: events: - push when: changeset: includes: - 'android/' ``` As a result, commits with changes outside of the `android` folder will skip a build. > > **Note:** 'Skipping' a build means that the build will be triggered and only after fetching app sources and meeting the **changeset** condition, the build will be stopped. > > > **Note:** The **`codemagic.yaml`** is always included in the changeset by default. > ### Using `condition` inside `when` Use `condition` to run or skip a build depending on the values of environment variables or webhook payload. The `condition` you specify will be evaluated during the build. The build will be skipped if the condition evaluates to `false`. You can use logical operators `==`, `not`, `and`, `or`. Environment variables are available under the `env` variable. You can check [built-in](https://docs.codemagic.io/variables/environment-variables/) or other environment variables. > > **Note:** In when conditions, environment variables must be referenced using the **`env.`** prefix (for example, **`env.ENV_VAR`**). Shell-style references such as **`$ENV_VAR`** are not supported inside the **`when`** block. > Webhook payload is available under the `event` variable. You can check the structure of the webhook payloads that your git provider sends on the **Webhooks** tab in application settings. Note that `event` is not available if the build is started manually from the UI or by a schedule. {{< collapsible title="Webhook payload sample" >}} Here's a JSON payload from GitHub which you can access from the `event` variable. ```json { "action": "labeled", // could be "opened", "synchronize", "reopened", or "ready_for_review" "number": 2, "pull_request": { "url": "https://api.github.com/repos/username/repo/pulls/2", "id": 100000000, "issue_url": "https://api.github.com/repos/username/repo/issues/2", "number": 2, "state": "open", "title": "fix-2", "user": { "login": "username", "id": 100000000, "url": "https://api.github.com/users/username", ... }, "created_at": "2023-10-18T05:27:35Z", "updated_at": "2023-10-18T05:28:21Z", "assignee": null, "assignees": [], "requested_reviewers": [], "requested_teams": [], "labels": [ { "id": 100000000, "url": "https://api.github.com/repos/username/repo/labels/label", "name": "label", "color": "6816E0", "default": false, "description": "" } ], "draft": false, "merged": false, "mergeable": true, "rebaseable": true, "mergeable_state": "clean", "merged_by": null, "comments": 0, "review_comments": 0, "maintainer_can_modify": false, "commits": 1, "additions": 2, "deletions": 4, "changed_files": 1, ... }, "label": { "id": 100000000, "url": "https://api.github.com/repos/username/repo/labels/label", "name": "label", "color": "6816E0", "default": false, "description": "" }, "repository": { "id": 100000000, "name": "repo", "full_name": "username/repo", "private": true, "html_url": "https://github.com/username/repo", "created_at": "2023-10-16T11:24:57Z", "updated_at": "2023-10-16T11:24:57Z", "pushed_at": "2023-10-18T05:27:35Z", "git_url": "git://github.com/username/repo.git", "visibility": "private", "default_branch": "main", ... }, "sender": { "login": "username", "id": 100000000, "url": "https://api.github.com/users/username", "type": "User", ... }, ... } ``` {{< /collapsible >}} **Example 1**. This build will continue if the triggering event was *not* a draft pull request update. In other words, it will skip the build if a pull request is marked as a draft: ```yaml workflows: build: name: Build on PR update triggering: events: - pull_request when: condition: not event.pull_request.draft ``` **Example 2**. Use built-in environment variables in the condition. This build will continue only if the source branch is "master." In other words, it will skip the build if the source branch of the pull request is anything other than "master," regardless of the destination branch. ```yaml workflows: build: name: Build on PR update triggering: events: - pull_request when: condition: env.CM_BRANCH == "master" ``` **Example 3**. This build is triggered on adding a label to a pull request but will continue only if the label added was anything else than "codemagicTest": ```yaml workflows: build: name: Build on PR update triggering: events: - pull_request_labeled when: condition: not event.pull_request.labels[0].name == "codemagicTest" ``` **Example 4**. You can also combine triggering conditions, just make sure that each condition is wrapped in brackets: ```yaml workflows: build: name: Build on PR update triggering: events: - pull_request - pull_request_labeled when: condition: (not event.pull_request.draft) and (not event.pull_request.labels[0].name == "codemagicTest") ``` > > **Note:** Condition expression is evaluated only after cloning the repository so the builds will be started regardless of the `condition`. However, if a `condition` is not met, the build will terminate early and will be marked as `skipped`. > ## Using `when` to run or skip build steps You may want to either run or skip some specific build steps in your workflow when building your application. ```yaml scripts: - name: Run unit tests script: | flutter test when: condition: env.RUN_TEST == "true" ``` Both `changeset` and `condition` are supported for build steps. ================================================================================ source: https://docs.codemagic.io/knowledge-git/access-private-git-submodules/ title: Accessing private dependencies and Git submodules description: How to enable Codemagic to access your private dependencies and Git submodules last_modified: 2026-06-26 ================================================================================ # Accessing private dependencies and Git submodules > How to enable Codemagic to access your private dependencies and Git submodules If your project requires accessing any private Git submodules or dependencies, you'll need to grant Codemagic access to them in order to build successfully. 1. [Create an SSH key pair](../knowledge-git/generating-an-ssh-key) for use with Codemagic. Note that the SSH key **cannot** be password-protected. 2. Add the **public key** to your account settings. See how to do that on [GitHub](https://help.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account), [Bitbucket](https://confluence.atlassian.com/bitbucket/use-access-keys-294486051.html), [GitLab](https://docs.gitlab.com/ee/user/ssh.html). 3. Copy the contents of the **private key** file and add it as an environment variable in the Codemagic UI and import it into your **codemagic.yaml** configuration file. > > **Note:** Make sure the environment variable name ends in `_SSH_KEY`. > 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `MODULE_SSH_KEY`. 3. Copy and paste the key string as **_Variable value_**. 4. Enter the variable group name, e.g. **_module_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - module_credentials ``` All environment variables whose name has the `_SSH_KEY` suffix will be automatically added to the SSH agent and will be ready for use during the whole build process. Check the **Fetching app sources** step in build logs to verify that the key has been successfully added to the SSH agent. > > **Warning:** Do not add an environment variable with the `_SSH_KEY` suffix if your repository was added using a different SSH key. If you do so, the repository's key will be overwritten and it won't be possible to clone the repository. > ### Using multiple SSH keys When you add multiple SSH keys or need to use a different key for private dependencies apart from the one used to clone your repository, git will by default attempt to use the first key available. This may cause problems when installing private dependencies. If you use yaml configuration, explicitly add the key to the SSH agent before invoking a command which requires it, as in the example below. ```yaml scripts: - name: Script that uses an alternative SSH key script: | #!/usr/bin/env bash echo "${CUSTOM_KEY_NAME}" > /tmp/ssh_key chmod 600 /tmp/ssh_key eval `ssh-agent -s` ssh-add /tmp/ssh_key # enter the commands that require the key ``` But if you added a repository with an SSH key and want to use a different key to fetch dependencies, it's not possible to do in Workflow editor. Scripts are executed in independent shells, so the key explicitly added in a post-clone script will be lost as soon as the script finishes. The best thing to do in such a case would be to use the same key for both your repository and your private dependency. You may need to add the key to your account, not to the specific repository. ================================================================================ source: https://docs.codemagic.io/integrations/capgo-integration/ title: Capgo integration description: How to integrate your workflows with Capgo using codemagic.yaml last_modified: 2025-11-19 ================================================================================ # Capgo integration > How to integrate your workflows with Capgo using codemagic.yaml [Capgo](https://capgo.app/) allows you to deploy live updates for Capacitor apps after they have been published to the App Store or Google Play. A sample project that shows how to configure Capgo integration is available [in our Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/capgo_integration_demo_project). ## Configuring Capgo in Codemagic ### Configure environment variables In order to get live updates in your Capgo account via Codemagic, you need to complete the following steps: 1. Sign up with [Capgo](https://capgo.app/) to get your login token 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `CAPGO_TOKEN`. 3. Copy and paste the Capgo token string as **_Variable value_**. 4. Enter the variable group name, e.g. **_capgo_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - capgo_credentials ``` ### Configure your project There are two ways of configuring your Capacitor project with Capgo: automatic and manual. #### Automatic mode Enable it by running the following command with your CAPGO_TOKEN: `npx @capgo/cli init [CAPGO_TOKEN]` #### Manual mode 1. Add the Capgo plugin to your packages `npm i @capgo/capacitor-updater` 2. Modify your Capacitor project by adding the following in your **capacitor.config.json** ```json "plugins": { "CapacitorUpdater": { "autoUpdate": true, "version": "1.0.0" // Bump this number each time you release a native version in the app store } } ``` 2. Inside your main app file (index.tsx), import the following package: ```TypeScript import { CapacitorUpdater } from '@capgo/capacitor-updater' CapacitorUpdater.notifyAppReady() ``` ### Configure `codemagic.yaml` Add the following scripts to your `codemagic.yaml` file to: - upload your project to Capgo Ensure you first install your dependencies and build your JS: ```yaml scripts: - name: Update dependencies and copy web assets to native project script: | npx cap sync - name: Upload to Capgo script: | npx @capgo/cli bundle upload --a $CAPGO_TOKEN ``` When uploading app versions to **Capgo**, executing the following command will submit updates to all users (if production channel is set to public): ```yaml npx @capgo/cli@latest bundle upload -c production ``` As soon as users start installing app versions on their devices, a device list will be visible in the Capgo UI. You can choose any one of them in order to let specific groups of users know about updates shipped with version uploads. ================================================================================ source: https://docs.codemagic.io/knowledge-codemagic/codemagic-cli-tools/ title: Codemagic CLI tools description: How to use Codemagic CLI tools locally or in other environments last_modified: 2026-06-05 ================================================================================ # Codemagic CLI tools > How to use Codemagic CLI tools locally or in other environments [codemagic-cli-tools](https://pypi.org/project/codemagic-cli-tools/) is a set of tools to simplify builds at Codemagic. They can be installed via pip and run locally. ```bash pip3 install codemagic-cli-tools ``` For more information, review the full documentation on [CLI tools](https://github.com/codemagic-ci-cd/cli-tools/tree/master/docs#cli-tools). > > **Note:** Requires: Python ≥ 3.8 > ## Build and code sign an Xcode project To fetch (or create and download) the provisioning profile(s) and certificate for `MY_BUNDLE_ID` app, use the [app-store-connect](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/README.md#app-store-connect) tool. ```bash app-store-connect fetch-signing-files \ --issuer-id ISSUER_ID \ --key-id KEY_IDENTIFIER \ --private-key PRIVATE_KEY \ --certificate-key PRIVATE_KEY \ MY_BUNDLE_ID ``` By default, your certificate will be saved to `$HOME/Library/MobileDevice/Certificates` and the provisioning profile(s) will be saved to `$HOME/Library/MobileDevice/Provisioning Profiles`. Refer to [Signing iOS apps](../code-signing-yaml/signing-ios/) for more information about accessing App Store Connect. To initialize keychain at system default keychain path with empty keychain password and add your `certificate.p12` with certificate password, use the [keychain](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/keychain/README.md#keychain) tool with the following command: ```bash keychain initialize keychain add-certificates --certificate /path/to/certificate.p12 --certificate-password CERTIFICATE_PASSWORD ``` Note that `--certificate` option can be either a path literal, or a glob pattern to match certificates. To use the provisioning profile from `/path/to/profile.mobileprovision` in your Xcode project located at `/path/to/MyProject.xcodeproj` and generate an .ipa archive using scheme `MyScheme`, use [xcode-project](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/README.md#xcode-project) with the following command: ```bash xcode-project use-profiles --project /path/to/MyProject.xcodeproj --profile /path/to/profile.mobileprovision xcode-project build-ipa --project /path/to/MyProject.xcodeproj --scheme MyScheme ``` Note that `--project` option can be either a path literal, or a glob pattern to match projects in the working directory (default is `**/*.xcodeproj`). `--profile` option can be a glob pattern as well (default is `$HOME/Library/MobileDevice/Provisioning Profiles/*.mobileprovision`). ## Generate universal .apk(s) with user-specified keys from the app bundle To build .apk files(s) from the app bundle(s) found with `/path/to/**/*.aab` glob pattern with keystore `/path/to/keystore.keystore`, `KEYSTORE_PASSWORD`, `KEY_ALIAS` and `KEY_PASSWORD`, use the [android-app-bundle](https://github.com/codemagic-ci-cd/cli-tools/tree/master/docs/android-app-bundle#android-app-bundle) tool: ```bash android-app-bundle build-universal-apk \ --bundle '/path/to/**/*.aab' \ --ks /path/to/keystore.keystore \ --ks-pass KEYSTORE_PASSWORD \ --ks-key-alias KEY_ALIAS \ --key-pass KEY_PASSWORD ``` If `--bundle` option is not specified, default glob pattern `**/*.aab` will be used. Please make sure to wrap the pattern in single quotes. > > **Tip:** Instead of entering `ISSUER_ID`, `KEY_IDENTIFIER`, `PRIVATE_KEY`, `CERTIFICATE_PASSWORD`, `KEYSTORE_PASSWORD`, `KEY_PASSWORD` as plaintext, you may specify them using an `@env:` prefix followed by an environment variable name, or `@file:` prefix followed by a path to the file containing the value. Example: `@env:` uses the value in the environment variable named ``, and `@file:` uses the value from file at ``. > > Please refer to the [documentation](https://github.com/codemagic-ci-cd/cli-tools/tree/master/docs#cli-tools) for more details. > ## Generate a changelog text from Git history To generate a changelog text from Git history, use the [git-changelog](https://github.com/codemagic-ci-cd/cli-tools/tree/master/docs/git-changelog#git-changelog) tool. For example, to generate a changelog to `CHANGELOG` file starting from the previous tag, use: ```bash git-changelog generate --previous-commit ${CM_PREVIOUS_COMMIT} \ `git rev-list --tags --skip=1 --max-count=1` > CHANGELOG ``` ================================================================================ source: https://docs.codemagic.io/yaml-distributing/publishing-to-codemagic-static-pages/ title: Codemagic Static Pages description: How to publish a web app to a custom subdomain using Yaml last_modified: 2026-04-01 ================================================================================ # Codemagic Static Pages > How to publish a web app to a custom subdomain using Yaml Publishing to Codemagic static pages is not available when using YAML configuration in Codemagic. If you are building a Flutter project and would like to publish to Codemagic static pages, consider switching your configuration to Flutter workflow editor. ================================================================================ source: https://docs.codemagic.io/troubleshooting/codemagic-status-page/ title: Codemagic status page description: How to get the latest information about the uptime status of Codemagic last_modified: 2024-03-01 ================================================================================ # Codemagic status page > How to get the latest information about the uptime status of Codemagic We post information about the service status, including maintenance and service disruptions on GitHub Discussions [here](https://github.com/orgs/codemagic-ci-cd/discussions). Please use this channel to report issues with the availability of the service. You can also check the status and uptime of the Codemagic web app and build machines on the [Codemagic status page](https://status.codemagic.io/). ================================================================================ source: https://docs.codemagic.io/getting-started/teams/ title: Creating and managing teams description: How to create and manage teams in Codemagic last_modified: 2026-06-05 ================================================================================ # Creating and managing teams > How to create and manage teams in Codemagic If more than one developer is contributing to a project, it is wiser to set up a team to work on the project together. Working in teams comes with some advantages: * One account is used to access the app repository * Team members can jointly configure app settings * Team members have access to build logs, build history and artifacts * Consistent build versioning > **Note:** Teams is a paid feature on Codemagic; see our [pricing page](https://codemagic.io/pricing/). ## Creating a new team To create a new team: 1. Click on the team selector in the navigation and select **Create new team**. 2. Enter a suitable name for your team. 3. Select applications from your personal account to be managed in this team. You can add more applications later. 4. Click **Next: Add payment details**. You will be then asked to add your credit card details and company information (if relevant) to enable billing for the team. 5. Then click **Finish: Create team** to enable billing and continue setting up the team. Once the team has been created, team admins can change the team's name, add or remove shared applications, add or remove users, change user roles and manage billing. ## Managing team applications To add new applications to a team, click **Add application** on the Apps page and select the team to which you wish to add the application. Alternatively, you can transfer existing applications from your personal account by selecting **Personal Account** from left navigation bar and clicking on **Settings** > **Applications** and clicking the transfer icon. > > **Notes on transferring apps to team:** > * Please review the repository settings and team integrations to ensure that your setup is intact and the repository is still accessible after the transfer. Read more about configuring repository access in [team integrations](#managing-team-integrations). > * As Personal accounts and team accounts are two different teams/accounts, iOS and Android code signing identities are not transferred from personal accounts, so please re-adjust workflows that rely on these configurations. To continue working with iOS automatic code signing in the Workflow Editor, you need to re-add the App Store Connect API key (.p8) in your team settings as the API keys are not shared between accounts. Moreover, none of the personal account integrations from your personal account settings > **Integrations** are migrated. > * If you used code signing identities on your personal account, please review any setup related to code signing identities. > * Once an application has been transferred to a team, it cannot be transferred back to the personal account or to other teams. > Deleting an application in team settings removes the app from Codemagic. ## Inviting team members You can invite users to the team by clicking on **Invite team member**. An email invitation will be sent to the user to join the team. If they don't yet have a Codemagic account, they will be asked to register before joining the team. If there are users that have triggered builds but are not yet part of the team in Codemagic, you can click **Add to team** on their email address to send them an invitation. To remove any team members, click on the three dots next to their name and select **Remove user**. ## Managing user roles Users in Codemagic teams can have one of the three roles. * **Admin**. (previously called **Owner**) The user creating a team will become a team admin by default and has full access to all team, app, and repository settings. Other members of the team can be upgraded to admins as well. Admins can select the repositories to be shared with the team, invite new team members, change their roles or remove existing members, including other team admins, manage team integrations and billing. * **Member**. A user with this role has access to the Codemagic UI and can view team settings, configure app settings and trigger new builds. Members cannot modify any team settings, billing details, or repository settings other than the app name. * **User**. Any user that triggers builds from a webhook but does not have access to the team in Codemagic UI. Admins can upgrade members to admins by clicking on the three dots next to their name and selecting **Upgrade to admin**, or downgrade other admins by selecting **Downgrade to member**. Users that have triggered builds can be invited to the team by clicking **Add to team** on the email address in the list of users. ## Build dashboards The build dashboards feature makes it possible to share the team's builds and build artifacts via a public link. Read more about this feature [here](/yaml-distributing/build-dashboards). ## Managing team integrations In Team integrations, it is possible to set up integrations to be used with team apps. Unless team admins have connected an integration in team settings, team creator's credentials are used to access repository information. It is advisable to configure access to the shared repositories on the team level in the **Team integrations** section. Set up an integration with a service where your repositories are hosted by clicking **Connect** next to its name. ## Managing billing Billing is managed separately for your personal account and each team. Read more about billing [here](../billing/billing). ## Leaving the team A team member can leave the team at any time by clicking **Leave team** in the lower part of the page. If the only team admin wants to leave the team, they first have to upgrade another member to the admin role or delete the team completely. ## Deleting the team Only the team admin can delete the team. To do so, scroll down to the **Danger zone** and click **Delete team**. > **Note:** Teams can only be deleted if they are empty (no members or shared applications) and billing has been disabled. ================================================================================ source: https://docs.codemagic.io/yaml-testing/detox-testing/ title: Detox (E2E) test automation description: How to run Detox tests with codemagic.yaml last_modified: 2025-08-22 ================================================================================ # Detox (E2E) test automation > How to run Detox tests with codemagic.yaml Detox testing refers to end-to-end (E2E) testing for React Native apps using the Detox framework. Detox provides a gray box testing solution, meaning it runs tests on a real device or emulator while also accessing the app's internal state for better synchronization. ## Prerequisites 1. A React Native project 2. **npm/yarn** are pre-installed 3. Xcode for iOS and Android Studio for Android are pre-installed 4. **homebrew** is pre-installed > > 🔔 Pre-installed means that Codemagic machines already have the software ready to use, so there is no need to install it manually. > ## Preparing the application Adjust your project's **package.json** file with Detox before starting Codemagic configurations: ```yaml "detox": { "runnerConfig": "e2e/config.json", "configurations": { "ios.sim.release": { "type": "ios.simulator", "device": { "type": "iPhone 14" }, "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/MyReactNativeApp.app", "build": "xcodebuild -workspace ios/YOUR_APP.xcworkspace -scheme YOUR_APP -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build" }, } } ``` More information about Detox environment setup can be found in the official documentation [here](https://wix.github.io/Detox/docs/introduction/environment-setup). ## Running Detox tests in Codemagic We are going to add all the scripts we need to run to install additional software and execute Detox tests to the `scripts` section of `codemagic.yaml`. 1. Install Detox CLI tools and **applesimutils** which is required by Detox to work with iOS simulators: ```yaml npm install detox-cli --global brew tap wix/brew brew install applesimutils ``` 2. Build and run Detox tests: ```yaml detox build --configuration ios.sim.release detox test --configuration ios.sim.release ``` Here is how your **codemagic.yaml** should look like: ```yaml workflows: detox-test: name: Detox test automation environment: node: latest xcode: latest scripts: - name: Install Detox CLI tools script: npm install detox-cli --global - name: Install applesimutils script: | brew tap wix/brew brew install applesimutils - name: Build Detox app script: detox build --configuration ios.sim.release - name: Execute Detox testing script: detox test --configuration ios.sim.release ``` To run this workflow automatically in response to events in the repository, you can additionally configure [automatic build triggering](https://docs.codemagic.io/yaml-running-builds/starting-builds-automatically/). ================================================================================ source: https://docs.codemagic.io/flutter-distributing/firebase-app-distribution/ title: Firebase App Distribution with Flutter workflow editor description: Deploy a Flutter app to Firebase App Distribution using the Flutter workflow editor last_modified: 2026-04-01 ================================================================================ # Firebase App Distribution with Flutter workflow editor > Deploy a Flutter app to Firebase App Distribution using the Flutter workflow editor Set up publishing to [Firebase App Distribution](https://firebase.google.com/docs/app-distribution) to distribute your Android and iOS apps to testers. > > **Note:** This guide only applies to workflows configured with the **Flutter workflow editor**. If your workflow is configured with **codemagic.yaml**, please go to [Publishing an app to Firebase App Distribution](../yaml-distributing/firebase-app-distribution). > ## Requirements - [Add Firebase to your Flutter project](https://firebase.google.com/docs/flutter/setup) - Generate a [Firebase token](https://firebase.google.com/docs/cli#cli-ci-systems) locally or set up a [service account](https://docs.codemagic.io/yaml-distributing/firebase-app-distribution/#requirements) with **Firebase App Distribution Admin** role to authenticate with Firebase App Distribution. - If your app uses Firebase services, you need to upload the Firebase configuration files to Codemagic, see the instructions [here](/knowledge-base/load-firebase-configuration/). - Set up [iOS code signing](../code-signing/ios-code-signing). Note that an Ad Hoc or Enterprise distribution profile is required to distribute the app outside your development team. - Set up [Android code signing](../code-signing/android-code-signing). If you do not set up code signing, the artifact will be signed with a debug keystore from Codemagic build machine. - To authenticate with Firebase, Codemagic requires either a **Firebase token** or a service account with **Firebase App Distribution Admin** role, as shown below: #### 1. Authenticating via service account Using a service account is a more secure option due to granular permission settings. It can also be used to authenticate with various Firebase services, such as Firebase Test Lab and Firebase App Distribution. 1. On the Firebase project page, navigate to **Project settings** by clicking on the cog button. Select the **Service accounts** tab. Click on the **X service accounts** button as shown on the screenshot.

![Firebase service accounts](../uploads/firebase_service_accounts_button.png) 2. This will lead you to the Google Cloud Platform. In step 1, fill in the **Service account details** and click **Create**. The name of the service account will allow you to identify it among other service accounts you may have created. 3. In step 2, click the **Select a role** dropdown menu and choose the role. Note that **Editor** role is required for Firebase Test Lab and **Firebase App Distribution Admin** for Firebase App Distribution. 4. In step 3, you can leave the fields blank and click **Done**. 5. In the list of created service accounts, identify the account you have just created and click on the menu in the **Actions** column, then click **Manage keys**.

![Google cloud key](../uploads/google_cloud_three.png) 6. In the Keys section, click **Add Key > Create new key**. Make sure that the key type is set to `JSON` and click **Create**. Save the key file in a secure location to have it available.

![Google cloud json](../uploads/google_cloud_four.png) #### 2. Authenticating via token > **Warning:** Firebase has marked authentication via token as deprecated and might disable it in future versions of `firebase tool`. Please authenticate using a service account, as described above. > To retrieve your Firebase token, follow the instructions in [Firebase documentation](https://firebase.google.com/docs/cli#cli-ci-systems). ## Enabling publishing to Firebase App Distribution 1. Navigate to **App settings > Distribution > Firebase App Distribution**. 2. Choose either **Firebase token** or **Firebase service account** as the authentication method. 3. Enter the Firebase token or upload the service account JSON key respectively. 4. Provide the **Firebase app ID** for Android and/or iOS. Note that the fields for Android or iOS configuration are displayed conditionally based on the selected build platforms at the top of the page. 5. Enter the alias(es) of the **tester groups** to whom you want to distribute your Android or iOS app. To enter multiple groups, separate them with a comma or a space, or press Enter after each value. 6. For Android, select whether you wish to publish the Android app bundle, the Android APK artifact, or select **Automatic** to publish either the Android app bundle (preferred) or the APK artifact (when no AAB is available). 7. Select **Publish even if tests fail** to upload the artifacts even when one or more tests have failed. 8. Finally, select **Enable publishing to Firebase App Distribution** at the top of the section to enable publishing. > > **Note:** > - If no suitable artifacts are found, publishing to Firebase App Distribution is skipped. > - Each uploaded binary must have a different version to appear in the Firebase console, see how to [increment build version](../building/build-versioning/). > - Release notes can be published with the build if you have added them to your repository, read more [here](./publish-release-notes). > ================================================================================ source: https://docs.codemagic.io/yaml-code-signing/ios-simulator-builds/ title: iOS simulator builds description: How to build an iOS app without code signing to use in simulator last_modified: 2026-06-26 ================================================================================ # iOS simulator builds > How to build an iOS app without code signing to use in simulator To test your app on simulators, Apple requires you to create an unsigned iOS app (with the `.app` extension). ## Building an unsigned native iOS app (.app) For building an unsigned iOS app, please follow the steps outlined in the [Native iOS guide](/yaml-quick-start/building-a-native-ios-app), stopping short of the code signing step. Adjust your build script to use these commands instead: ```yaml scripts: - name: Build the .app script: | # build using workspace xcodebuild build \ -workspace "MyXcodeWorkspace.xcworkspace" \ -scheme "MyScheme" \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=18.0' \ -configuration Debug \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO # # build using project # xcodebuild build \ # -project ""MyXcodeProject.xcodeproj" \ # -scheme "MyScheme" \ # -sdk iphonesimulator \ # -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=18.0' \ # -configuration Debug \ # CODE_SIGN_IDENTITY="" \ # CODE_SIGNING_REQUIRED=NO \ # CODE_SIGNING_ALLOWED=NO ``` Your artifacts will be generated at the default Xcode path. You can access them by adding the following pattern in the `artifacts` section of `codemagic.yaml`: ```yaml artifacts: - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app ``` If you have Xcode Debugging Symbols enabled, the dSYM file will be generated in the same directory as the app and can be accessed with the following artifact pattern: ```yaml artifacts: - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM ``` ## Building an unsigned Maui .NET7 iOS app (.app) Adjust your build script to use these commands: ```yaml scripts: - name: Build the app for iOS Simulator script: | cd MauiNet7 $DOTNET dotnet build -f net7.0-ios -c Debug -o ../artifacts ``` Your artifact will be generated at the default artifacts path. You can access it by adding the following pattern in the `artifacts` section of `codemagic.yaml`: ```yaml artifacts: - ./artifacts/*.app ``` ## Native iOS example The following `codemagic.yaml` file shows a sample workflow that builds a `.zip` archive containing the `.app` file inside. ```yaml workflows: simulator-native-ios: name: iOS simulator build max_build_duration: 120 instance_type: mac_mini_m2 environment: vars: XCODE_WORKSPACE: "your_workspace_name.xcworkspace" XCODE_SCHEME: "your_workspace_name" xcode: latest cocoapods: default scripts: - name: Install CocoaPods dependencies script: | pod install - name: Build the .app script: | xcodebuild build \ -workspace "$XCODE_WORKSPACE" \ -scheme "$XCODE_SCHEME" \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 15 Pro,OS=18.0' \ -configuration Debug \ CODE_SIGN_IDENTITY="" \ CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO artifacts: - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM ``` ## Maui .NET7 example The following `codemagic.yaml` file shows a sample workflow that builds a `.zip` archive containing the `.app` file inside. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/dotnet-maui/dotnet7-maui-unsigned-ios-app). ```yaml workflows: maui-ios-simulator-build: name: Dotnet MAUI iOS Simulator max_build_duration: 120 instance_type: mac_mini_m2 environment: xcode: latest vars: DOTNET_PATH: $CM_BUILD_DIR/dotnet DOTNET: $CM_BUILD_DIR/dotnet/dotnet scripts: - name: Install .NET SDK script: | wget https://dot.net/v1/dotnet-install.sh chmod +x dotnet-install.sh ./dotnet-install.sh --channel 7.0 --install-dir $DOTNET_PATH - name: Add nuget source script: | $DOTNET nuget add source https://www.myget.org/F/caliburn-micro-builds/api/v3/index.json --name CaliburnNuGet.org - name: Install MAUI script: | $DOTNET_BIN nuget locals all --clear $DOTNET workload restore $DOTNET workload install maui-android maui-ios \ --source https://aka.ms/dotnet7/nuget/index.json \ --source https://api.nuget.org/v3/index.json - name: Build the app for iOS Simulator script: | cd MauiNet7 $DOTNET dotnet build -f net7.0-ios -c Debug -o ../artifacts artifacts: - ./artifacts/*.app ``` ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-react-native-app/ title: React Native apps description: How to build a React Native app with codemagic.yaml last_modified: 2026-06-26 ================================================================================ # React Native apps > How to build a React Native app with codemagic.yaml React Native is a cross-platform solution that allows you to build apps for both iOS and Android faster using a single language. Pairing it with Codemagic's CI/CD pipeline creates a powerful tool that automates all phases of mobile app development. ## Setting up a React Native project If you do not have an existing React Native project or if you just want to quickly test Codemagic using a sample project, follow these steps to get started: ### Option: Clone a sample For a quick start, you can clone the appropriate project from our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/react-native) to a version control platform of your choice and proceed with the next steps.   ### Option: New Expo project If you are new to mobile development, the easiest way to get started is with Expo. Expo is a set of tools built around React Native and, while it has many features, the most relevant feature for us right now is that it can get you writing a React Native app within minutes. You will only need a recent version of Node.js and a phone or emulator. The following steps must be completed on your local machine before pushing the repository to Codemagic for building and publishing to the stores: 1. If necessary, install [Node LTS](https://nodejs.org/en/download/). 2. Create a new project ```Shell npx create-expo-app CodemagicSample cd CodemagicSample ``` 3. Configure the Git repository for the app. ### Option: New React Native CLI project" lang="en If you are already familiar with mobile development, you may want to use React Native CLI. It requires Xcode or Android Studio to get started. The required steps are outlined at the [official React Native site](https://reactnative.dev/docs/environment-setup). --- ## Using Expo without prebuild To run a build on CI/CD we need to have the `ios` and `android` project folders. If you can't or don’t want to permanently prebuild Expo from your app, then you can do it on the build server each time you run a build. Follow the steps below to get started. You can check the finished sample app in our [samples repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/blob/main/react-native/expo-react-native-not-ejected/codemagic.yaml). 1. Clone your repository to a temporary new location or create a new branch, in order to prebuild Expo once and get the `android/app/build.gradle` file. 2. Generates native projects by running the following command: ```Shell npx expo prebuild ``` 3. Make sure that `namespace` and `applicationId` under `android{` section in `app/build.gradle` file use the same package name. It will be used as a reference for the `app.json` file. 4. Copy the `android/app/build.gradle` file from the generated project and add it to your main repository. In our example, we create a `support-files` folder and store the `build.gradle` inside. 5. Whenever this guide calls for making changes to the `android/app/build.gradle`, apply these changes to the `support-files/build.gradle` file instead. 6. Follow the steps in other **Expo without prebuild** sections in this guide to install the expo cli tools on the VM, run the scripts to copy the `build.gradle` file to the correct location and use other tools to adjust iOS settings in the `info.plist` file. --- ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. ### Option: Android #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` #### Signing Android apps using Gradle To sign your Android app, simply modify your **`android/app/build.gradle`** or **`android/app/build.gradle.kts`** as follows: %!s() ### Option: build.gradle ```Groovy ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` ### Option: build.gradle.kts ```groovy import java.io.File import java.util.* val keystoreProperties = Properties().apply { var file = File("key.properties") if (file.exists()) load(file.reader()) } plugins { ... } android { ... val appVersionCode = (System.getenv()["NEW_BUILD_NUMBER"] ?: "1")?.toInt() defaultConfig { ... versionCode = appVersionCode ... } signingConfigs { create("release") { if (System.getenv()["CI"].toBoolean()) { // 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 { storeFile = file(keystoreProperties.getProperty("storeFile")) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } } } buildTypes { getByName("release") { isMinifyEnabled = false signingConfig = signingConfigs.getByName("release") } } } dependencies { ... } ``` ### Option: iOS #### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. %!s() ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ##### Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > ## Setting up the Android package name and iOS bundle identifier Configure Android package name and iOS bundle identifier by adding the corresponding variables in the `codemagic.yaml` and editing the `app.json` files. ### Option: Android One very useful method of calculating the code version is to use Codemagic command line tools to get the latest build number from Google Play and increment it by one. You can find the full sample project with the instructions on alternative ways to perform Android build versioning [in our repository](https://github.com/codemagic-ci-cd/android-versioning-example). The prerequisite is a valid **Google Cloud Service Account**. Please follow these steps: 1. Go to [this guide](https://docs.codemagic.io/yaml-publishing/google-play/) and complete the steps in the **Google Play** section. 2. Skip to the **Creating a service account** section in the same guide and complete those steps also. 3. You now have a `JSON` file with the credentials. 4. Open Codemagic UI and create a new Environment variable `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. 5. Paste the content of the downloaded `JSON` file in the **_Value_** field, set the group name (e.g. **google_play**) and make sure the **Secret** option is checked. --- 6. Add the **google_play** variable group to the `codemagic.yaml` ```yaml workflows: android-workflow-id: # .... environment: groups: - google_play ``` 7. Modify the build script to calculate the build number and use it as gradlew arguments. ```yaml scripts: # .... - name: Build Android release script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z $LATEST_GOOGLE_PLAY_BUILD_NUMBER ]; then # fallback in case no build number was found from Google Play. # Alternatively, you can `exit 1` to fail the build # BUILD_NUMBER is a Codemagic built-in variable tracking the number # of times this workflow has been built UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi cd android ./gradlew bundleRelease \ -PversionCode=$UPDATED_BUILD_NUMBER \ -PversionName=1.0.$UPDATED_BUILD_NUMBER ``` 8. Modify the `android/app/build.gradle` file to get the build number values and apply them: ```kotlin // get version code from the specified property argument `-PversionCode` during the build call def getMyVersionCode = { -> return project.hasProperty('versionCode') ? versionCode.toInteger() : -1 } // get version name from the specified property argument `-PversionName` during the build call def getMyVersionName = { -> return project.hasProperty('versionName') ? versionName : "1.0" } .... android { .... defaultConfig { ... versionCode getMyVersionCode() versionName getMyVersionName() ``` %!s() ### Option: iOS In order to get the latest build number from App Store or TestFlight, you will need the App Store credentials as well as the **Application Apple ID**. This is an automatically generated ID assigned to your app and it can be found under **General > App Information > Apple ID** under your application in App Store Connect. 1. Add the **Application Apple ID** to the `codemagic.yaml` as a variable 2. Add the script to get the latest build number using `app-store-connect` and configure the new build number using `agvtool`. 3. Your `codemagic.yaml` will look like this: ```yaml workflows: ios-workflow: name: iOS Workflow integrations: app_store_connect: environment: vars: APP_STORE_APPLE_ID: 1555555551 scripts: - name: Increment build number script: | #!/bin/sh cd $CM_BUILD_DIR LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number "$APP_STORE_APPLE_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build ipa for distribution script: | # build command ``` ## Publishing Codemagic offers a wide array of options for app publishing and the list of partners and integrations is continuously growing. For the most up-to-date information, check the guides in the **Configuration > Publishing** section of these docs. To get more details on the publishing options presented in this guide, please check the [Email publishing](../yaml-publishing/email), the [Google Play Store](../yaml-publishing/google-play) publishing and the [App Store Connect](../yaml-publishing/app-store-connect). #### Email publishing If the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to Google Play and App Store %!s() ### Option: Android Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` %!s() ### Option: iOSCodemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` ## OTA Updates with CodePush Our hosted CodePush service lets you publish OTA updates for React Native projects directly to users' devices, without going through the App Store or Google Play. Read the [concepts page](../rn-codepush/concepts/) for how it works, or the [setup page](../rn-codepush/setup/) to get started. ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: ```yaml workflows: react-native-android: name: React Native Android max_build_duration: 120 instance_type: mac_mini_m2 environment: android_signing: - keystore_reference groups: - google_play vars: PACKAGE_NAME: "io.codemagic.sample.reactnative" scripts: - name: Set Android SDK location script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/android/local.properties" - name: Install npm dependencies script: | npm install - name: Run Expo Prebuild script: | npx expo prebuild - name: Set up app/build.gradle script: | mv ./support-files/build.gradle android/app - name: Build Android release script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z $LATEST_GOOGLE_PLAY_BUILD_NUMBER ]; then # fallback in case no build number was found from google play. Alternatively, you can `exit 1` to fail the build UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi cd android ./gradlew bundleRelease \ -PversionCode=$UPDATED_BUILD_NUMBER \ -PversionName=1.0.$UPDATED_BUILD_NUMBER artifacts: - android/app/build/outputs/**/*.aab publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true react-native-ios: name: React Native iOS max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: codemagic environment: ios_signing: distribution_type: app_store bundle_identifier: io.codemagic.sample.reactnative vars: BUNDLE_ID: "io.codemagic.sample.reactnative" XCODE_WORKSPACE: "CodemagicSample.xcworkspace" # <-- Put the name of your Xcode workspace here XCODE_SCHEME: "CodemagicSample" # <-- Put the name of your Xcode scheme here APP_STORE_APPLE_ID: 1555555551 scripts: - name: Install npm dependencies script: | npm install - name: Run Expo Prebuild script: | npx expo prebuild - name: Set Info.plist values script: | PLIST=$CM_BUILD_DIR/$XCODE_SCHEME/Info.plist PLIST_BUDDY=/usr/libexec/PlistBuddy $PLIST_BUDDY -c "Add :ITSAppUsesNonExemptEncryption bool false" $PLIST - name: Install CocoaPods dependencies script: | cd ios && pod install - name: Set up provisioning profiles settings on Xcode project script: xcode-project use-profiles - name: Increment build number script: | cd $CM_BUILD_DIR/ios LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number "$APP_STORE_APPLE_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "$CM_BUILD_DIR/ios/$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false app_store_connect: auth: integration # Configuration related to TestFlight (optional) # Note: This action is performed during post-processing. submit_to_testflight: true beta_groups: # Specify the names of beta tester groups that will get access to the build once it has passed beta review. - group name 1 - group name 2 # Configuration related to App Store (optional) # Note: This action is performed during post-processing. submit_to_app_store: false ``` ## Next steps While this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/rn-codepush/security-and-access/ title: Security and access description: Authentication and signing for OTA updates last_modified: 2026-05-07 ================================================================================ # Security and access > Authentication and signing for OTA updates CodePush includes several security mechanisms to control who can publish updates and to ensure that apps only install trusted packages. Security is handled in two main areas: - authentication for developers and CI systems - cryptographic signing of OTA update packages These features help protect the update pipeline from unauthorized releases and tampered bundles. --- ## Authentication and access keys Access to the CodePush server is controlled using **access keys**. These keys authenticate the CodePush CLI and any automation that publishes updates. Access keys are typically used in two contexts: - developer machines running the CLI - CI systems that publish updates automatically Example login: ```bash code-push login "https://codepush.pro/" --access-key $ACCESS_TOKEN ``` Once authenticated, the CLI can: * Create and manage apps * Manage deployments * Publish updates * Promote releases between deployments Access keys can be used to authenticate the CLI in automated environments such as CI/CD pipelines. For example, by adding an authentication step in your CI pipeline, the CLI can log in using an access key and then execute subsequent commands automatically: ```bash code-push login "https://codepush.pro" --accessKey $CODEPUSH_TOKEN code-push release-react --deploymentName Production --rollout 10 ``` In this setup: * The CLI authenticates using the access key stored in $CODEPUSH_TOKEN * All following CLI commands run in the authenticated context * No manual login is required This allows automated pipelines to publish updates without requiring an interactive login. For configuring tokens in CI workflows, see [CI integration](/rn-codepush/ci-integration/). For initial setup and CLI authentication, see [Setup](/rn-codepush/setup/). ### Obtaining the access key Users with an active CodePush subscription can manage access keys in Codemagic. To generate an access key, navigate to **OTA Updates** in Codemagic and click **Manage Access Keys** to open a modal. Click **Generate key**, enter an identifier for your key, and select an expiration period. Once generated, the key is displayed only once — copy and store it securely before closing the dialog. ### Revoking the access key You can see your existing access keys in Codemagic by navigating to **OTA Updates** and clicking **Manage Access Keys** to open a modal with available keys. Click **Revoke access** next to the key you want to remove. ## Signing OTA updates In addition to server authentication, CodePush supports **cryptographic signing of update packages**. Signing allows the mobile app to verify that an update was created by a trusted source before installing it. This protects against scenarios where a malicious server or network attack attempts to deliver a modified update. The signing process involves three components: - an RSA key pair - signed update packages - a public key embedded in the mobile app ### How signing works The signing process is based on an RSA key pair and involves three components: * An RSA key pair (private + public key) * Signed update packages generated during release * A public key embedded in the mobile app for verification ### Generate an RSA key pair Before you can sign updates, you must generate an RSA key pair. This produces: * A private key used to sign update packages during the release process * A public key embedded in the mobile application to verify updates at runtime You can generate an RSA key pair using OpenSSL: ```bash # Generate a private key openssl genrsa -out codepush_private.key 2048 # Extract the public key from the private key openssl rsa -in codepush_private.key -pubout -out codepush_public.key ``` - The **private key** is kept securely on your build or CI system - Used to sign update packages during release - Must never be exposed or committed to source control - The **public key** is embedded in the mobile app - Used to verify that updates were signed by a trusted source - Can be safely distributed with the application - **iOS:** add `CodePushPublicKey` in `Info.plist` and string value of public key content. Example: ```bash CodePushPublicKey -----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEy.....== -----END PUBLIC KEY----- ``` - **Android:** add `CodePushPublicKey` string item to `strings.xml`. Example: ```bash my_app -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtPSR9lkGzZ4FR0lxF+ZA....... -----END PUBLIC KEY----- ``` ### Sign update packages Once the RSA key pair is generated, the next step is to configure your build and release process so updates are automatically signed and verified. **1. Store the private key securely** The private key should never be included in the mobile app or committed to source control. Typical secure storage options: * CI/CD secret variables (recommended) * Secure file storage in build pipelines * Dedicated secret managers (e.g., Vault, cloud secrets services) **2. Embed the public key in the mobile app** The public key must be bundled into the app so it can verify updates at runtime. This is usually done by: * Adding it to a configuration file * Embedding it in native code (Android/iOS) * Loading it during app initialization Example: ```bash const codePushConfig = { publicKey: "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----" }; ``` **3. Signing updates during release** When you release an update, the CLI uses the **private key** to generate a cryptographic signature for the update package. ```bash code-push release-react MyApp-Android android \ --privateKeyPath ./codepush_private.key ``` This produces a signed update bundle that includes: * JavaScript bundle * Assets (if any) * Signature generated using the private key ### Verification on the device When the app downloads an update: * The update package is received * The app verifies the signature using the embedded **public key** * If verification succeeds → update is installed * If verification fails → update is rejected ## Security considerations In production environments it is recommended to: - restrict access keys to trusted developers and CI systems - store CI tokens securely using secret management - rotate access keys periodically - protect the private signing key - enable update signing for sensitive applications These practices help ensure that only authorized updates are delivered to users. ================================================================================ source: https://docs.codemagic.io/flutter-configuration/using-environment-variables/ title: Using environment variables with Flutter workflow editor description: How to use environment variables in scripts in Flutter workflow editor last_modified: 2022-11-03 ================================================================================ # Using environment variables with Flutter workflow editor > How to use environment variables in scripts in Flutter workflow editor To access a variable during build time, add the `$` symbol in front of its name. For example, you can access the value of `API_TOKEN` variable by referencing it as `$API_TOKEN`. > > **Note:** It is required to use quotation marks with multi-line variables when you are referencing them in custom scripts. > ## Setting environment variables at build time and accessing them across shell scripts By default, if you define an environment variable inside your script, you can only use it within that particular script itself. However, you can make an environment variable available to any subsequent step of your workflow by writing it to the `CM_ENV` environment file. Specifically, you can do this by writing a `"KEY=value"` pair to the `CM_ENV` environment file. `CM_ENV` can contain multiple environment variables separated by newlines. The following commands show how to write variables to the `CM_ENV` file, depending on the `instance type` of the build machine you are using: ### Option: macOS ```yaml scripts: - name: Save variable to ENV file script: | echo "KEY=value" >> $CM_ENV ``` You can then reference the variable in subsequent parts of your workflow by using `$KEY`. ### Option: Linux ```yaml scripts: - name: Save variable to ENV file script: | echo "KEY=value" >> $CM_ENV ``` You can then reference the variable in subsequent parts of your workflow by using `$KEY`. ### Option: Windows ```yaml scripts: - name: Save variable to ENV file script: | Add-Content -Path $env:CM_ENV -Value "KEY=value" ``` You can then reference the variable in subsequent parts of your workflow by using `$env:KEY`. #### Setting a multiline environment variable To add a multiline environment variable, you need to use `<<` instead of an `=` to mark the end of the key in the key-value pair. In addition, set a delimiter to mark the start and the end of the variable. In the following example, the `DELIMITER` keyword can be replaced by any word of your choice, however, make sure that the delimiter at the beginning and at the end match. ```yaml scripts: - name: Save variable to ENV file script: | echo 'MULTILINE_VAR<> $CM_ENV echo 'line_one\nline_two' >> $CM_ENV echo 'DELIMITER' >> $CM_ENV ``` Note that the example is specific to Linux and macOS machines but the same principles apply when building on Windows. ## Accessing environment variables from apps Environment variables can also be accessed from within your apps. One of the great advantages is that you are able to use sensitive data such as API keys without having to store them in your repository. The following examples show how to place your Google Maps API key into an Android or iOS application from an environment variable. ### Option: Android 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. Reference the environment variable in the `build.gradle` ```Groovy defaultConfig { // Other values set here resValue "string", "maps_api_key", "$System.env.MAPS_API_KEY" } ``` 3. Reference the value from `build.gradle` in the `AndroidManifest.xml` ```xml ``` ### Option: Flutter 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. In the build step, add `--dart-define` to your build script ```yaml scripts: - name: Flutter build ipa script: | flutter build ipa --release \ --dart-define=MAPS_API_KEY=$MAPS_API_KEY ``` 3. Within your Flutter Application, use `String.fromEnvironment` to retrieve these variables in your Dart Code. ```Dart void main() { final secret = String.fromEnvironment('MAPS_API_KEY'); print(secret); } ``` ### Option: iOS (Swift) 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. Reference the environment variable in the `Info.plist` ```xml MAPS_API_KEY $(MAPS_API_KEY) ``` 3. Reference the value from `Info.plist` in the `AppDelegate.swift` ```Swift GMSServices.provideAPIKey(Bundle.main.object(forInfoDictionaryKey: "MAPS_API_KEY") as? String ?? "") ``` ### Option: iOS (Objective-C) 1. Add your key as an environment variable with the name `MAPS_API_KEY` 2. Reference the environment variable in the `AppDelegate.m` as in the following [example](https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner/AppDelegate.m). ```Objective-C [GMSServices provideAPIKey:[[NSProcessInfo processInfo] environment][@"MAPS_API_KEY"]]; ``` ================================================================================ source: https://docs.codemagic.io/knowledge-git/add-a-git-tag-with-app-version/ title: Adding a Git tag with app version description: How to add a Git tag to your apps last_modified: 2025-05-27 ================================================================================ # Adding a Git tag with app version > How to add a Git tag to your apps You can use Codemagic to create a Git tag and push it to your repository. > > **Note:** Pushing Git tags from Codemagic to your repository requires **write access** to the repository. Depending on the Git service and authentication method, Codemagic may not have write access to your repository, and you may need to grant it separately in your Git service settings. We recommend that you create a dedicated app password / personal access token for Codemagic. > > * For repositories hosted on Bitbucket, create an [app password](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html) with **write** permission for repositories. > * For repositories hosted on GitHub, create a [personal access token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) with **repo** scope. > * For repositories hosted on GitLab, create a [personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) with **write_repository** scope. > ## Configure environment variables To allow Codemagic to access your repository, please save the app password or the personal access token in Codemagic. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `APP_PASSWORD`. 3. Enter the value as **_Variable value_**. 4. Enter the variable group name, e.g. **_repo_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - repo_credentials ``` ## Publishing Git tags To create and publish git tags, add the following **pre-publish script**, replacing the placeholders with your actual service details. ```yaml scripts: - name: Push git tags script: | #!/usr/bin/env bash set -e # exit on first failed command set -x # print all executed commands to the log if [ "$CM_BUILD_STEP_STATUS" = "success" ] then new_version=v1.0.$BUILD_NUMBER git tag $new_version git push "https://your-username:$APP_PASSWORD@your-git-service.com/your-repo.git" --tags fi ``` Where: * `BUILD_NUMBER` is the built-in environment variable that holds the total count of builds for this project in Codemagic. * `your-username` is your Git service username * `APP_PASSWORD` is the name of the environment variable that holds your app password / personal access token. * `your-git-service.com` is the name of your Git service, e.g. github.com, bitbucket.com, or gitlab.com. * `your-repo` is the name of your repository Before creating the tag, the script will check if the build was successful. > > **Note:** Make sure to use the `https` repository URL for pushing. Using the `ssh` format is not supported with app passwords or personal access tokens. > ================================================================================ source: https://docs.codemagic.io/flutter-configuration/built-in-variables/ title: Built-in environment variables using Flutter workflow editor description: Useful variables exported during builds using Flutter workflow editor last_modified: 2022-11-03 ================================================================================ # Built-in environment variables using Flutter workflow editor > Useful variables exported during builds using Flutter workflow editor Codemagic exports several built-in environment variables during the build that you can use in scripts to customize the build process. Environment variables added by the user will override Codemagic defaults. You can check which environment variables are exported by inserting the following script before or after any of the default build steps: ```yaml scripts: - name: Set up app/build.gradle script: | #!/bin/sh set -ex printenv ``` Here is a list of the built-in environment variables with brief explanations: | **Environment variable** | **Value** | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ANDROID_SDK_ROOT | Absolute path to Android SDK and tools | | CI | true | | CONTINUOUS_INTEGRATION | true | | BUILD_NUMBER | Number of the build for this project in Codemagic for the given workflow | | PROJECT_BUILD_NUMBER | Number of the build for this project in Codemagic | | FLUTTER_ROOT | Absolute path to Flutter SDK | | CM_BRANCH | The current branch being built, for pull requests it is the source branch | | CM_TAG | The tag being built if started from a tag webhook, unset otherwise | CM_REPO_SLUG | The slug of the repository that is currently being built in the form `owner_name/repository_name`. Unset for repositories added from custom source | | CM_COMMIT | Commit hash that is currently being built by Codemagic, for pull request builds it is the hash of the source commit | | CM_PREVIOUS_COMMIT | Commit hash of the previous successfully built commit in the same branch, (current excluded), unset if there is no previous successful commit | | CM_PULL_REQUEST | `true`, if the current build is building a pull request, `false` otherwise | | CM_PULL_REQUEST_NUMBER | Set to Integer ID of the pull request for the Git provider (Bitbucket, Github etc) if the current build is building a pull request, unset otherwise | | CM_PULL_REQUEST_DEST | The destination branch, if the current build is building a pull request, unset otherwise | | CM_CLONE_DEPTH | Number of commits to be cloned. Overwrites the following defaults: branch builds and destination branch for PR builds - 50, tag builds - 1 | | CM_CLONE_UNSHALLOW | Set `true` to clone full commit history | | CM_RECURSIVE_SUBMODULE_INIT | If set to `false`, recursive submodule cloning is disabled | | CM_PROJECT_ID | UUID of the project that is being built | CM_BUILD_ID | UUID of the build | | CM_TEST_STEP_STATUS | Test step status, success or failure | | CM_BUILD_STEP_STATUS | Build step status, success, failure or skipped. Only available when using Workflow Editor, unavailable with codemagic.yaml | | CM_BUILD_DIR | Absolute path to the root directory of the cloned repository in Codemagic builders | | CM_BUILD_OUTPUT_DIR | Contains the artifact files generated during the build | | CM_EXPORT_DIR | The files added to this directory will be added to a zip file and made available as build artifacts | | CM_FLUTTER_SCHEME | Name of the iOS scheme to be used | | CM_KEYSTORE_PASSWORD | Password of Android keystore as configured in the UI | | CM_KEY_PASSWORD | Password of Android key as configured in the UI | | CM_KEY_ALIAS | Alias of the key as configured in the UI | | CM_KEYSTORE_PATH | Path of the file in our VM | | CM_ARTIFACT_LINKS | Information about generated build artifacts that is available in post-publishing step. Read more about it below. | | CM_WORKFLOW_NAME | Name of the workflow that is currently being built | CM_ENV | Environment file that sets/overrides environment variables at build time | CM_TRIGGER_SOURCE | The source that triggered the build. Possible values are `webhook`, `schedule`, or `api` (started manually from the UI or via the REST API). | CM_BUILD_STARTED_BY | The email of the user who started the build. Used only with builds triggered by `api` (see `CM_TRIGGER_SOURCE`). ### Artifact links `$CM_ARTIFACT_LINKS` environment variable value is a JSON encoded list in the following form: ```json [ { "name": "Codemagic_Release.ipa", "type": "ipa", "url": "https://api.codemagic.io/artifacts/2e7564b2-9ffa-40c2-b9e0-8980436ac717/81c5a723-b162-488a-854e-3f5f7fdfb22f/Codemagic_Release.ipa", "md5": "d2884be6985dad3ffc4d6f85b3a3642a", "versionName": "1.0.2", "bundleId": "io.codemagic.app" } ] ``` ================================================================================ source: https://docs.codemagic.io/rn-codepush/ci-integration/ title: CI integration description: Release updates automatically from CI last_modified: 2026-04-13 ================================================================================ # CI integration > Release updates automatically from CI CodePush updates can be published manually from a developer machine, but many teams choose to release OTA updates from CI pipelines. For a one-page list of CLI commands (including `login` and `release-react`), see [CLI quick reference](/rn-codepush/cli-quick-reference/). Releasing from CI allows updates to be automatically deployed after successful builds, tests, or merges. This makes OTA updates part of the normal delivery workflow. This reduces manual release steps and keeps OTA updates consistent with the rest of your CI/CD process. Typical CI release flow: ```text commit → CI build → tests pass → CodePush release command → update deployed ``` In most cases the CI pipeline runs the same `release-react` command used locally. ```text build succeeds → release-react → update deployed ``` To publish updates from CI, the pipeline must: - [install the CodePush CLI]() - [authenticate using an access token]() - [run the release command]() ## Releasing from Codemagic Codemagic workflows can publish OTA updates by running the CodePush CLI as part of a build step. They use the same commands you would run locally (such as release-react), and there is no separate “dashboard publish” mechanism for OTA releases. A common pattern is to trigger the CodePush release only after a successful build and test phase as shown above. Example step in `codemagic.yaml`: ```bash scripts: - name: Install CodePush CLI script: | npm install -g @codemagic/code-push-cli - name: Release CodePush update script: | code-push login "https://codepush.pro" --accessKey $CODEPUSH_TOKEN code-push release-react MyApp-Android android ``` ``` The pipeline performs the following steps: ```text build app → install CLI tools → authenticate with CodePush → bundle JavaScript → upload update ``` The access token should be stored as a **secure environment variable** in the Codemagic project settings. ## Releasing from GitHub Actions CodePush releases can also be triggered from GitHub Actions or other CI systems. Example GitHub Actions steps: Create a repository secret (for example **`CODEPUSH_TOKEN`**). Without an **`env`** block, `$CODEPUSH_TOKEN` in **`run`** is empty—map the secret as shown, or use `${{ secrets.CODEPUSH_TOKEN }}` in the command instead. ```bash - name: Install CodePush CLI run: npm install -g @codemagic/code-push-cli - name: Release CodePush update env: CODEPUSH_TOKEN: ${{ secrets.CODEPUSH_TOKEN }} run: | code-push login "https://codepush.pro" --accessKey $CODEPUSH_TOKEN code-push release-react MyApp-Android android ``` As with Codemagic, the access token should be stored as a repository secret. ## Choosing when to release OTA updates Teams can choose different strategies for triggering OTA (CodePush) releases depending on their workflow, release frequency, and risk tolerance. **1. Release on every merge to main** In this approach, every change merged into the main branch automatically triggers an OTA release. Typical flow: ```text merge to main → CI build → tests pass → OTA update published ``` **2. Release based on tags or specific commits** Here, OTA updates are only published when a version tag or specific commit is created. Typical flow: ```text tag created (e.g. v1.2.0) → CI build → OTA update published ``` **3. Manual CI-triggered releases** In this model, OTA releases are triggered manually via the CI system. Typical flow: ```text developer triggers pipeline → CI build → OTA update published ``` OTA release strategy is not fixed—teams choose the level of automation based on how often they want to ship and how much control they need over production deployments. ## Best practices When integrating CodePush with CI, it is recommended to: - store access tokens as secure secrets - restrict who can trigger OTA release pipelines - release to **Staging** first and promote to **Production** - monitor update metrics after deployment These practices help ensure that OTA updates are released safely and predictably. ================================================================================ source: https://docs.codemagic.io/yaml-distributing/cloudflare-pages/ title: Cloudflare Pages description: How to deploy a website to Cloudflare Pages using codemagic.yaml last_modified: 2026-04-01 ================================================================================ # Cloudflare Pages > How to deploy a website to Cloudflare Pages using codemagic.yaml [**Cloudflare Pages**](https://pages.cloudflare.com/) is a JAMstack platform for frontend developers to collaborate and deploy websites. ## Configure Cloudflare access Before getting started you will need to create a **Cloudflare API token** and get your **Account ID**. ### Create a Cloudflare API token To create a token: 1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/). 2. Select the user icon on the top right of your dashboard > My Profile. 3. Select [API Tokens](https://dash.cloudflare.com/profile/api-tokens) > Create Token. 4. Select **Use template** next to **Edit Cloudflare Workers**. All templates are prefilled with a token name and permissions. You also need to modify the account and zone resources you want assigned to the token. 5. After editing your token, select **Continue to summary** and review the permissions before selecting create token. 6. Save the generated token for later to store it in Codemagic. ### Get the Account ID From [Cloudflare dashboard](https://dash.cloudflare.com/) select your website and copy the `Account ID` under the **API** section at the right section from the `Overview` page. > > If there is only one account associated with the API token, then the account ID is inferred automatically. > See the official [docs](https://developers.cloudflare.com/workers/wrangler/ci-cd/). ### Configure environment variables 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `CLOUDFLARE_API_TOKEN`. 3. Enter the desired variable value as **_Variable value_**. 4. Enter the variable group name, e.g. **_cloudflare_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to add the `CLOUDFLARE_ACCOUNT_ID`. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - cloudflare_credentials # <-- (Includes CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID) ``` ## Publish to Cloudflare Pages After you have created your page from the [Cloudflare dashboard](https://dash.cloudflare.com/) and given it a name, you can configure automatic publishing in your `codemagic.yaml`. First, we need to install `wrangler`, which is a command-line tool for building with Cloudflare developer products, and then publish our website. Add the following script to your `publishing` section: ```yaml publishing: scripts: - name: Install wrangler script: npm install -g wrangler - name: Deploy to Cloudflare Pages script: | wrangler pages publish --project-name --branch ``` > > You can change the default commit message which is your current git commit message by using `--commit-message "Your commit message"` > If the deployment is complete then you should be able to browse your website using the URL at the last line of the log. ## Flutter web sample workflow Here's a workflow for building a Flutter web application and then publish it to Cloudflare Pages. ```yaml web-workflow: name: Web Workflow instance_type: linux_x2 environment: groups: - cloudflare # <-- (Includes CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID) flutter: stable scripts: - name: Get Flutter packages script: flutter packages pub get - flutter config --enable-web - name: Build Web script: | flutter build web --release - name: Gather the web files script: | cd build/web 7z a -r ../web.zip ./* artifacts: - build/web.zip publishing: scripts: - name: Install wrangler script: npm install -g wrangler - name: Deploy to Cloudflare Pages script: | wrangler pages publish build/web/ --project-name my-flutter-pages --branch production slack: channel: "#builds" notify_on_build_start: true ``` ================================================================================ source: https://docs.codemagic.io/integrations/codecov-integration/ title: Codecov integration description: How to integrate your workflows with Codecov using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Codecov integration > How to integrate your workflows with Codecov using codemagic.yaml [**Codecov**](https://about.codecov.io/) is a dedicated code analysis tool and one of the leading code coverage solutions for mobile applications. It can be used as a part of the Codemagic CI/CD pipeline for code coverage. A sample project that shows how to configure Codecov integration is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/codecov_integration_demo_project). ## Configure Codecov access 1. In order to get a dedicated Codecov token, signing up is required. You can sign up for free [here](https://about.codecov.io/). 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `CODECOV_TOKEN`. 3. Copy and paste the Codecov token string as **_Variable value_**. 4. Enter the variable group name, e.g. **_codecov_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - codecov_credentials ``` ## Collecting test results After writing tests with your test suite you can generate a coverage report using **lcov** and upload that coverage report to **Codecov** directly via **codemagic.yaml**. It is also possible to exit the script if code coverage is lower or higher than the expected threshold. Refer to the sample script below: ```yaml scripts: - name: Create coverage report script: | HOMEBREW_NO_AUTO_UPDATE=1 brew install lcov mkdir -p test-results flutter test --coverage --machine > test-results/flutter.json code_coverage=$(lcov --list $CM_BUILD_DIR/coverage/lcov.info | sed -n "s/.*Total:|\(.*\)%.*/\1/p") echo "Code Coverage: ${code_coverage}% " if (( $(echo "$code_coverage < $CODE_COVERAGE_TARGET" | bc) )) then { echo "code coverage is less than expected" && exit 1; } fi test_report: test-results/flutter.json ``` Codecov accepts **.xml**, **.json**, and **.txt** coverage report formats. You can display test results visually in the build overview by adding them to a path. Just include the **test_report** field with a glob pattern matching the test result file location. More information can be found [here](https://docs.codemagic.io/yaml-testing/testing/). ## Submitting to Codecov Code coverages can be submitted to the Codecov environment through Codemagic using a **cURL** request. Codecov uses a separate upload tool to make it easy to upload coverage reports to Codecov for processing. Depending on the build machine type, add the corresponding script to your `codemagic.yaml` file: ### Option: macOS ```yaml scripts: - name: Codecov upload script: | curl -Os https://uploader.codecov.io/latest/macos/codecov chmod +x codecov ./codecov -t ${CODECOV_TOKEN} ``` ### Option: Linux ```yaml scripts: - name: Codecov upload script: | curl -Os https://uploader.codecov.io/latest/linux/codecov chmod +x codecov ./codecov -t ${CODECOV_TOKEN} ``` ### Option: Windows ```yaml scripts: - name: Codecov upload script: | $ProgressPreference = 'SilentlyContinue' Invoke-WebRequest -Uri https://uploader.codecov.io/latest/windows/codecov.exe -Outfile codecov.exe .\codecov.exe -t ${CODECOV_TOKEN} ``` After successfully uploading code coverage to **Codecov**, line-by-line coverage will be displayed on your GitHub pull requests via GitHub Checks. More information can be found [here](https://about.codecov.io/blog/announcing-line-by-line-coverage-via-github-checks/#:~:text=On%20a%20pull%20request%2C%20simply,right%20side%20of%20the%20annotation). ================================================================================ source: https://docs.codemagic.io/getting-started/faq/ title: FAQ description: Frequently Asked Questions last_modified: 2026-06-26 ================================================================================ # FAQ > Frequently Asked Questions ## Where are the build servers located? Codemagic build servers are all based in the US: - Milwaukee - Phoenix - Las Vegas ## Will Codemagic make permanent changes to my project? Codemagic uses your source control system, such as GitHub, Bitbucket, or Gitlab, to get read-only access to the CI/CD features, such as list branches, set webhooks, get the latest commit information, update commit/PR statuses, etc. Codemagic protects the integrity of your source code and doesn’t alter the code unless you have explicitly specified so in the build scripts. The only exceptions here are some platform-specific files that would have to be modified for successful building. For example, Codemagic modifies the project files for iOS to specify code signing settings during the build and injects a Gradle plugin to the Android component to gather build information and information about the artifacts to be generated. However, all of these changes are temporary and do not alter the source code in your repository. The source code checked out during the build is deleted from the virtual machine after the build and never stored on Codemagic. For a more detailed description, please refer to the [Security statement](https://codemagic.io/security-statement/). ## Is Codemagic really magic or just a clever trick of technology? We can neither confirm nor deny that magic is involved. ## Can I trigger my builds to run automatically? Codemagic offers several options for automating your CI/CD workflow. Builds can be [scheduled](https://docs.codemagic.io/yaml-running-builds/scheduling/) to start at specific times, configured to [trigger automatically](https://docs.codemagic.io/yaml-running-builds/starting-builds-automatically/) on repository events such as Pull requests or tag creation, and they can even be started externally through [REST API](https://docs.codemagic.io/rest-api/builds/) calls. ## Can workflows be scheduled to run at specific times? Yes. To schedule workflows, follow [this guide](https://docs.codemagic.io/yaml-running-builds/scheduling/). ## How many builds can I run concurrently? If you need to run parallel builds you can add additional concurrencies as your needs grow. The [pay-as-you-go](https://docs.codemagic.io/billing/pricing/#pricing-for-teams) plan includes one concurrency to begin with but can be increased to a total of three. The [Annual](https://docs.codemagic.io/billing/pricing/#annual-plan-with-20-discount) plan and [Enterprise](https://docs.codemagic.io/billing/pricing/#enterprise-plan) plans start with three concurrencies and an unlimited number of concurrencies can be added at any time during your subscription period. ## Can I build only the parts of my project that changed? There are multiple ways to fine-tune and customize exactly how and when Codemagic builds are run. Follow [this guide](https://docs.codemagic.io/yaml-running-builds/starting-builds-automatically/#using-when-to-run-or-skip-builds) to configure a workflow to build only when watched files or folders have changed since the last successful build. This is particularly useful if your apps are kept in a mono repo and you want to limit a workflow to build only a single project folder. ## My project needs a specific version of Xcode or dependencies. Can I use non-default versions of these tools? Codemagic allows you a lot of freedom and flexibility in choosing your tools and dependencies. You can check the exact software and hardware specifications of our [Linux](https://docs.codemagic.io/specs/versions-linux/), [macOS](https://docs.codemagic.io/specs/versions-macos/), and [Windows](https://docs.codemagic.io/specs/versions-windows/) build machines. If your project requires a different version of Xcode or some other tool, you can specify that in the [environment](https://docs.codemagic.io/yaml-basic-configuration/yaml-getting-started/#environment) section of your `codemagic.yaml` file. If you are building a Flutter project using Codemagic Workflow Editor, you can select the required versions for Flutter, Xcode, and CocoaPods directly from a dropdown list within the **Build** section. ## Why is my build shown as ‘queued’ and when will it start? Depending on your concurrency settings, you may be able to run up to 3 builds in parallel on the standard plan. If any additional builds are triggered, they will wait in queue for one of the active builds to finish. If you need more than 3 parallel builds, additional concurrencies are available for purchase. Builds can also be queued if there is a temporary spike in network traffic or a hardware issue in one of the data centers. However, these issues are normally resolved in a matter of minutes. Should you experience a longer delay, please contact our support team. ## I have used up my 500 free build minutes. How can I continue using the service? The free build minutes are renewed at the start of each month. However, you can [enable billing](https://docs.codemagic.io/billing/billing/#enabling-billing) at any point and continue using the service at our standard prices in the meantime. ## Our company policy requires that Codemagic register as a vendor with third parties, sign an NDA, or fill out a security questionnaire. Is this possible? If you require any of the listed advanced account services, they are available as part of our Enterprise plan. Find out more about [Enterprise plan benefits](https://codemagic.io/enterprise/). ## Do Teams get 500 free build minutes? Free build minutes are reserved for personal and hobby projects on Personal accounts. ## If I enable Billing for my Personal account, will I still get the 500 free minutes? Yes, you will always receive 500 free build minutes on a Personal account, even if billing is enabled. ## Does it cost extra to build white-label apps? Because of the great freedom it offers in customizing your CI/CD workflows, Codemagic is a great choice for building white-label apps. Whether you want to utilize our REST API or the possibility to configure advanced Bash or Python scripts, Codemagic has you covered out of the box and without any extra costs. ## Can I pay annually and get a discount? Most definitely. The annual subscription grants you 2 months of free usage for the whole plan, including any extra concurrencies. ## What’s an Enterprise plan? The Enterprise plan offers the same superb quality service you have come to expect from Codemagic but enhanced with additional customization options. This plan is recommended if you need to go through a security compliance process, vendor registration or have special requirements such as an NDA, DPA, dedicated hosts, custom base images, or other account management services. Enterprise customers are also able to authenticate using SSO. ## How's a dedicated host different from shared hosts? The common pool operates on shared hardware, where the physical machine resources are shared between two virtual machines. During peak periods, up to two VMs may be deployed on a single host. We actively optimize workload distribution to spread builds evenly across available hardware. However, during periods of high demand, the likelihood of multiple virtual machines sharing the same physical host increases. This can lead to resource contention and, as a result, variability in build performance. Because of this shared model, we cannot guarantee consistent performance at all times. For customers who require predictable and stable performance, dedicated hosts are recommended. In such setups, hardware resources are reserved, and customers can explicitly configure their environment to run a single virtual machine per physical host, eliminating resource contention. ## Where can I find the Codemagic API Token? Each Codemagic user has their own personal API token. There is no shared API token at the team level, so you should always use the token from your personal account, even when working within a team. Navigate to **Account settings > API token** to get your API token. ## How to delete a Codemagic account? If you need to delete your Codemagic account, select **Personal account** in the menu and navigate to **Settings** > **Danger zone** > **Delete account**. However, please note that the deletion will not occur immediately. There is a 14-day grace period before the deletion takes place, during which you have the opportunity to prevent it from happening before the scheduled deletion day. If you need us to delete any chat threads related to your account, please reach out to us, and we will take care of the deletion process for you. ================================================================================ source: https://docs.codemagic.io/knowledge-others/github-checks/ title: GitHub Checks description: How to report PR build statuses to GitHub as checks last_modified: 2026-06-26 ================================================================================ # GitHub Checks > How to report PR build statuses to GitHub as checks > > **Note:** Reporting to GitHub Checks is available for repositories connected via [Codemagic GitHub App](https://github.com/apps/codemagic-ci-cd) integration. > If you have set up [checks](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-status-checks#checks) in GitHub, your workflow build summary will appear in the Checks tab of the pull request in GitHub. For every build on the branch to be merged, Codemagic will report the build summary along with the status and logs of individual build steps to GitHub. Failed checks will block merging the pull request. In case reporting the commit check fails, Codemagic attempts to report commit status. Checks can be set up in GitHub when configuring [branch protection rules](https://docs.github.com/en/github/administering-a-repository/managing-a-branch-protection-rule) for a repository. 1. In Github, open the **Settings** of your repository. 2. In the left menu, click **Branches**. 3. Click **Add rule** to add a new branch protection rule. 4. Enter the name of the branch you want to protect in the **Branch name pattern** field. For example, if you want to require checks on pull requests to the master branch, enter `master`. 5. Under **Protect matching branches**, check **Require status checks to pass before merging**. 6. Select the name of the workflow to add it as a check. Note that the workflow name is listed only if you have already built this workflow in Codemagic. 7. Click **Save changes**. Note that it's not currently possible to rerun failed checks (builds) from GitHub UI. ================================================================================ source: https://docs.codemagic.io/yaml-notification/github-checks/ title: GitHub Checks description: How to report PR build statuses to GitHub as checks last_modified: 2025-10-29 ================================================================================ # GitHub Checks > How to report PR build statuses to GitHub as checks > > **Note:** Reporting to GitHub Checks is available for repositories connected via [Codemagic GitHub App](https://github.com/apps/codemagic-ci-cd) integration. > If you have set up [checks](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-status-checks#checks) in GitHub, your workflow build summary will appear in the Checks tab of the pull request in GitHub. For every build on the branch to be merged, Codemagic will report the build summary along with the status and logs of individual build steps to GitHub. Failed checks will block merging the pull request. In case reporting commit check failed, Codemagic attempts to report commit status. Checks can be set up in GitHub when configuring [branch protection rules](https://docs.github.com/en/github/administering-a-repository/managing-a-branch-protection-rule) for a repository. 1. In Github, open the **Settings** of your repository. 2. In the left menu, click **Branches**. 3. Click **Add rule** to add a new branch protection rule. 4. Enter the name of the branch you want to protect in the **Branch name pattern** field. For example, if you want to require checks on pull requests to the master branch, enter `master`. 5. Under **Protect matching branches**, check **Require status checks to pass before merging**. 6. Select the name of the workflow to add it as a check. Note that the workflow name is listed only if you have already built this workflow in Codemagic. 7. Click **Save changes**. ## Re-running Checks You can re-run failed builds (checks) or all check suite's builds from GitHub UI. ================================================================================ source: https://docs.codemagic.io/yaml-publishing/huawei-appgallery/ title: Huawei AppGallery description: How to deploy an app to Huawei AppGallery using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Huawei AppGallery > How to deploy an app to Huawei AppGallery using codemagic.yaml Codemagic enables you to automatically publish your iOS or Android app to Huawei AppGallery. ## Creating an API Client in Huawei AppGallery An API client is an identity credential used by **AppGallery Connect** to manage user access to AppGallery Connect APIs. Before accessing an API, you must create an API client with the permission for accessing the API. The procedure is as follows: 1. Sign in to [AppGallery Connect](https://developer.huawei.com/consumer/en/service/josp/agc/index.html) and click **Users and permissions**. 2. Go to **API key** > **Connect API** and click **Create**. 3. For **Name**, enter a custom client name. Set **Project** to **N/A**, select the required roles, and click **OK**. > > **Note:** Set Project to N/A to define the API client as a team-level one. Otherwise, the result code 403 will be returned during API calls. > 4. After the client is successfully created, you need to save the **Client ID** and the **Client Secret** (**Key**) to [environment variables](/variables/environment-variable-groups/#storing-sensitive-valuesfiles) in a group named **app_gallery** for example. ## Get the App ID 1. Sign in to [AppGallery Connect](https://developer.huawei.com/consumer/en/service/josp/agc/index.html) and click **My apps** and select your app. 3. Go to **App Information** and save the **App ID** to the environment variables as well in the **app_gallery** environment group. ## App Signing If you want to release your app in App Bundle format `.aab` and use the dynamic delivery feature, you will need to sign your app. You will need to upload the signing key to the Codemagic environment variables so Codemagic can sign your app before publishing it, see the [docs](https://docs.codemagic.io/yaml-code-signing/signing-android/). 1. Go to your app page. 2. Go to **App Signing** tab in the *Services* section. 3. Choose the first option *(Let AppGallery connect create and manage app signature for you)*. 4. After you create your upload key, you need to export a PEM certificate for the new upload key. ```bash $ keytool -export -rfc -keystore YOUR_KEYSTORE.jks -alias upload -file upload_certificate.pem ``` 5. Upload the **upload_certificate.pem** file to AppGallery Connect under the App Signing tab and click **Submit**. ## Adding the Fastlane script to your code First, you need to set up Fastlane in your project by running the `fastlane init` command, see the [docs](https://docs.fastlane.tools/getting-started/android/setup/). Now add this lane to your **Fastfile** file. ```shell lane :huawei do gradle( task: 'bundle', #apk & aab build_type: 'Release', print_command: true, ) huawei_appgallery_connect( client_id: "#{ENV["CLIENT_ID"]}", client_secret: "#{ENV["CLIENT_SECRET"]}", app_id: "#{ENV["APP_ID"]}", apk_path: "./app/build/outputs/bundle/release/app-release.aab", # Optional, Parameter beyond this are optional is_aab: true, submit_for_review: true, delay_before_submit_for_review: 20, ) end ``` ## Publish to the AppGallery store After you set everything up you need to execute the lane from your `codemagic.yaml` file, so add this to your scripts section: ```yaml - name: Publish to the AppGallery store script: | fastlane add_plugin huawei_appgallery_connect bundle install bundle exec fastlane huawei ``` The whole `codemagic.yaml` file should look something like this: ```yaml workflows: android-fastlane: name: Android Fastlane instance_type: linux_x2 environment: groups: - app_gallery # <-- (Includes CLIENT_ID, CLIENT_SECRET, APP_ID) android_signing: - codemagic_test scripts: - chmod +x gradlew - name: Publish to the AppGallery store script: | fastlane add_plugin huawei_appgallery_connect bundle install bundle exec fastlane huawei artifacts: - app/build/outputs/**/**/*.aab ``` ================================================================================ source: https://docs.codemagic.io/knowledge-codemagic/flutter-screenshots-stores/ title: Screenshots description: Generate screenshots for a Flutter app with golden testing and upload them to the stores last_modified: 2026-06-26 ================================================================================ # Screenshots > Generate screenshots for a Flutter app with golden testing and upload them to the stores If you are going to publish your Flutter app to **App Store Connect** or the **Google Play Store**, you can automate the process of taking screenshots and uploading them to the stores so your users can discover your app. In order to strictly follow the steps below, you'll need to use [Riverpod](https://pub.dev/packages/flutter_riverpod) (for dependency injection) and [intl](https://pub.dev/packages/intl) (for internationalization) in your Flutter project. While it might not be necessary for your project, it’s important to keep in mind that, if you want this approach to work, you’ll have to properly separate the UI from the logic in your code, using Riverpod or some other means of dependency injection, so you can easily mock anything you want. ## Automate screenshots generation The screenshots will be generated thanks to golden testing, using the [Golden Toolkit](https://pub.dev/packages/golden_toolkit) package. In the steps below, the screenshots will be illustrated as they are commonly seen in the stores. For each illustrated screenshot, here are the main steps to follow: - You first take a screenshot of the screen you want - You load the generated image using `MemoryImage` - You generate a new Flutter widget with all the needed decorations, texts, backgrounds… to decorate the screenshot - You take a final screenshot of that widget Create a wrapper for the screen, so you'll be able to screenshot it later: ```dart Widget getScreenWrapper({ required Widget child, required Locale locale, required bool isAndroid, List overrides = const [], }) { return ProviderScope( overrides: overrides, child: MaterialApp( debugShowCheckedModeBanner: false, supportedLocales: L10n.all, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], locale: locale, theme: ThemeData( platform: (isAndroid ? TargetPlatform.android : TargetPlatform.iOS), ), home: Column( children: [ Container(color: Colors.black, height: 24), // fake, black and empty status bar Expanded(child: child), ], ), ), ); } ``` The `getScreenWrapper()` function above returns the final screen to screenshot and here are its arguments: - The `child` argument is the screen you want to take a screenshot of. - The `locale` argument is the language you want to use for your screenshot. - The `isAndroid` argument is important here to get a rendering specific to each OS. - The `overrides` argument is useful to mock the logic of your app (database or webservices calls for example). - In that example, we use black for the status bar color, which is actually a basic rectangle. But you can change it to whatever you want. In order to get your fonts working, you’ll need to add the following `flutter_test_config.dart` file in your `test/` directory, with the following content: ```dart import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:golden_toolkit/golden_toolkit.dart'; Future testExecutable(FutureOr Function() testMain) async { TestWidgetsFlutterBinding.ensureInitialized(); await loadAppFonts(); return testMain(); } ``` There are specific requirements for the screenshots sizes. Here are the size and densities that you can use for both the Google Play Store and the App Store Connect: | **Device** | **Screen size** | **Screen density** | | --------------------------------- | ---------------------------------------- | ------------------ | | Android smartphone | `1107 x 1968` | `3` | | 7 inches Android tablet | `1206 x 2144` | `2` | | 10 inches Android tablet | `1449 x 2576` | `2` | | iPad pro 2nd gen | `2048 x 2732` | `2` | | iPad pro 6th gen | `2048 x 2732` | `2` | | iPhone 8 Plus | `1242 x 2208` | `3` | | iPhone Xs Max | `1242 x 2688` | `3` | Note that while the sizes for App Store Connect have to be specifically those sizes, the Google Play Store is more permissive. Also, if you want to display what your app looks like on a tablet, prefer the portrait mode (if it still makes sense for your app, of course), so your users can see more screens on the store without any swipe. When it comes to naming the screenshots files to be uploaded to the stores, you can name them anything you want. But keep in mind that: - They will display in the stores in alphabetical order. - For the App Store Connect, since the two iPads have exactly the same size, we need to differentiate them by naming the iPad pro 6th gen files with a name that should contain `IPAD_PRO_3GEN_129` (other values are possible as you can see in the [deliver documentation](https://docs.fastlane.tools/actions/deliver/)). Now you can take a screenshot of your screen (wrapped with the `getScreenWrapper()` function above), using the [Golden Toolkit](https://pub.dev/packages/golden_toolkit) package: ```dart Future takeScreenshot({ required WidgetTester tester, required Widget widget, required String pageName, required bool isFinal, required Size sizeDp, required double density, CustomPump? customPump, }) async { await tester.pumpWidgetBuilder(widget); await multiScreenGolden( tester, pageName, customPump: customPump, devices: [ Device( name: isFinal ? "final" : "screen", size: sizeDp, textScale: 1, devicePixelRatio: density, ), ], ); } ``` Here are some important notes about the arguments: - The `widget` argument is the widget you want to screenshot. - The `pageName` argument is the name of the image file containing your screenshot. - Since you'll take 2 screenshots per screen (one for the screen itself, another one for the final illustration), you’ll pass `false` for the `isFinal` argument here for the moment. - The `density` argument is the density of the device screen as specified above. - The `sizeDp` argument is the size of the device screen, where its width and height **_have to be divided by the density_**. For example, for the iPhone Xs Max, you’ll pass: `Size(1242 / 3, 2688 / 3)`. - The `customPump` argument, although not mandatory, can be useful in some cases. By default, the [Golden Toolkit](https://pub.dev/packages/golden_toolkit) package uses `pumpAndSettle()`, which can sometimes block the rendering if, for example, there is an infinite animation. In that case, you can pass the following argument (only for the first screenshot): `(tester) async => await tester.pump(const Duration(milliseconds: 200))`. Calling the `takeScreenshot()` function above generates an image file. You can load it into an image widget as follows: ```dart final screenFile = File("test/screenshots/goldens/$pageName.screen.png"); final memoryImage = MemoryImage(screenFile.readAsBytesSync()); final image = Image(image: memoryImage); ``` Now you can decorate your screenshot, using a function like the following that returns a new widget. Note that you might need to pass multiple arguments, including the screen information, depending on what you want to draw: ```dart Widget getDecoratedScreen(Widget image, ...) { return Container( child: ... // draw anything you want ); } ``` You can now take a screenshot of the widget returned by the `getDecoratedScreen()` function above, again with the `takeScreenshot()` function. Note that this time, you shouldn't need to pass anything to the `customPump` argument. Finally, you can delete the first screenshot (the one in `screenFile` above): `screenFile.deleteSync()`. In order to keep your screenshots tests class separated from your other golden tests and unit tests, you may want to do as follows: - Add a tag at the very top of the test class that generates the screenshots, for example `[@Tags]([“screenshots”])`, then generate your illustrations with: `flutter test --update-goldens --tags=screenshots` - In order to launch your other tests without interfering with the screenshots test class, add the following argument to exclude the screenshots tests class: `-x screenshots` One last thing: some screens display a back button in the app bar, but with that method above, that button won’t display. Here is what you can do: - Create a provider: `final platformScreenshotProvider = Provider((ref) => null);` - Even though that provider value is `null` by default, it will be overridden in the golden tests like this: `platformScreenshotProvider.overrideWithValue(isAndroid)`, where `isAndroid` can be `true` or `false` whether you’re on Android or iOS, and which returns an `Override` that you can pass in the `overrides` array argument of the `getScreenWrapper()` function above, like any other override. - Create a fake app bar back icon: ```dart class AppBarBackIcon extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return (ref.read(platformScreenshotProvider) == true ? Icon(Icons.arrow_back_sharp) : Icon(Icons.arrow_back_ios_sharp)); } } ``` - Use that icon for the `leading` argument of the app bar in your app: ```dart leading: (ref.read(platformScreenshotProvider) != null ? const AppBarBackIcon() : null) ``` Note that this provider can be used anywhere in your app, to fake entered text in a `TextFormField` for example. ## Automatically upload screenshots to the stores To upload the screenshots to the stores, we will use the same strategy for both the Google Play Store and the App Store Connect: upload the screenshots while we deploy the app. To achieve that, we will use Fastlane. Fastlane is pre-installed in Codemagic and is a set of open-source tools and scripts that automates building, testing, and deploying mobile apps for both iOS and Android. You can easily install Fastlane on your local machine with the following command: `sudo gem install fastlane`. Once installed, we need to set it up. Open a terminal and go to the root of your Flutter project. ### Android - Go to the `android` directory: `cd android`. - Run the following command: `sudo fastlane init`. - Follow the instructions with the minimum requirements. - At that point, you might need to change the owners of the generated files, since we used `sudo`: ```bash sudo chown your_id fastlane/ sudo chown -R your_id fastlane/* sudo chown your_id Gemfile sudo chown your_id Gemfile.lock ``` - Now, we need an API Key, which is a JSON. Just follow this [short video](https://youtu.be/qrtk6e0BYjM?t=18) to learn how to get that key. Let's name that file `google-play-store.json`. - For testing purposes, we can locally save that file in the `android` directory. But don’t forget to add it in your `.gitignore` file. - Now you can test that Fastlane can communicate with your store with the following command:`fastlane run validate_play_store_json_key json_key:google-play-store.json` - Edit your `Appfile` file so you can update it like the following: ```text # Path to the json secret file, relative to the "android" directory: json_key_file("google-play-store.json") # Package name (actually your application ID): package_name("com.example.app") ``` - Finally, in order to locally get all the current screenshots and metadata with the right files and folders, run: `sudo fastlane supply init`. Here again, you might need to change the owners of the generated files as explained above. ### iOS - Go to the `ios` directory: `cd ios`. - Run the following command: `sudo fastlane init`. - Follow the instructions with the minimum requirements: choose `Manual setup`, and continue. **Be careful not to create an app on App Store Connect at this point**. - Again, you might need to change the owners of the generated files, since we used `sudo`: ```bash sudo chown your_id fastlane/ sudo chown -R your_id fastlane/* sudo chown your_id Gemfile sudo chown your_id Gemfile.lock ``` - Now, we need an API Key, which is a JSON. Let's name that file `app_store_connect.json`, which will look like the following: ```json { "key_id": "D123SF789", "issuer_id": "1234a5cd-12a3-4acb-56dd-123bb1234567", "key": "-----BEGIN PRIVATE KEY-----\n[...]\n-----END PRIVATE KEY-----" } ``` To get the different values, login to the App Store Connect, then go to _My Apps > Users and access > Keys_. Here you can generate a new API Key, whose content will go into `key` in the JSON above. On that same page, you can also find the key ID that you’ve just created, and the Issuer ID that you can find on the top of the list. - For testing purposes, we can locally save that file in the `ios` directory. But don’t forget to add it in your `.gitignore` file. - Edit your `Appfile` file so you can update it like the following: ```text app_identifier("com.example.app") # The bundle identifier of your app apple_id("yourlogin@icloud.com") # Your Apple Developer Portal username itc_team_id("123456789") # App Store Connect Team ID team_id("123A4P567S") # Developer Portal Team ID ``` - In order to locally get all the current screenshots and metadata with the right files and folders, run: `sudo fastlane deliver init --use_live_version true`. Here again, you might need to change the owners of the generated files as explained above. - Finally, if your app does not use encryption, in your `Info.plist` file, add the `ITSAppUsesNonExemptEncryption` key with `false` for its value. ### Flutter Now you can add the following in your `.gitignore` file, at the root of your Flutter project: ```text /android/fastlane/metadata/android/fr-FR/images/ /android/fastlane/metadata/android/en-US/images/ /android/google-play-store.json /ios/fastlane/screenshots /ios/app_store_connect.json ``` Since the `google-play-store.json` and the `app_store_connect.json` files are not meant to be added to your repository, we need to provide them in the workflow in a safe way. With Codemagic, you can for example store the content of the `google-play-store.json` file in a encrypted environment variable named `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`, and run a script in your workflow that will generate the `google-play-store.json` in the right location, with the right content, by doing as follows: ```bash echo $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS > android/google-play-store.json ``` Then in your workflow, you can write a script that copies the generated illustrations in the right directories. For example, here is how you can copy your illustrations for the French Android version of your app: ```bash mkdir -p android/fastlane/metadata/android/fr-FR/images/phoneScreenshots mkdir -p android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots mkdir -p android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots mkdir -p android/fastlane/metadata/android/fr-FR/images/tvScreenshots mkdir -p android/fastlane/metadata/android/fr-FR/images/wearScreenshots cp test/screenshots/goldens/fr.android_smartphone.* android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/ cp test/screenshots/goldens/fr.android_tablet_7.* android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/ cp test/screenshots/goldens/fr.android_tablet_10.* android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/ ``` ### Fastfile One last step: the `Fastfile` files, one for Android, one for iOS, that will each contain the detailed command to deploy everything to each store. Here is what the `Fastfile` file looks like for the Google Play Store (go to the [supply](https://docs.fastlane.tools/actions/supply/) documentation for more information): ```ruby default_platform(:android) platform :android do desc "Deploy app with screenshots to the Google Play Store" lane :deployapp do |options| supply( package_name: "com.example.app", # put your own package name instead aab: "../build/app/outputs/bundle/release/app-release.aab", # check if it's the right path for you skip_upload_apk: "true", skip_upload_aab: "false", skip_upload_metadata: "false", skip_upload_changelogs: "false", skip_upload_images: "false", skip_upload_screenshots: "false", json_key: "google-play-store.json", track: "production", metadata_path: "./fastlane/metadata/android", version_code: options[:versionCode].to_i ) end end ``` And here is what the `Fastfile` file looks like for the App Store Connect (go to the [deliver](http://docs.fastlane.tools/actions/deliver) documentation for more information): ```ruby default_platform(:ios) platform :ios do desc "Deploy app with screenshots to App Store Connect" lane :deployapp do |options| deliver( api_key_path: "./app_store_connect.json", app_version: options[:versionName], ipa: "../build/ios/ipa/mistikee.ipa", submit_for_review: true, skip_binary_upload: false, skip_metadata: false, skip_app_version_update: false, skip_screenshots: false, overwrite_screenshots: true, metadata_path: "./fastlane/metadata", screenshots_path: "./fastlane/screenshots", languages: ['en-US','fr-FR'], # or any other languages according to your needs precheck_include_in_app_purchases: false, force: true, submission_information: { add_id_info_limits_tracking: true, add_id_info_serves_ads: true, # or false, depending on your app having ads or not add_id_info_tracks_action: true, add_id_info_tracks_install: true, add_id_info_uses_idfa: true, content_rights_has_rights: true, content_rights_contains_third_party_content: true, export_compliance_platform: "ios", export_compliance_compliance_required: false, export_compliance_encryption_updated: false, export_compliance_app_type: nil, export_compliance_uses_encryption: false, export_compliance_is_exempt: false, export_compliance_contains_third_party_cryptography: false, export_compliance_contains_proprietary_cryptography: false, export_compliance_available_on_french_store: true } ) end end ``` Now, in your workflow, in order to run the `deployapp` command above for the Google Play Store, you just need to run the following script: ```bash cd android/ fastlane deployapp versionCode:1 # put your own version code here ``` And for the `deployapp` command above for the App Store Connect, here is the script: ```bash cd ios/ fastlane deployapp versionName:"1.0.0" # put your own version name here ``` Note that the App Store Connect might sometimes be buggy when it comes to deleting the previous screenshots. If that operation takes too much time (it should be done in a matter of seconds), don’t hesitate to interrupt the script and run your workflow all over again. ================================================================================ source: https://docs.codemagic.io/flutter-publishing/snap-store/ title: Snapcraft Snap Store description: How to publish a snap to the Snap Store using the Flutter workflow editor last_modified: 2025-02-06 ================================================================================ # Snapcraft Snap Store > How to publish a snap to the Snap Store using the Flutter workflow editor The [snap packages](../flutter-configuration/flutter-projects/#building-snap-packages) you build in Codemagic can be published straight to the [Snapcraft Snap Store](https://snapcraft.io/) as part of the build workflow. 1. Go to **App settings > Distribution > Snapcraft** to configure publishing to the Snapcraft Snap Store. 2. Upload your Snapcraft login credentials file. This can be created by running the following command locally. ```bash snapcraft export-login snapcraft-login-credentials ``` 3. Select a channel for publishing the snap package. 4. Select the **Enable Snapcraft publishing** checkbox to enable publishing to the Snapcraft Snap Store. Now each time you run the workflow on Codemagic, the snap package artifact will be published to the selected channel on Snapcraft. ================================================================================ source: https://docs.codemagic.io/knowledge-git/accessing-git-lfs/ title: Accessing Git LFS description: How to use Git LFS with Codemagic last_modified: 2022-11-03 ================================================================================ # Accessing Git LFS > How to use Git LFS with Codemagic Git Large File Storage (LFS) replaces large files such as audio samples, videos, datasets, and graphics with text pointers inside Git, while storing the file contents on a remote server like GitHub.com or GitHub Enterprise. More info about Git LFS can be found [here](https://git-lfs.github.com/). In order to access Git LFS (an open-source Git extension for versioning large files) during a build, add `git lfs install --skip-smudge` in a post-clone script when working with the Flutter workflow editor and at the very top of the scripts section in the **yaml** file. ```yaml scripts: - name: Install Git LFS script: | git lfs install --skip-smudge ``` ================================================================================ source: https://docs.codemagic.io/flutter-distributing/publishing-to-codemagic-static-pages/ title: Codemagic Static Pages description: How to publish a web app to a custom subdomain using the Flutter workflow editor last_modified: 2026-06-05 ================================================================================ # Codemagic Static Pages > How to publish a web app to a custom subdomain using the Flutter workflow editor You can publish your web app to a custom subdomain of `codemagic.app` for easy access. > > ⚠️ **Note**: This feature is intended for **testing purposes only**. Production apps should be deployed to production-grade web hosting services such as Firebase Hosting or Cloudflare pages. > 1. Go to **App settings > Distribution > Codemagic Static Pages** to configure publishing to Codemagic Static Pages. 2. Choose a subdomain name, make sure to enter only one level, such as **test.codemagic.app**, and enter it in the **Web page subdomain** field. By default, we suggest your app name as the subdomain name. 3. Check **Publish artifacts even if tests fail** to publish the build even when one or more tests fail. Leaving this option unchecked will publish only successful builds that pass the tests, if any. 4. Select **Enable Codemagic Static Pages publishing** at the top of the section to enable publishing. Now each time you run a build of your web app on Codemagic, you'll see the web app artifact being published to the web page in Codemagic logs and can immediately access the app at the specified URL. ================================================================================ source: https://docs.codemagic.io/flutter-configuration/custom-scripts/ title: Custom build steps description: How to execute custom scripts in builds configured with the Flutter workflow editor last_modified: 2023-06-26 ================================================================================ # Custom build steps > How to execute custom scripts in builds configured with the Flutter workflow editor You can customize the Codemagic workflow by running custom scripts before and after the default build steps. In the Flutter workflow editor, the spots for injecting custom scripts are marked by **'+'** signs between the sections. Click on **'+'** to expand the section and add your script in the appropriate section. You can run custom scripts in post-clone, pre-test, post-test, pre-build, post-build, pre-publish and post-publish phases. The scripts can be run in any language, simply define the language with a shebang line. For example, `#!/usr/bin/env python3`. > > Please note that custom scripts are always executed from the absolute path to the cloned repository which is located at `/Users/builder/clone` and can also be accessed using the environment variable `CM_BUILD_DIR`. If your project is not in the repository root and you want to access it from a script, you will need to move to the needed directory inside the script. > Using `codemagic.yaml` for build configuration allows for even greater customization of builds, read more about it [here](../getting-started/yaml). ================================================================================ source: https://docs.codemagic.io/integrations/dcm-integration/ title: Dart Code Metrics integration description: How to integrate your workflows with Dart Code Metrics using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Dart Code Metrics integration > How to integrate your workflows with Dart Code Metrics using codemagic.yaml **Dart Code Metrics** is a powerful static analysis tool that helps improve code quality, ensure code consistency, and identify potential issues early in the development process. ## Configuring Access to Dart Code Metrics To get started with [Dart Code Metrics](https://dcm.dev/), you need an API key and save it as an environment variable in Codemagic. 1. To effectively integrate Dart Code Metrics (DCM) into your Codemagic CI/CD pipeline, it's essential to obtain a [Team Plan API key](https://dcm.dev/pricing/). This key is a crucial component as it authorizes the use of DCM on CI/CD platforms, allowing you to run code analysis as part of your automated workflows. 2. Open your Codemagic app settings, and go to the **Environment variables** tab. 3. Enter the desired **_Variable name_**, e.g. `DCM_KEY`. 4. Copy and paste the API key string as **_Variable value_**. 5. Enter the variable group name, e.g. **_dcm_credentials_**. Click the button to create the group. 6. Make sure the **Secret** option is selected. 7. Click the **Add** button to add the variable. 8. Repeat the above process for `DCM_EMAIL_ID`. 9. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - dcm_credentials ``` ## Configuring DCM Rules with `analysis_options.yaml` Dart Code Metrics (DCM) provides a flexible way to define and enforce coding standards through its rules. These rules are specified in a file named `analysis_options.yaml`, which should be located at the root of your project. By configuring this file, you can tailor DCM to analyze your code according to specific guidelines that align with your project's requirements and coding standards. Here is a sample Rule set. ```yaml dart_code_metrics: metrics: cyclomatic-complexity: 20 number-of-parameters: 4 maximum-nesting-level: 5 metrics-exclude: - test/** rules: - avoid-dynamic - avoid-passing-async-when-sync-expected - avoid-redundant-async - avoid-unnecessary-type-assertions - avoid-unnecessary-type-casts - avoid-unrelated-type-assertions - avoid-unused-parameters - avoid-nested-conditional-expressions ``` You can further customise the Rule set as per your requirements by visiting the Dart Code Metrics documentation at [DCM Rules Documentation](https://dcm.dev/docs/rules/). This page provides a comprehensive list of all available rules along with their descriptions and configuration options. ## Configuring `codemagic.yaml` After setting up your `analysis_options.yaml` file with the desired Dart Code Metrics (DCM) rules, let's configure our `codemagic.yaml` file. ```yaml scripts: - name: install DCM on Codemagic script: | brew tap CQLabs/dcm export HOMEBREW_NO_AUTO_UPDATE=1 brew install dcm - name: Install flutter packages script: flutter pub get - name: Run DCM Analysis with License key script: dcm analyze --ci-key=$DCM_KEY --email=$DCM_EMAIL_ID lib --reporter=console ``` By the end of this configuration process, you will have a fully automated system in place for running Dart Code Metrics analysis within your CI/CD pipeline, enhancing the quality and reliability of your Flutter application. ================================================================================ source: https://docs.codemagic.io/yaml-distributing/github-releases/ title: Github Releases with codemagic.yaml description: How to deploy an app to Github Releases using codemagic.yaml last_modified: 2026-04-01 ================================================================================ # Github Releases with codemagic.yaml > How to deploy an app to Github Releases using codemagic.yaml

> > **Note:** This guide only applies to workflows configured with the **codemagic.yaml**. > ### Some general notes Publishing to GitHub releases is available **only for apps hosted in GitHub repositories**. Also, the publishing happens only for successful builds triggered on tag creation and is unavailable for manual builds. ### Granting access to GitHub In order to enable Codemagic to publish releases to GitHub, you need to grant it write access to your repository. For this, you need to set up a personal access token as described in the [GitHub documentation](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). ### Configuring Codemagic 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `GITHUB_TOKEN`. 3. Enter the token value as **_Variable value_**. 4. Make sure the **Secret** option is selected. 5. Click the **Add** button to add the variable. 6. Include the `GITHUB_TOKEN` variable in your `codemagic.yaml` and configure build triggering on tag creation. Don't forget to add a branch pattern and ensure the webhook exists. ```yaml environment: vars: GITHUB_TOKEN ... triggering: events: - tag branch_patterns: - pattern: '*' include: true source: true ``` 7. Add the following script after the build or publishing scripts. Edit the placeholders like your application name and the build artifacts path to match your setup. ```yaml scripts: - name: Publish to GitHub script: | #!/usr/bin/env zsh # Publish only for tag builds if [ -z ${CM_TAG} ]; then echo "Not a tag build, will not publish GitHub release" exit 0 fi gh release create "${CM_TAG}" \ --title " ${CM_TAG}" \ --notes-file changelog.md \ path/to/build-artifact.ipa \ path/to/build-artifact.apk # Note that you don't need to include title and changelog if you do not want to. # Any number of artifacts can be included with the release. ``` See more options about `gh release create` usage from [GitHub CLI official docs](https://cli.github.com/manual/gh_release_create) ================================================================================ source: https://docs.codemagic.io/rn-codepush/debugging-and-common-issues/ title: Issues and debugging description: Troubleshooting and common failure modes last_modified: 2026-05-15 ================================================================================ # Issues and debugging > Troubleshooting and common failure modes This section covers tools and techniques for diagnosing problems with OTA updates. When an update does not install or behaves unexpectedly, the issue is usually caused by one of the following: - a configuration mismatch - a version targeting problem - an SDK integration issue - a build or bundle error The tools below help identify where the failure occurs. **Optional:** If you use an AI coding assistant, the [Codemagic CodePush Skill](/rn-codepush/setup/#teach-your-ai-assistant-to-use-codepush-optional) will give your assistant knowledge about CodePush setup and troubleshooting. --- ## Debugging OTA updates CodePush provides several ways to inspect and diagnose OTA (over-the-air) update behavior on a device. Effective debugging typically combines: * CLI debugging tools * Device logs * Release metadata (CLI inspection) * Error monitoring tools (via source maps) Understanding how to use these together is key to quickly identifying where an issue occurs. ### CLI debugging tools The CodePush CLI includes a debug command that streams logs from a connected device. Example for Android: ```bash code-push debug android ``` This command uses Android Debug Bridge (adb logcat) to stream logs and automatically filters CodePush-related messages. Requirements (Android): - Android device connected - Android Debug Bridge (`adb`) installed - only one connected device Logs are filtered using the prefix: **[CodePush]** This helps isolate messages related to the update process. Typical log messages include: * Checking for updates * Update found / not found * Download progress * Installation status * Restart triggers * Rollback detection For iOS, logs are collected from the simulator. Requirements: - macOS - iOS simulator running Physical iOS devices are not supported by the CLI debug command. ### Inspecting device logs Even without the CLI debug command, OTA behaviour can be inspected through standard logging tools. Useful tools include: - `adb logcat` for Android - Xcode console logs for iOS Filter logs using: ```bash [CodePush] ``` You can trace the full update lifecycle through logs: ```text check for update download bundle install update restart application ``` If an update fails, the logs usually contain the reason. ### Source maps for error monitoring tools When CodePush releases a new JavaScript bundle, the bundle is compiled and minified. Error monitoring tools such as: - Sentry - Datadog use **source maps** to translate stack traces back to the original source code. Because each OTA update generates a new bundle, the corresponding source maps should also be uploaded to the monitoring tool. If source maps are not uploaded: - stack traces may reference compiled bundle code - debugging production errors becomes much more difficult Most monitoring platforms provide documentation for integrating CodePush releases into their source map upload process. ## Common update failures The following issues are common when releasing CodePush updates. ### Native binary without the CodePush SDK OTA updates only install on native builds that already contain the CodePush SDK. If the SDK was recently added to the project but the store binary users have installed predates that change, `release-react` will publish successfully and the update will appear in the deployment history, but **no client will pick it up** — there is nothing on the device to check the server. Symptoms: - Release shows in `code-push deployment history ` with active installs staying at zero. - No `[CodePush]` log entries appear on device when you open the app, even with good network connectivity. - The issue affects all users, not a subset. Fix: 1. Confirm the SDK is wired up in the React Native project (see [Setup](/rn-codepush/setup/#add-codepush-to-a-react-native-app)). 2. Rebuild the app so the native binary includes the SDK, and install that build on the devices that should receive updates: - **Staging:** a fresh dev or internal-distribution build on your test devices is enough; no store release needed. - **Production:** publish to the App Store / Google Play and wait for users to update. 3. Subsequent `release-react` calls against the matching deployment will then reach those devices over the air. This is a one-time gate per deployment when first adopting CodePush; after devices are on an SDK-enabled binary, the regular OTA flow applies. See [Concepts](/rn-codepush/concepts/#prerequisite-a-native-build-with-the-sdk) for the underlying reason. ### Wrong binary version targeting Updates are only installed if the device's app version satisfies the `targetBinaryVersion` constraint. Example targeting: ```bash --targetBinaryVersion "1.2.x" ``` If the installed app version does not match the specified range, the update will not be delivered. A common mistake is forgetting to update the target version after releasing a new app store build. ### Running the CLI outside the project directory The `release-react` command expects to run inside the root of a React Native project. Required files include: - `package.json` - React Native project structure If the command is executed from another directory, the bundle generation step may fail. ### Incorrect deployment key If the deployment key embedded in the mobile app does not match the intended deployment, the app will check the wrong update channel. Common scenarios include: - development builds using the Production key - production builds using the Staging key - incorrect key in environment configuration This can cause updates to appear missing or install unexpectedly. ### Missing or invalid version metadata The CodePush CLI attempts to automatically detect the app version. On Android, this is usually read from: ```text build.gradle → versionName ``` On iOS, it is read from: ```text Info.plist → CFBundleShortVersionString ``` If these values are missing or not valid semantic versions, the release command may fail. In this case the version can be specified manually with the `targetBinaryVersion` option. ### Missing `notifyAppReady` after a manual update flow If your app **installs an OTA update without** going through the default **`sync()` on startup** path (for example you use **`checkForUpdate`**, then download and **`install()`** yourself), you must call **`notifyAppReady()`** once the new JavaScript bundle has started successfully. If **`notifyAppReady`** never runs, CodePush assumes the update **crashed or failed to boot**. On the **next** app restart the runtime can **roll the app back** to the previous bundle so users are not stuck on a broken release. In practice this looks like “the update installed, then disappeared” or “we keep reverting to the old JS,” which is a frequent source of confusion. The method is also available as **`notifyApplicationReady`** (legacy alias). When you use **`codePush.sync()`** in the usual way—for example wrapping the root component so **`sync`** runs on launch—the client **calls `notifyAppReady` for you** after a successful check path. You only need to think about this when you implement a **custom** update pipeline. For more on **`sync`** and related APIs, see [Advanced: sync options](/rn-codepush/advanced-sync-options/). For **`notifyAppReady`** and other client APIs, use [`@code-push-next/react-native-code-push`](https://www.npmjs.com/package/@code-push-next/react-native-code-push) (README and TypeScript types) as the source of truth. ## When to investigate further If updates still do not install after verifying configuration, the following checks can help narrow the issue: - confirm the device can reach the CodePush server - verify the update appears in the deployment history - confirm the deployment key matches the expected environment - inspect device logs for update installation errors These checks usually identify where the update pipeline is failing. If you need to review the release process, see [Releasing updates](/rn-codepush/releasing-updates/). For installation metrics and failure counts, see [Analytics](/rn-codepush/analytics/). ================================================================================ source: https://docs.codemagic.io/flutter-configuration/moving-wfe-to-yaml/ title: Moving From Workflow Editor to YAML description: How to move from Codemagic Workflow Editor to YAML configuration. last_modified: 2023-10-13 ================================================================================ # Moving From Workflow Editor to YAML > How to move from Codemagic Workflow Editor to YAML configuration. Converting workflow settings to `yaml` cannot be done directly at the moment. Please follow the steps we have included below for moving from Workflow Editor to YAML configuration. 1. Prepare your `codemagic.yaml` file. You can use our sample templates for [iOS](https://github.com/codemagic-ci-cd/codemagic-sample-projects/blob/main/flutter/flutter-android-and-ios-yaml-demo-project/codemagic.yaml#L51) and [Android](https://github.com/codemagic-ci-cd/codemagic-sample-projects/blob/main/flutter/flutter-android-and-ios-yaml-demo-project/codemagic.yaml#L2) workflows for Flutter. You should be able to use it with minimal modifications. 2. If you have added any custom scripts to your Workflow Editor, please make sure to include them as a separate build step in your `codemagic.yaml` file. 3. You need to manually move your secrets and add them to the `Environment variables` section of your YAML configuration. Ensure that this section is ready before you start the process. 4. For all the code-signing related credentials like distribution certificates, provisioning profiles for iOS, and keystores for Android, you will have to add them to the `Code signing identities` section under `Teams > Settings > Code signing identities`. `codemagic.yaml` allows for even greater customization and better control over your builds, read more about it [here](../getting-started/yaml). ================================================================================ source: https://docs.codemagic.io/flutter-distributing/publishing-to-aws/ title: Amazon S3 publishing using Flutter workflow editor description: How to publish a web app to Amazon S3 using Flutter workflow editor last_modified: 2026-04-01 ================================================================================ # Amazon S3 publishing using Flutter workflow editor > How to publish a web app to Amazon S3 using Flutter workflow editor In order to publish your web application to AWS S3: 1. Navigate to your workflow's **Distribution** section. 2. Select `Enable AWS S3 bucket publishing`. 3. Provide the values for `AWS access key ID`, `AWS secret access Key` and `Bucket name`. You can follow the [instructions](https://aws.amazon.com/getting-started/hands-on/backup-to-s3-cli/) provided by Amazon to create your account and get the necessary details. Now, each time you build the workflow, the app artifact will be published to your Amazon S3 bucket. Note that the minimal required permission policy attached to the AWS IAM is as follows: ```json { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::/*" } ] } ``` ================================================================================ source: https://docs.codemagic.io/rn-codepush/codepush-analytics/ title: CodePush analytics description: Installation and usage metrics for OTA updates last_modified: 2026-05-08 ================================================================================ # CodePush analytics > Installation and usage metrics for OTA updates CodePush analytics are available via the dashboard or CLI so you can use the one suitable to your workflow. ## Accessing your metrics ### Dashboard The Codemagic OTA Updates dashboard gives a visual overview of your team's OTA activity. The main page shows team-level totals for the current month: - **Downloads** - total update downloads across all projects - **Installs** - total successful installs across all projects It also includes a time-series chart of succeeded and failed installs, updated hourly. Each project is listed below with its latest release and per-release download, install, and failure counts. Clicking through to a project shows time-series charts for downloads, installs, and failures broken down by release version, with a configurable date range. ### CLI You can view per-release metrics directly in the terminal. | **Metric** | **Description** | | --- | --- | | Active | Number of devices currently running this release | | Total | Total successful installs of this release | | Pending | Downloaded but not yet installed | | Rollbacks | Number of automatic client-side rollbacks | Run the following command to list deployment metrics for an app: ```bash code-push deployment ls ``` The following command shows these metrics for all recent releases in a deployment, which is useful for comparing adoption across versions. ```bash code-push deployment history Production ``` ## Deployment health Analytics can be used to monitor the overall health of a deployment and ensure OTA updates are being delivered and installed correctly. Some of the key indicators are described below. ### Install rates The ratio between downloads and successful installs can indicate whether updates are installing correctly. Example signal: ```text high downloads low installs ``` This may indicate: * Installation failures * Client-side integration issues * App crashes during or after install ### Rollout monitoring When using staged rollouts, analytics help verify how an update spreads across the user base. Example rollout monitoring flow: ```text release → 10% rollout observe installs increase rollout → 25% monitor crash reports increase rollout → 100% ``` If issues appear during rollout, you can: * Adjust rollout percentage using the CLI (e.g. patch) * Roll back the deployment * Pause further exposure until resolved See [Production control](/rn-codepush/production-control/) for more details. ### Failure rates High failure counts may indicate: * Corrupted or invalid bundles * Incompatible updates (version targeting issues) * Client-side integration problems * Runtime crashes triggering automatic rollback Monitoring failures after each release helps teams identify problematic updates quickly. ## Using analytics effectively Analytics are most useful when reviewed after each release to ensure updates are performing as expected. A typical release monitoring process might look like this: ```text release deployed → monitor installs and downloads → track failure rate and crashes → evaluate rollout health → increase rollout or rollback if needed ``` Combining CodePush analytics with external monitoring tools such as crash reporting or error tracking helps teams diagnose issues faster and validate release quality. ================================================================================ source: https://docs.codemagic.io/troubleshooting/common-issues/ title: Common issues description: How to overcome common issues building mobile apps on Codemagic last_modified: 2026-06-26 ================================================================================ # Common issues > How to overcome common issues building mobile apps on Codemagic ### Repository is failing to be cloned from AWS CodeCommit ###### Description Repositories can be added to Codemagic from multiple sources such as Github, Gitlab, Bitbucket, and others. When connecting repositories from AWS CodeCommit via HTTPS, you may get the following error at the fetching app sources step: ``` Cloning into '/home/builder/clone'... fatal: unable to access 'https://git-codecommit.us-west-2.amazonaws.com/v1/repos/my_repo/': The requested URL returned error: 403 Build failed :| Failed to clone repository ``` {{}} ###### Solution It is a known issue with repositories coming from AWS CodeCommit through HTTPS. In order to solve it, try an SSH connection instead, and when adding the repo URL, it needs to look like this: ``` ssh://XXXXXXXX@git-codecommit.us-west-2.amazonaws.com/v1/repos/my_repo.git ``` Please note that the **XXXXXXXXX** refers to your **SSH-Key-ID**. {{< /collapsible >}} ### Cannot access the repository. Request is unauthorized (401) ###### Description When fetching or adding repositories from Github, Gitlab, Bitbucket, and others, you might encounter the below error: ``` "Cannot access the repository. Request is unauthorized (401). Please check your credentials to access ..." ``` or ``` Repository is not accessible. Check access credentials and firewall settings... ``` {{}} ###### Cause This could happen due to many reasons such as: 1. Repository settings were changed 2. Access credentials are not valid e.g. provided SSH key is either expired or malformed or any other reason 3. Repository is behind a firewall and requires IP addresses to be whitelisted 4. OAuth access token should be refreshed ###### Solution The following suggestions can help resolve the issue: 1. Verify that the access credentials e.g. SSH key pairs were added correctly 2. Generally, ensure that the repository access is up to date. You can find more information [here](https://docs.codemagic.io/getting-started/adding-apps/#modifying-access) 3. Confirm that the relevant IP addresses are [whitelisted](https://docs.codemagic.io/getting-started/adding-apps/#firewall-configuration-for-privately-hosted-repositories) 4. Refresh the OAuth integration by going to the **Team integrations** section in team settings and disconnecting and reconnecting the integration. {{< /collapsible >}} ### GitHub Integration - Repositories not showing up in the dropdown ###### Description GitHub repositories won't show up in the dropdown while trying to add an app to Codemagic. {{}} ###### Solution Try disconnecting the GitHub/Bitbucket integration and then connecting it again. 1. Go to your Team settings. 2. Expand Team Integrations 3. Disconnect your GitHub/Bitbucket Integration and then reconnect. {{< /collapsible >}} ### MacOS publishing failed ###### Description ``` The product archive is invalid. The Info.plist must contain a LSApplicationCategoryType key, whose value is the UTI for a valid category. For more details, see "Submitting your Mac apps to the App Store" ``` {{}} ###### Solution Add the and its value in Info.plist file accordingly. ``` LSApplicationCategoryType public.app-category.education ``` {{< /collapsible >}} ### Changing repository for an application ###### Description When migrating from one repository to another, whether from the same provider or not, you may want to preserve the build history, environment variables etc. instead of adding the application again, and potentially losing valuable information. {{}} ###### Solution Add your new repository as an application to Codemagic, then retrieve both old and new application IDs. You can find these IDs in the browser URL after ``app/`` when you open the app in your Codemagic account: ``https://codemagic.io/app/``. Then contact our support team by providing both IDs by specifying which one is which, and we will make the appropriate changes for you. {{< /collapsible >}} ### Flutter build error when using localizations ###### Description You might encounter a Flutter build error when using localizations in your app, as shown below: ```logs Try correcting the name to the name of an existing getter, or defining a getter or field named 'AppLocalizations'. AppLocalizations.of(context)!.helloWorldString ^ ``` {{}} ###### Cause This happens when the required localization files are not generated during the build process. ###### Solution To resolve this issue, include the `flutter gen-l10n` command in your pre-build script, right after `flutter pub get`. This ensures that the necessary localization files are generated before the build process begins. ```bash flutter pub get # Optional if dependencies are already being fetched flutter gen-l10n ``` For more details on setting up localizations, refer to [Flutter's documentation on Localization](https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization#adding-your-own-localized-messages) (Step 6). {{< /collapsible >}} ### App is stuck on splash screen ###### Description The app builds and deploys successfully to Firebase App Distribution and Google Play. However, after downloading it from either source, it fails to open and remains stuck on the splash screen. {{}} ###### Solution This issue is often caused by a mismatch or missing environment variable in your Codemagic configuration. Make sure that all necessary Firebase configuration values like `ANDROID_API_KEY`, `ANDROID_APP_ID`, `SERVICE_ACCOUNT`, `IOS_APP_ID`, `IOS_API_KEY`, or any other required for your use-case, are correctly set as Codemagic environment variables. {{< /collapsible >}} ### Builds initializing for abnormally long time or workflows taking too long to load ###### Description Builds remain in the initializing state for an extended period (sometimes hours) before starting, or workflows take an unusually long time to load. This can happen even after deleting branches from your repository. {{}} ###### Cause The worker takes too long to fetch the YAML configuration due to large repository size. This happens because the repository contains many unpacked objects, loose refs, or needs general housekeeping. Simply deleting branches is not enough as the git history and objects remain in the repository. ###### Solution Clean up your repository using Git housekeeping procedures: **For repositories hosted on platforms like GitHub, GitLab, Bitbucket:** 1. Clone your repository locally 2. Run the following commands: - `git gc` - Cleanup unnecessary files and optimize the local repository ([docs](https://git-scm.com/docs/git-gc)) - `git repack -A` - Pack unpacked objects ([docs](https://git-scm.com/docs/git-repack)) 3. Force push the changes back to your remote repository (if needed) **For self-hosted Git repositories:** Before modifying client-side configurations, perform maintenance on the server side: 1. Log into your git server (e.g., `ssh source.example.com`) 2. Navigate to your repository directory: `cd /path/to/your/repo` 3. Run housekeeping commands: - `git gc` - Cleanup unnecessary files - `git repack -A` - Pack unpacked objects **Additional recommendations:** - For GitLab users, refer to the [housekeeping documentation](https://docs.gitlab.com/ee/administration/housekeeping.html) - Consider implementing regular repository maintenance as part of your workflow - Monitor your repository size and perform cleanup periodically {{< /collapsible >}} ### "Failed to pack new cache" error during builds ###### Description During a build (cleanup step), you may encounter the following error while the cache is being saved: ``` Failed to pack new cache ``` {{}} ###### Solution The most common cause of this error is having duplicate cache paths defined in your workflow configuration. To resolve this: - Review your workflow cache configuration and check for duplicate path entries and ensure the same directory is not listed multiple times. ```yaml workflows: example-workflow: cache: cache_paths: - ~/.gradle/caches - ~/.gradle/caches ``` - Remove any duplicate cache path entries. - Save the workflow configuration and trigger a new build. After removing duplicate cache paths, the build should complete successfully without the caching error. {{< /collapsible >}} ### "User and Invitation emails do not match" error when joining a team ###### Description A user may be able to log in successfully but fail to join a team with the following error: ``` User and Invitation emails do not match ``` This can happen when the email address used for the invitation does not exactly match the email address used during login. {{}} ###### Solution The most common cause of this error is a mismatch in the invited email address, including differences in letter casing. To resolve this: - Verify the email address the invitation was sent to. - Compare it with the email address used to log in. - Ensure both email addresses match exactly. - Casing is important, so even differences in uppercase and lowercase letters will cause a mismatch. Example: ``` Invited: Test@example.com Logged in: test@example.com ``` - If needed, revoke or cancel the incorrect invitation. - Send a new invitation to the exact email address the user uses to log in. - Ask the user to accept the new invitation. After sending an invitation to the matching email address, the user should be able to join the team successfully. {{< /collapsible >}} ================================================================================ source: https://docs.codemagic.io/integrations/discord-integration/ title: Discord integration description: How to integrate your workflows with Discord using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Discord integration > How to integrate your workflows with Discord using codemagic.yaml **Discord** is a free voice, video and text chat application originally built for gamers, but it has since become a general-use platform for many different communities. If your development team uses Discord, it can be used as part of your CI/CD to notify your development team when a build is complete and include information about the build and links to download build artifacts. A sample project that shows how to configure Discord integration is available [in our sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/discord_integration_demo_project). ## Create a Discord account You will need access to a Discord account and can [sign up](https://discord.com/) for free. ## Create a Server and channel in Discord A Server is a dedicated space for your community. A server is required for you to create text channels to talk with people you invite to the server. 1. Log into Discord [here](https://discord.com/login) 2. Click on the **+** button on the left hand menu to create a Server and give it a name and click the **Create** button. 3. Click on the **+** button next to Text Channels. Make sure the channel type is set to **Text channel** and give your channel a name e.g. `codemagic-builds` and then click **Create channel**. 4. Once the channel has been created, click on the channel name to highlight it and then click on the channel's settings icon. 5. Click on **Integrations** and then click **Create webhook** and change the name if you want. 6. Click the **Copy webhook URL** ## Configuring access to Discord in Codemagic One **environment variable** needs to be added to your workflow for the Discord integration: `WEBHOOK_URL` which is the webhook URL you created in the steps above. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `WEBHOOK_URL`. 3. Enter the required value as **_Variable value_**. 4. Enter the variable group name, e.g. **_discord_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - discord_credentials ``` ## Post a message to Discord A cURL request can be used to send a message to your Discord channel with information about your Codemagic builds. The following is an example of how to perform a cURL request that uses your Discord webhook to send a message with a commit number, commit message, branch name, Git commit author and a link to the build artifact. It also adds a file attachment that contains the Git changelog. ```bash curl -H "Content-Type: multipart/form-data" \ -F 'payload_json={"username" : "codemagic-builds", "content": "**Commit:** `'"$COMMIT"'`\n\n**Commit message:** '"$COMMIT_MESSAGE"'\n\n**Branch:** '"$CM_BRANCH"'\n\n**Author:** '"$AUTHOR"'\n\n**Artifacts: **\n\n'"$APP_LINK"'\n\n"}' \ -F "file1=@release_notes.txt" \ $WEBHOOK_URL ``` The below example shows how you can generate a **Changelog** and publish a notification to Discord using scripts in the `codemagic.yaml` file: ```yaml scripts: # ... first perform the steps required to build your project - name: Create a changelog script: | if [[ -z ${CM_PREVIOUS_COMMIT} ]] then echo "No finished builds found to generate changelog" | tee release_notes.txt else echo "$(git-changelog generate --previous-commit $CM_PREVIOUS_COMMIT)" | tee release_notes.txt fi artifacts: # ... publishing: scripts: - name: Discord notification script: | set -ex APP_LINK=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name=="app.apk") | .url') # Get first 7 digits of commit number COMMIT=$(echo "${CM_COMMIT}" | sed 's/^\(........\).*/\1/;q') # Get commit message COMMIT_MESSAGE=$(git log --format=%B -n 1 $CM_COMMIT) # Get commit author AUTHOR=$(git show -s --format='%ae' $CM_COMMIT) # Publish the notification curl -H "Content-Type: multipart/form-data" \ -F 'payload_json={"username" : "codemagic-bot", "content": "**Commit:** `'"$COMMIT"'`\n\n**Commit message:** '"$COMMIT_MESSAGE"'\n\n**Branch:** '"$CM_BRANCH"'\n\n**Author:** '"$AUTHOR"'\n\n**Artifacts: **\n\n'"$APP_LINK"'\n\n"}' \ -F "file1=@release_notes.txt" \ $WEBHOOK_URL ``` The result will look similar to this: ![A formatted Discord message](https://github.com/codemagic-ci-cd/codemagic-sample-projects/raw/main/integrations/discord_integration_demo_project/discord-message.png) ## Environment variables in JSON If you want to use an environment variable within your message use single quotes and double quotes within the JSON value as follows (note that the additional backticks will format it as code in Discord): ```json "content": "**Commit:** `'"$COMMIT"'`" ``` ================================================================================ source: https://docs.codemagic.io/knowledge-others/import-variables-from-secret-manager/ title: Importing variables from a secret manager description: How to import variables and secrets from third party services and use them with Codemagic last_modified: 2026-06-26 ================================================================================ # Importing variables from a secret manager > How to import variables and secrets from third party services and use them with Codemagic Codemagic allows you to add encrypted secrets and variables in the UI which can be used during your workflow. You can find out more about storing sensitive values in Codemagic [here](https://docs.codemagic.io/variables/environment-variable-groups/#storing-sensitive-valuesfiles) However, it is possible to use third-party secret managers in your pipelines. In order to do this, you will need to override environment variables defined in your `codemagic.yaml` configuration file during the build as explained [here](https://docs.codemagic.io/variables/using-environment-variables/#setting-environment-variables-during-the-build) ## AWS Secrets Manager The following steps illustrate how to use AWS Secrets Manager with Codemagic. #### Configure AWS Environment access You will need to configure the environment variables `AWS_DEFAULT_REGION` , `AWS_SECRET_ACCESS_KEY` , and `AWS_ACCESS_KEY_ID` in the Codemagic UI. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `AWS_DEFAULT_REGION`. 3. Enter the variable value as **_Variable value_**. 4. Enter the variable group name, e.g. **_aws_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to also add `AWS_SECRET_ACCESS_KEY` and `AWS_ACCESS_KEY_ID` variables. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - aws_credentials ``` #### Storing a secret in AWS Secrets Manager Make sure that any secrets you store are in the same region as your AWS config file. 1. Log into your AWS account and search for **Secrets Manager** 2. Use the drop list at the top right to select the region that corresponds with the Default region you set in your environment variables. 3. Click on the **Store a new secret** button. 4. Set the secret type to **Other type of secret**. 5. In the *Key/value* pairs section select **Plain text** and delete any placeholder text. 6. Paste in the secret you would like to store, this can be an RSA certificate or simple string value. 7. Click the **Next** button. 8. In the **Secret name and description** section enter a name for your secret in the **Secret name** field. For example, if you are storing your App Store Connect API key, you might want to name it using the same naming convention as Codemagic, e.g. `APP_STORE_CONNECT_PRIVATE_KEY`. 9. Click the **Next** button. 10. There is no need to configure any secret rotation, so click the **Next** button again. 11. On the Review screen, click on the **Store** button to store your secret. 12. Repeat this process for other values you would like to store. #### Retrieving secrets Secrets can be retrieved using the **AWS CLI**. Secrets stored as plain text values can be retrieved as JSON text and parsed using `jq` command. Note the use of the `-r` flag to strip the quotes from the JSON property value returned. The following example shows how to retrieve a secret called `APP_STORE_CONNECT_ISSUER_ID` that was stored as plain text. ```bash aws secretsmanager get-secret-value --secret-id APP_STORE_CONNECT_ISSUER_ID | jq -r '.SecretString' ``` If you have stored your secret using a *key/pair* value you can use the following syntax: ```bash aws secretsmanager get-secret-value \ --secret-id APP_STORE_CONNECT_ISSUER_ID | \ jq -r '.SecretString' | \ jq -r '.APP_STORE_CONNECT_ISSUER_ID' ``` #### Use secrets in `codemagic.yaml` ### Option: Android 1. The environment variable `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS` must be provided with a valid Service Account JSON key, even if you will overwrite it with a different key later. Add this variable to a group called `service_account` and then import it into your workflow as follows: ```yaml environment: groups: - service_account - aws_credentials vars: GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS_HOLDER: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS ``` 2. In your first script step, retrieve the Service Account JSON from AWS and add it to **CM_ENV**. ```yaml scripts: - name: Set Service Account JSON from AWS script: | echo "GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS<> $CM_ENV echo "$(aws secretsmanager get-secret-value \ --secret-id GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS | jq -r '.SecretString')" >> $CM_ENV echo "DELIMITER" >> $CM_ENV ``` 3. Reference the variable for publishing to Google Play as follows: ```yaml publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS_HOLDER track: $GOOGLE_PLAY_TRACK ``` ### Option: iOS 1. Add the following variables in the codemagic.yaml ```yaml environment: groups: - aws_credentials vars: APP_STORE_CONNECT_PRIVATE_KEY: $APP_STORE_CONNECT_PRIVATE_KEY APP_STORE_CONNECT_KEY_IDENTIFIER: $APP_STORE_CONNECT_KEY_IDENTIFIER APP_STORE_CONNECT_ISSUER_ID: $APP_STORE_CONNECT_ISSUER_ID CERTIFICATE_PRIVATE_KEY: $CERTIFICATE_PRIVATE_KEY ``` 2. In your first script step, retrieve the secrets from AWS and add them to **CM_ENV**. ```yaml scripts: - name: Set iOS credentials from AWS secrets script: | echo "APP_STORE_CONNECT_PRIVATE_KEY<> $CM_ENV echo "$(aws secretsmanager get-secret-value \ --secret-id ASC_PRIVATE_KEY | jq -r '.SecretString')" >> $CM_ENV echo "DELIMITER" >> $CM_ENV # echo "CERTIFICATE_PRIVATE_KEY<> $CM_ENV echo "$(aws secretsmanager get-secret-value \ --secret-id CERTIFICATE_PRIVATE_KEY | jq -r '.SecretString')" >> $CM_ENV echo "DELIMITER" >> $CM_ENV # echo "APP_STORE_CONNECT_KEY_IDENTIFIER=$(aws secretsmanager get-secret-value \ --secret-id APP_STORE_CONNECT_KEY_IDENTIFIER | jq -r '.SecretString')" >> $CM_ENV # echo "APP_STORE_CONNECT_ISSUER_ID=$(aws secretsmanager get-secret-value \ --secret-id APP_STORE_CONNECT_ISSUER_ID | jq -r '.SecretString')" >> $CM_ENV ``` 3. Reference the variables for iOS publishing as usual: ```yaml publishing: app_store_connect: api_key: $APP_STORE_CONNECT_PRIVATE_KEY key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER issuer_id: $APP_STORE_CONNECT_ISSUER_ID ```

## Doppler The following steps illustrate how to use Doppler Secrets Manager with Codemagic. #### Configure Doppler access You will need to configure the `DOPPLER_TOKEN` environment variable in Codemagic UI. To create the token, login to Doppler, navigate to the **ACCESS** tab in your project click on **Generate**. Enter a token name, give it *read access* and click **Generate Service Token**. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `DOPPLER_TOKEN`. 3. Enter the token value as **_Variable value_**. 4. Enter the variable group name, e.g. **_doppler_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - doppler_credentials ``` #### Storing a secret in Doppler To store a secret in Doppler, do the following: 1. Log into your Doppler account and go to your workspace then your project. 2. Navigate to the **SECRETS** tab, 3. Click on the **Add Secret** button. 4. Paste in the secret you would like to store, this can be an RSA certificate or simple string value. 5. In the **NAME** section enter a name for your secret field. For example, if you are storing your App Store Connect API key, you might want to name it using the same naming convention as Codemagic, e.g. `APP_STORE_CONNECT_PRIVATE_KEY`. 6. Repeat this process for other values you would like to store. #### Install the Doppler CLI The Codemagic base build image doesn't have the **Doppler CLI** by default, so we need to install it first. The following example shows how to install the Doppler CLI on various build instance types: ### Option: macOS ```yaml scripts: - name: Install Doppler on macOS script: | brew install gnupg brew install dopplerhq/cli/doppler ``` ### Option: Linux ```yaml scripts: - name: Install Doppler on Linux script: | (curl -Ls --tlsv1.2 --proto "=https" \ --retry 3 https://cli.doppler.com/install.sh || \ wget -t 3 -qO- https://cli.doppler.com/install.sh) | \ sudo sh ``` ### Option: Windows ```yaml scripts: - name: Install Doppler on Windows script: | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser iex "& {$(irm get.scoop.sh)} -RunAsAdmin" scoop bucket add doppler https://github.com/DopplerHQ/scoop-doppler.git scoop install doppler ``` For more information, see the official [Doppler docs](https://docs.doppler.com/docs/cli#installation). #### Retrieving secrets The following example shows how to retrieve a secret called `APP_STORE_CONNECT_ISSUER_ID` as plain text and add it to the System Environment directly. ```bash echo "APP_STORE_CONNECT_ISSUER_ID=$(doppler secrets get APP_STORE_CONNECT_ISSUER_ID --plain)" >> $CM_ENV ``` If you want to retrieve a secret with multiline variable, like the `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS` you can do it like this: ```bash echo "GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS<> $CM_ENV echo "$(doppler secrets get GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS --plain)" >> $CM_ENV echo "DELIMITER" >> $CM_ENV ``` > > **Note:** If you add the `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS` make sure you choose **No** when it asks you to replace `\n` with new lines. > You can download all of your secrets and add them to your environment in a single step. Make sure to set the `$DOPPLER_ENV` variable in the **vars** section. ```yaml environment: groups: - doppler_credentials # <-- (Includes the $DOPPLER_TOKEN) vars: DOPPLER_ENV: dev scripts: - name: Import Doppler secrets script: | doppler secrets download --no-read-env \ --no-file \ --format env-no-quotes \ --config $DOPPLER_ENV \ --token $DOPPLER_TOKEN >> $CM_ENV ``` #### For Windows Users 1. You should add the doppler path to the system path at the beginning of each script like this: ```bash $env:Path += ";C:\Users\builder\scoop\shims" ``` 2. When accessing the environment variables on Windows, reference them as `$env:VAR_NAME`. See more [here](../troubleshooting/common-windows-issues/).

## Hashicorp Vault The following steps illustrate how to use Hashicorp Vault with Codemagic. #### Configure Hashicorp Vault access This example uses token authentication. To authenticate with other methods provided by Hashicorp Vault, please consult their documentation. You will need to configure the `VAULT_NAMESPACE`, `VAULT_ADDRESS`, and `VAULT_TOKEN` environment variables in the Codemagic UI. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `VAULT_NAMESPACE`. 3. Enter the variable value as **_Variable value_**. 4. Enter the variable group name, e.g. **_vault_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to also add `VAULT_ADDRESS` and `VAULT_TOKEN` variables. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - vault_credentials ``` #### Storing a secret in Hashicorp Vault Install the Hashicorp Vault CLI on your local machine: ```bash brew tap hashicorp/tap brew install hashicorp/tap/vault ``` To set a simple string value, you can add a single secret to a group as follows: ```bash vault kv put secret/greetings message=hello ``` Retrieve the secret as follows: ```bash vault kv get -field=message secret/greetings ``` To add a secret from file such as an RSA key or JSON key, you can add the contents of a file as follows: ```bash vault kv put secret/gcloud GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS=@gcloud.json ``` To retrieve the secret you would do the following: ```bash vault kv get -field=GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS secret/gcloud ``` #### Retrieving secrets from Hashicorp Vault Secrets can be retrieved using the **Hashicorp Vault CLI**. To retrieve a secret (e.g. 'message') stored as plain text value on a specified path (e.g. 'secret/greetings'): ```bash vault kv get -field=message secret/greetings ``` ### Option: Android 1. The environment variable `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS` must be provided with a valid Service Account JSON key, even if you will overwrite it with a different key later. Add this variable to a group called `service_account` and then import it into your workflow. 2. Add the secret for your **Google Console Service Account** to Hashicorp Vault as follows: ```bash vault kv put secret/google \\ GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS=@/path/to/service_account.json ``` 3. Add the following environment variables and groups in your `codemagic.yaml` ```yaml environment: groups: - service_account - vault_credentials vars: GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS_HOLDER: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS ``` 4. In your first script step, retrieve the Service Account JSON from Hashicorp Vault and add it to *CM_ENV*. ```yaml scripts: - name: Set Service Account JSON from Hashicorp Vault script: | echo "GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS<> $CM_ENV echo "$(vault kv get -field=GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS secret/google)" >> $CM_ENV echo "DELIMITER" >> $CM_ENV ``` 5. Reference the variable for publishing to Google Play. ```yaml publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS_HOLDER track: $GOOGLE_PLAY_TRACK ``` ### Option: iOS 1. Add your App Store credentials to Hashicorp Vault. ```bash vault kv put secret/appstore \\ APP_STORE_CONNECT_PRIVATE_KEY=@/path/to/app_store_connect_api_key_file APP_STORE_CONNECT_KEY_IDENTIFIER=XXXXXXXXXX APP_STORE_CONNECT_ISSUER_ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX CERTIFICATE_PRIVATE_KEY=@/path/to/ios_distribution_cert_private_key_file ``` 2. Add the following environment variables and groups in your `codemagic.yaml` ```yaml environment: groups: - vault_credentials vars: APP_STORE_CONNECT_PRIVATE_KEY: $APP_STORE_CONNECT_PRIVATE_KEY APP_STORE_CONNECT_KEY_IDENTIFIER: $APP_STORE_CONNECT_KEY_IDENTIFIER APP_STORE_CONNECT_ISSUER_ID: $APP_STORE_CONNECT_ISSUER_ID CERTIFICATE_PRIVATE_KEY: $CERTIFICATE_PRIVATE_KEY ``` 3. In your first script step, retrieve the secrets from Hashicorp Vault and add them to *CM_ENV*. ```yaml scripts: - name: Set iOS credentials from Hashicorp Vault script: | echo "APP_STORE_CONNECT_PRIVATE_KEY<> $CM_ENV echo "$(vault kv get -field=APP_STORE_CONNECT_PRIVATE_KEY secret/appstore)" >> $CM_ENV echo "DELIMITER" >> $CM_ENV # echo "CERTIFICATE_PRIVATE_KEY<> $CM_ENV echo "$(vault kv get -field=CERTIFICATE_PRIVATE_KEY secret/appstore)" >> $CM_ENV echo "DELIMITER" >> $CM_ENV # echo "APP_STORE_CONNECT_KEY_IDENTIFIER=$(vault kv get -field=APP_STORE_CONNECT_KEY_IDENTIFIER secret/appstore)" >> $CM_ENV # echo "APP_STORE_CONNECT_ISSUER_ID=$(vault kv get -field=APP_STORE_CONNECT_ISSUER_ID secret/appstore)" >> $CM_ENV ``` 4. Reference the variables for iOS publishing as usual. ```yaml publishing: app_store_connect: api_key: $APP_STORE_CONNECT_PRIVATE_KEY key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER issuer_id: $APP_STORE_CONNECT_ISSUER_ID ``` ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-an-ionic-app/ title: Ionic Capacitor apps description: How to build an Ionic Capacitor app with codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Ionic Capacitor apps > How to build an Ionic Capacitor app with codemagic.yaml This guide will illustrate all of the necessary steps to successfully build and publish an Ionic Capacitor app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ionic/ionic-capacitor-demo-project). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. ### Option: Android #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` #### Signing Android apps using Gradle To sign your Android app, simply modify your **`android/app/build.gradle`** or **`android/app/build.gradle.kts`** as follows: %!s() ### Option: build.gradle ```Groovy ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` ### Option: build.gradle.kts ```groovy import java.io.File import java.util.* val keystoreProperties = Properties().apply { var file = File("key.properties") if (file.exists()) load(file.reader()) } plugins { ... } android { ... val appVersionCode = (System.getenv()["NEW_BUILD_NUMBER"] ?: "1")?.toInt() defaultConfig { ... versionCode = appVersionCode ... } signingConfigs { create("release") { if (System.getenv()["CI"].toBoolean()) { // 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 { storeFile = file(keystoreProperties.getProperty("storeFile")) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } } } buildTypes { getByName("release") { isMinifyEnabled = false signingConfig = signingConfigs.getByName("release") } } } dependencies { ... } ``` ### Option: iOS #### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. %!s() ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ##### Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > ## Configure scripts to build the app Add the following scripts to your `codemagic.yaml` file in order to prepare the build environment and start the actual build process. In this step you can also define the build artifacts you are interested in. These files will be available for download when the build finishes. For more information about artifacts, see [here](../yaml/yaml-getting-started/#artifacts). ### Option: Android One very useful method of calculating the code version is to use Codemagic command line tools to get the latest build number from Google Play and increment it by one. You can find the full sample project with the instructions on alternative ways to perform Android build versioning [in our repository](https://github.com/codemagic-ci-cd/android-versioning-example). The prerequisite is a valid **Google Cloud Service Account**. Please follow these steps: 1. Go to [this guide](https://docs.codemagic.io/yaml-publishing/google-play/) and complete the steps in the **Google Play** section. 2. Skip to the **Creating a service account** section in the same guide and complete those steps also. 3. You now have a `JSON` file with the credentials. 4. Open Codemagic UI and create a new Environment variable `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. 5. Paste the content of the downloaded `JSON` file in the **_Value_** field, set the group name (e.g. **google_play**) and make sure the **Secret** option is checked. --- 6. Add the **google_play** variable group to the `codemagic.yaml` ```yaml workflows: android-workflow-id: # .... environment: groups: - google_play ``` 7. Modify the build script to calculate the build number and use it as gradlew arguments. ```yaml scripts: # .... - name: Build Android release script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z $LATEST_GOOGLE_PLAY_BUILD_NUMBER ]; then # fallback in case no build number was found from Google Play. # Alternatively, you can `exit 1` to fail the build # BUILD_NUMBER is a Codemagic built-in variable tracking the number # of times this workflow has been built UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi cd android ./gradlew bundleRelease \ -PversionCode=$UPDATED_BUILD_NUMBER \ -PversionName=1.0.$UPDATED_BUILD_NUMBER ``` 8. Modify the `android/app/build.gradle` file to get the build number values and apply them: ```kotlin // get version code from the specified property argument `-PversionCode` during the build call def getMyVersionCode = { -> return project.hasProperty('versionCode') ? versionCode.toInteger() : -1 } // get version name from the specified property argument `-PversionName` during the build call def getMyVersionName = { -> return project.hasProperty('versionName') ? versionName : "1.0" } .... android { .... defaultConfig { ... versionCode getMyVersionCode() versionName getMyVersionName() ``` %!s() ### Option: iOS In order to get the latest build number from App Store or TestFlight, you will need the App Store credentials as well as the **Application Apple ID**. This is an automatically generated ID assigned to your app and it can be found under **General > App Information > Apple ID** under your application in App Store Connect. 1. Add the **Application Apple ID** to the `codemagic.yaml` as a variable 2. Add the script to get the latest build number using `app-store-connect` and configure the new build number using `agvtool`. 3. Your `codemagic.yaml` will look like this: ```yaml workflows: ios-workflow: name: iOS Workflow integrations: app_store_connect: environment: vars: APP_STORE_APPLE_ID: 1555555551 scripts: - name: Increment build number script: | #!/bin/sh cd $CM_BUILD_DIR LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number "$APP_STORE_APPLE_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build ipa for distribution script: | # build command ``` ## Publishing Codemagic offers a wide array of options for app publishing and the list of partners and integrations is continuously growing. For the most up-to-date information, check the guides in the **Configuration > Publishing** section of these docs. To get more details on the publishing options presented in this guide, please check the [Email publishing](../yaml-publishing/email), the [Google Play Store](../yaml-publishing/google-play) publishing and the [App Store Connect](../yaml-publishing/app-store-connect). #### Email publishing If the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to Google Play and App Store %!s() ### Option: Android Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` %!s() ### Option: iOSCodemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: %!s() ### Option: AndroidWhile this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-cordova-app/ title: Ionic Cordova apps description: How to build a Ionic Cordova app with codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Ionic Cordova apps > How to build a Ionic Cordova app with codemagic.yaml This guide will illustrate all of the necessary steps to successfully build and publish an Ionic Cordova app with Codemagic. It will cover the basic steps such as code signing and publishing. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ionic/ionic-cordova-demo-project). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. ### Option: Android #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` #### Signing Android apps using Gradle To sign your Android app, simply modify your **`android/app/build.gradle`** or **`android/app/build.gradle.kts`** as follows: %!s() ### Option: build.gradle ```Groovy ... android { ... defaultConfig { ... } 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'] } } } buildTypes { release { ... signingConfig signingConfigs.release } } } ... ``` ### Option: build.gradle.kts ```groovy import java.io.File import java.util.* val keystoreProperties = Properties().apply { var file = File("key.properties") if (file.exists()) load(file.reader()) } plugins { ... } android { ... val appVersionCode = (System.getenv()["NEW_BUILD_NUMBER"] ?: "1")?.toInt() defaultConfig { ... versionCode = appVersionCode ... } signingConfigs { create("release") { if (System.getenv()["CI"].toBoolean()) { // 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 { storeFile = file(keystoreProperties.getProperty("storeFile")) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } } } buildTypes { getByName("release") { isMinifyEnabled = false signingConfig = signingConfigs.getByName("release") } } } dependencies { ... } ``` ### Option: iOS #### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. %!s() ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ##### Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > ## Configure scripts to build the app Add the following scripts to your `codemagic.yaml` file in order to prepare the build environment and start the actual build process. In this step you can also define the build artifacts you are interested in. These files will be available for download when the build finishes. For more information about artifacts, see [here](../yaml/yaml-getting-started/#artifacts). ### Option: Android Codemagic offers a wide array of options for app publishing and the list of partners and integrations is continuously growing. For the most up-to-date information, check the guides in the **Configuration > Publishing** section of these docs. To get more details on the publishing options presented in this guide, please check the [Email publishing](../yaml-publishing/email), the [Google Play Store](../yaml-publishing/google-play) publishing and the [App Store Connect](../yaml-publishing/app-store-connect). #### Email publishing If the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to Google Play and App Store %!s() ### Option: Android Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` %!s() ### Option: iOSCodemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: %!s() ### Option: AndroidWhile this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/yaml-distributing/pub.dev/ title: pub.dev description: How to deploy a package to pub.dev using codemagic.yaml last_modified: 2026-04-01 ================================================================================ # pub.dev > How to deploy a package to pub.dev using codemagic.yaml In order to get publishing permissions, you first need to log in to **pub.dev** locally. You can do this by running `pub publish --dry-run`. This will create the `credentials.json` file, which you can use to log in without the need for Google confirmation through the browser. Credentials will be created in the pub cache directory (`~/.pub-cache/credentials.json` on macOS and Linux, `%APPDATA%\Pub\Cache\credentials.json` on Windows). 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `PUB_DEV_CREDENTIALS`. 3. Enter the token value as **_Variable value_**. 4. Make sure the **Secret** option is selected. 5. Click the **Add** button to add the variable. 6. Configure publishing in `codemagic.yaml` ```yaml environment: vars: PUB_DEV_CREDENTIALS # ... scripts: - name: Publish to pub.dev script: | echo $PUB_DEV_CREDENTIALS > "$FLUTTER_ROOT/.pub-cache/credentials.json" flutter pub publish --dry-run flutter pub publish -f ``` ================================================================================ source: https://docs.codemagic.io/yaml-publishing/steam/ title: Steam description: How to deploy an app to Steam using codemagic.yaml last_modified: 2025-05-27 ================================================================================ # Steam > How to deploy an app to Steam using codemagic.yaml

> > **Note:** This guide only applies to workflows configured with the **codemagic.yaml**. > A sample project showcasing steps included in this guide is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/unity/unity-deploy-steam). ## Prerequisites - A Unity **Plus** or **Pro** license. Your license is used to activate Unity on the Codemagic build server so the project can be built. The license is returned automatically once the workflow completes. - A Steam Partner account is required to publish to Steam. ## Getting Started **SteamCMD** is a tool used to upload builds to Steam. SteamCMD requires logging in to Steam and typically requires entering a Steam Guard code. There are two ways of solving this problem. 1. Disable Steam Guard for the account doing the Steam upload. This is not recommended, as it makes the Steam account less secure. 2. Use sentry files that are generated after logging in successfully to Steam. A Steam Guard code is not required when these sentry files are present on the build machine. Thus, we will save the sentry files as secret environment variables and place them at the correct path when the build starts. ### Obtain the sentry files: First, you need to install the SteamCMD. ### Option: macOS ```bash mkdir ~/Steam curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_osx.tar.gz" | tar zxvf - -C ~/Steam ``` ### Option: Linux ```bash sudo apt-get install lib32gcc1 mkdir ~/Steam curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf - -C ~/Steam ``` Then log into Steam using the following command, which will prompt for the Steam Guard code: ```bash ~/Steam/steamcmd.sh +login steam $STEAM_USERNAME $STEAM_PASSWORD ``` The **ssfn** file will be stored as `~/Steam/ssfn*******************` and the **config.vdf** file as `~/Steam/config/config.vdf`. > > **Warning:** Keep the sentry files private; do not check them into public source control. > ### Configure environment variables 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `SSFN_FILE_NAME`. 3. Enter the ssfn file name as **_Variable value_**. 4. Enter the variable group name, e.g. **_steam_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Enter another variable named `SSFN_FILE` and copy/paste the `base64` encoded value of the ssfn file. Follow the instructions for [storing binary files](/yaml-basic-configuration/configuring-environment-variables/#storing-binary-files). 8. Repeat the previous step to add the `config.vdf` file as a variable named `CONFIG_FILE`. > > **Warning:** When base64 encoding the files, make sure to remove the new lines `\n` of the encoded value before saving it to Codemagic. > If you don't want to install the SteamCMD on your local machine to obtain the sentry files, you can use Codemagic machines to do so and then copy them into your local machine using the secure copy command `scp`. ```bash scp -P builder@X.X.X.X ~/Library/Application\ Support/ssfn******************* . scp -P builder@X.X.X.X ~/Library/Application\ Support/config/config.vdf . ``` ### Decode Sentry Files In your workflow you need to base64 decode these binary files before they can be used: ```yaml - name: Decode Sentry files script: | echo $CONFIG_FILE | base64 --decode > steam/config.vdf echo $SSFN_FILE | base64 --decode > steam/$SSFN_FILE_NAME ``` ### Copy Sentry files And then copy them to the correct path, depending on the build machine type: ### Option: macOS ```yaml - name: Copy Sentry Files script: | mkdir -p ~/Library/Application\ Support/Steam/config cp ~/clone/steam/$SSFN_FILE_NAME ~/Library/Application\ Support/Steam cp ~/clone/steam/config.vdf ~/Library/Application\ Support/Steam/config ``` ### Option: Linux ```yaml - name: Copy Sentry Files script: | mkdir -p ~/Steam/config cp ~/clone/steam/$SSFN_FILE_NAME ~/Steam cp ~/clone/steam/config.vdf ~/Steam/config ``` ### Upload to Steam To configure the upload to Steam, edit the following two files in the project by adding your application's AppID, DepotID, and branch name for deployment: **steam/app_build.vdf** ```json "AppBuild" { "AppID" "2086870" // Your AppID "Desc" "Published using Codemagic" // internal description for this build "Preview" "0" // make this a preview build only, nothing is uploaded "Local" "" // put content on local content server instead of uploading to Steam "SetLive" "cm-release" // set this build live on cm-branch branch (Change this) "ContentRoot" "..\win64" // content root folder relative to this script file "BuildOutput" ".\output\" // put build cache and log files on different drive for better performance "Depots" { // file mapping instructions for each depot are in separate script files "2086871" "depot_build.vdf" } } ``` **steam/depot_build.vdf** ```json "DepotBuild" { // Set your assigned depot ID here "DepotID" "2086871" // include all files recursively "FileMapping" { // This can be a full path, or a path relative to ContentRoot "LocalPath" "*" // This is a path relative to the install folder of your game "DepotPath" "." // If LocalPath contains wildcards, setting this means that all // matching files within subdirectories of LocalPath will also // be included. "Recursive" "1" } } ``` These are standard VDF files required for uploading a build to Steam and require your application's AppID, DepotID, and branch name for deployment. Finally, use the following script in your `codemagic.yaml` to publish your app to Steam: ```yaml scripts: - name: Upload Build to Steam script: | ~/Steam/steamcmd.sh +login $STEAM_USERNAME $STEAM_PASSWORD +run_app_build ~/clone/steam/app_build.vdf +quit ``` ================================================================================ source: https://docs.codemagic.io/rn-codepush/cli-quick-reference/ title: CLI quick reference description: Copy-paste CodePush CLI commands for auth, releases, and rollouts last_modified: 2026-04-13 ================================================================================ # CLI quick reference > Copy-paste CodePush CLI commands for auth, releases, and rollouts Examples use placeholder app names **`MyApp-Android`** and **`MyApp-iOS`**—replace them with your registered CodePush apps. Platform arguments for `release-react` are **`android`** or **`ios`**. All bundle uploads and release changes go through the **CLI** (locally or in CI), not the Codemagic UI. For install options and client-side APIs, see [Advanced: sync options](/rn-codepush/advanced-sync-options/). --- ## Install and version check ```bash npm install -g @codemagic/code-push-cli code-push --version ``` See [Setup](/rn-codepush/setup/) for full installation and server configuration. --- ## Authentication ```bash code-push login "https://codepush.pro" --accessKey $CODEPUSH_ACCESS_KEY ``` See [Security and access](/rn-codepush/security-and-access/) for keys and token handling. --- ## Apps and deployments Register an app (creates **Staging** and **Production** deployments): ```shell code-push app add MyApp-Android code-push app add MyApp-iOS ``` List apps: ```shell code-push app list ``` List deployments and **deployment keys** (`-k`): ```shell code-push deployment list MyApp-Android -k ``` --- ## Publish a React Native bundle (`release-react`) Default deployment is usually **Staging** if you omit a deployment flag (confirm with `code-push release-react --help` for your CLI version). **Android** ```shell code-push release-react MyApp-Android android ``` **iOS** ```shell code-push release-react MyApp-iOS ios ``` **Common options** (combine as needed): ```shell code-push release-react MyApp-Android android -d Production --targetBinaryVersion "1.2.x" --description "Short release notes" --mandatory --rollout 25 ``` | Flag | Purpose | |------|---------| | `--targetBinaryVersion` | Limit which store app versions may install the update | | `--description` | Release notes (for example shown in an in-app update dialog) | | `--mandatory` | Treat the release as mandatory on supported clients | | `--rollout ` | Deliver to approximately `n` percent of users | See [Releasing updates](/rn-codepush/releasing-updates/) and [Production control](/rn-codepush/production-control/) for workflows, constraints, and examples. --- ## Promote between deployments Promote an existing release from one deployment to another without rebuilding or creating a new bundle. ```shell code-push promote MyApp-Android Staging Production ``` Promotion allows you to safely move tested updates between environments without rebuilding or modifying the original release. --- ## Change rollout on an existing release Update the rollout percentage of an existing release without creating a new one using the `patch` command. ```shell code-push patch MyApp-Android Production --rollout 50 ``` See [Production control](/rn-codepush/production-control/#rollouts) for rollout rules and limits. --- ## Roll back a deployment To revert a deployment to the previous release, use the rollback command. ```shell code-push rollback MyApp-Android Production ``` This will deactivate the current release and restore the previously active version for the specified deployment. See [Production control](/rn-codepush/production-control/#rollbacks). --- ## Device debug logs (Android) ```shell code-push debug android ``` Requires a connected device, `adb`, and a single Android target. For iOS simulator requirements and log interpretation, see [Issues and debugging](/rn-codepush/debugging-and-common-issues/#cli-debugging-tools). --- ## Full flag lists Run `code-push --help` and `code-push --help` for the authoritative option list for your installed CLI version. ================================================================================ source: https://docs.codemagic.io/troubleshooting/codemagic-init/ title: Codemagic Knowledge for AI Agents description: Give your AI agent Codemagic skills to answer questions, debug builds, and suggest fixes last_modified: 2026-08-25 ================================================================================ # Codemagic Knowledge for AI Agents > Give your AI agent Codemagic skills to answer questions, debug builds, and suggest fixes ## What is codemagic-init ? `codemagic-init` is a CLI tool that brings Codemagic knowledge directly into AI agents running locally on a developer's machine. The goal is to equip AI agents with the context, skills, and knowledge they need to work effectively with Codemagic. Once installed, these capabilities enable the agent to: * Understand Codemagic configuration and workflows. * Create and modify codemagic.yaml files. * Answer questions about Codemagic. * Troubleshoot build and configuration issues. * Follow Codemagic best practices. * Help developers set up and maintain CI/CD pipelines. ## How it works 1. Install the package by running `pip install codemagic-init` in your local terminal. 2. Once installed, run `codemagic init`. This detects the supported AI agents installed on your machine and automatically sets up the Codemagic skills for them. Once initialized, the AI agent can leverage Codemagic-specific knowledge and skills to provide informed assistance across a wide range of Codemagic-related tasks and questions. The skills and their references to the Codemagic knowledge base are refreshed every 6 hours by a cron job. This keeps the information available to the AI agent aligned with the latest Codemagic documentation and knowledge. You can also refresh the knowledge manually with: ```bash codemagic update ``` To remove the installed Codemagic skills, run: ```bash codemagic uninstall ``` ## Project Setup `codemagic init` can also help configure Codemagic for a project by detecting project-specific information and using it during the setup process. Project detection is only available when `codemagic init` is run from within the project directory. In this case, the CLI can inspect the project's files and identify relevant information such as the project type, supported platforms, and application configuration. When `codemagic init` is run outside a project directory, the CLI cannot perform this project-specific detection. The Codemagic skills can still be installed for supported AI agents, however. Once the skills are installed, the AI agent can work with projects independently. For example, you can open a project in your AI agent and ask it to create or configure a `codemagic.yaml`, drawing on the Codemagic knowledge provided by `codemagic init`. In other words, the project-directory requirement applies only to project detection performed by the CLI, not to the use of Codemagic skills by the AI agent. ## Summary `codemagic-init` makes Codemagic readily available to the AI agents you already use locally, giving them the context and capabilities needed to assist with Codemagic throughout your development workflow. The source repository is available [here](https://github.com/codemagic-ci-cd/codemagic-init). ================================================================================ source: https://docs.codemagic.io/integrations/emerge-integration/ title: Emerge Tools integration description: How to integrate your workflows with Emerge using codemagic.yaml last_modified: 2026-02-16 ================================================================================ # Emerge Tools integration > How to integrate your workflows with Emerge using codemagic.yaml **Emerge Tools** helps you monitor and reduce app size with insights for instant savings. It provides continuous monitoring to write smaller, better code by profiling binary size on every pull request. A sample project that shows how to configure Emerge Tools integration is available [in our Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/emerge-tools-integration-demo-project). ## Configuring access to Emerge in Codemagic To get started with [Emerge Tools](https://www.emergetools.com/), you need to create an API key and save it as an environment variable in Codemagic. 1. Obtain an **API key** from your [Emerge Tools profile](https://www.emergetools.com/profile) by clicking the **Create a new API Key** button. > > **Warning:** Make sure to save the API key, as you cannot view it again on the site. > 2. Open your Codemagic app settings, and go to the **Environment variables** tab. 3. Enter the desired **_Variable name_**, e.g. `EMERGE_API_TOKEN`. 4. Copy and paste the API key string as **_Variable value_**. 5. Enter the variable group name, e.g. **_emergetools_credentials_**. Click the button to create the group. 6. Make sure the **Secret** option is selected. 7. Click the **Add** button to add the variable. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - emergetools_credentials ``` ## Fastlane plugin Emerge has created a plugin for Fastlane that makes it easy to upload iOS builds. You can add it to your project by running: ```yaml scripts: - name: Install Emerge Tools Fastlane plugin script: | fastlane add_plugin emerge ``` In the `Fastfile`, create a lane that utilizes the `emerge` plugin to upload the archive. You can refer to the complete example given below for uploading the build to Emerge: ```ruby fastlane_require 'git' default_platform(:ios) git = Git.open('..') platform :ios do lane :emerge_app_upload do BRANCH = ENV["CM_BRANCH"] IS_PULL_REQUEST = ENV["CM_PULL_REQUEST"] PR_NUMBER = ENV["CM_PULL_REQUEST_NUMBER"] REPO_NAME = ENV["CM_REPO_SLUG"] CURRENT_BUILD_ID = ENV["CM_COMMIT"] FILE_PATH = "/build/ios/xcarchive/swiftly.xcarchive" BASE_BUILD_ID = git.log[0].parent.sha PARENT_BUILD_ID = git.log[0].sha if IS_PULL_REQUEST == "true" emerge( file_path: FILE_PATH, build_type: "pull_request", repo_name: REPO_NAME, pr_number: PR_NUMBER, sha: CURRENT_BUILD_ID, base_sha: BASE_BUILD_ID ) elsif BRANCH.eql? "main" emerge( file_path: FILE_PATH, build_type: "main", repo_name: REPO_NAME, sha: PARENT_BUILD_ID ) end end end ``` This script checks if the current build is building a pull request. If it is a pull request, it takes the source commit of the build and compares it to the build of the base commit hash. Then, it uploads it to Emerge for processing for the size comparison. Otherwise, it uploads the build to Emerge with the type "main". ## Configuring `codemagic.yaml` You can upload the iOS build to Emerge Tool as a part of your Codemagic CI/CD workflow to automate the process. Here is an example of the scripts you can add to your `codemagic.yaml` for building the archive and uploading it to Emerge. Don't forget to upload a base build so Emerge can compare the archive's size differences in subsequent pull requests. ```yaml scripts: - name: Bundle install script: | bundle install - name: Install Emerge Tools Fastlane plugin script: | fastlane add_plugin emerge - name: Build ipa for distribution script: | xcode-project build-ipa --project "$XCODE_PROJECT" --scheme "$XCODE_SCHEME" - name: Upload archive to Emerge Tools script: | bundle exec fastlane emerge_app_upload ``` ================================================================================ source: https://docs.codemagic.io/flutter-distributing/github-releases/ title: GitHub releases with Flutter workflow editor description: How to create a GitHub release with artifacts using the Flutter workflow editor last_modified: 2026-04-01 ================================================================================ # GitHub releases with Flutter workflow editor > How to create a GitHub release with artifacts using the Flutter workflow editor Codemagic enables you to create a GitHub release automatically and upload generated artifacts when your build is triggered on tag creation. Read more about GitHub releases in [GitHub's documentation](https://docs.github.com/en/github/administering-a-repository/about-releases). ## Requirements Publishing GitHub releases is available for GitHub repositories only. Publishing to GitHub happens only for successful builds triggered on tag creation and is unavailable for manual builds. > > **Note:** The UI section for setting up publishing GitHub releases is deprecated in Flutter workflow editor. To continue to publish GitHub releases, please follow the instructions below. > 1. Create a personal access token in GitHub as described [here](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). 2. In the Environment section in Codemagic, save the personal access token as an environment variable with the name `GITHUB_TOKEN`. 3. In the Build triggers section, select **Trigger on tag creation**. Don't forget to add a branch pattern and ensure the webhook exists. 4. Add the following custom script in the **pre-publish step** that publishes the artifacts with tag builds. Edit the placeholders like your application name and the path to build artifacts to match your setup. ```bash #!/usr/bin/env zsh # Publish only for tag builds if [ -z ${CM_TAG} ]; then echo "Not a tag build will not publish GitHub release" exit 0 fi # See more options about `gh release create` usage from GitHub CLI # official docs at https://cli.github.com/manual/gh_release_create gh release create "${CM_TAG}" \ --title " ${CM_TAG}" \ --notes-file changelog.md \ path/to/build-artifact.ipa \ path/to/build-artifact.apk # Note that you don't need to include title and changelog if you do not want to. # Any number of artifacts can be included with the release. ``` ================================================================================ source: https://docs.codemagic.io/yaml-distributing/google-cloud-storage/ title: Google Cloud Storage description: How to publish build artifacts to Google Cloud Storage using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Google Cloud Storage > How to publish build artifacts to Google Cloud Storage using codemagic.yaml In order to publish your generated artifacts to Google Cloud Storage: 1. Log in to your Google Cloud platform [console](https://console.cloud.google.com/). 2. Create a new service account under **IAM & Admin > Service Accounts**. Find more information about how to create a service account [here](https://docs.codemagic.io/yaml-publishing/google-play/#configure-google-play-api-access). 3. Generate a JSON key for the service account and download it.

4. Open your Codemagic app settings, and go to the **Environment variables** tab. 5. Enter `GCLOUD_STORAGE_KEY` as the **_Variable name_**. 6. Copy and paste the content of the JSON key file as **_Variable value_**. 7. Enter the variable group name, e.g. **_google_credentials_**. Click the button to create the group. 8. Make sure the **Secret** option is selected. 9. Click the **Add** button to add the variable.

10. Go to your Google Cloud Platform console and open Cloud Storage. Make a note of the name of the bucket you want to upload to or create a new bucket. 11. In case of an existing bucket, make sure that necessary permissions are configured. To set up permissions go to the permission section of the bucket, click on **+ Add** and add the service account details with the role of Storage Object Creator and click save. ![Google Cloud Storage Permission](../uploads/storage-object-creator-role.png)
12. Configure your `codemagic.yaml` by adding the following script in your post-publishing step. Replace `gs://YOUR_BUCKET_NAME` with your own bucket name. ```yaml publishing: scripts: - name: Publish to Google Cloud script: | echo $GCLOUD_STORAGE_KEY > $CM_BUILD_DIR/gcloud_storage_key.json gcloud auth activate-service-account --key-file $CM_BUILD_DIR/gcloud_storage_key.json gsutil cp $CM_BUILD_DIR/app/build/outputs/**/*.apk gs://YOUR_BUCKET_NAME ``` After completing the steps above, you can go to your Cloud Storage account and check if the object is uploaded. ================================================================================ source: https://docs.codemagic.io/knowledge-others/import-variables-from-env-file/ title: Importing variables from a .env file description: How to import variables and secrets from a settings.env file last_modified: 2026-06-18 ================================================================================ # Importing variables from a .env file > How to import variables and secrets from a settings.env file If you are white labelling apps for different customers, you might want to store the credentials for each customer in a settings.env in a secure S3 or GCP bucket. You can then download the settings.env for the specific customer to run the build and write the values to the `CM_ENV` environment variable. To learn more about setting environment variables at build time, please see [here](../yaml-basic-configuration/using-environment-variables/). ## Configure the settings.env file Make sure that if you include any RSA keys that you add them to the file and preserve the line breaks as follows. ```bash APP_STORE_CONNECT_KEY_IDENTIFIER=XXXXXXXXXX APP_STORE_CONNECT_ISSUER_ID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX APP_STORE_CONNECT_PRIVATE_KEY='-----BEGIN PRIVATE KEY----- xxxx xxxx xxxx xxxx -----END PRIVATE KEY-----' CERTIFICATE_PRIVATE_KEY='-----BEGIN RSA PRIVATE KEY----- xxxx xxxx xxxx xxxx -----END RSA PRIVATE KEY-----' GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS='{ "type": "service_account", "project_id": "xxxx", "private_key_id": "xxxx", "private_key": "-----BEGIN PRIVATE KEY-----\nXXXX\n-----END PRIVATE KEY-----\n", "client_email": "xxxxx-xxxx@pxxxx.iam.gserviceaccount.com", "client_id": "xxxx", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/xxxx-xxxx%40pc-api-xxxx-xxxx.iam.gserviceaccount.com" }' ``` ## Add environment variables to codemagic.yaml In your codemagic.yaml you’ll need to define the variables so you don’t get yaml validation errors. ```yaml vars: ... APP_STORE_CONNECT_PRIVATE_KEY: $APP_STORE_CONNECT_PRIVATE_KEY APP_STORE_CONNECT_KEY_IDENTIFIER: $APP_STORE_CONNECT_KEY_IDENTIFIER APP_STORE_CONNECT_ISSUER_ID: $APP_STORE_CONNECT_ISSUER_ID CERTIFICATE_PRIVATE_KEY: $CERTIFICATE_PRIVATE_KEY GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS_HOLDER: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS ... ``` ## Add a valid Service Account JSON in the UI > > **Note:** it is important that a valid service account is configured in the UI before overriding with another. > In the Codemagic UI you should create an environment variable called `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS` and set its value to a valid Service Account JSON, even if this will be overwritten by another key when white labelling. ## Writing values to CM_ENV The following script first loads the **settings.env** file so you can read its values, and then writes the values to **CM_ENV**. Note that writing RSA keys requires using a delimiter to write a multi-line variable. ```yaml - name: Set value from settings.env script: | source settings.env echo "APP_STORE_CONNECT_KEY_IDENTIFIER=$APP_STORE_CONNECT_KEY_IDENTIFIER" >> $CM_ENV echo "APP_STORE_CONNECT_ISSUER_ID=$APP_STORE_CONNECT_ISSUER_ID" >> $CM_ENV echo "APP_STORE_CONNECT_PRIVATE_KEY<> $CM_ENV echo "$APP_STORE_CONNECT_PRIVATE_KEY" >> $CM_ENV echo "DELIMITER" >> $CM_ENV echo "CERTIFICATE_PRIVATE_KEY<> $CM_ENV echo "$CERTIFICATE_PRIVATE_KEY" >> $CM_ENV echo "DELIMITER" >> $CM_ENV echo "GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS<> $CM_ENV echo "$GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS" >> $CM_ENV echo "DELIMITER" >> $CM_ENV ``` ## A basic sample of using a settings.env file ```yaml workflow-name: name: Workflow name instance_type: mac_mini_m2 max_build_duration: 120 environment: groups: - group_name vars: ... APP_STORE_CONNECT_PRIVATE_KEY: $APP_STORE_CONNECT_PRIVATE_KEY APP_STORE_CONNECT_KEY_IDENTIFIER: $APP_STORE_CONNECT_KEY_IDENTIFIER APP_STORE_CONNECT_ISSUER_ID: $APP_STORE_CONNECT_ISSUER_ID CERTIFICATE_PRIVATE_KEY: $CERTIFICATE_PRIVATE_KEY GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS_HOLDER: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS ... scripts: - name: Set value from settings.env script: | source settings.env echo "APP_STORE_CONNECT_KEY_IDENTIFIER=$APP_STORE_CONNECT_KEY_IDENTIFIER" >> $CM_ENV echo "APP_STORE_CONNECT_ISSUER_ID=$APP_STORE_CONNECT_ISSUER_ID" >> $CM_ENV echo "APP_STORE_CONNECT_PRIVATE_KEY<> $CM_ENV echo "$APP_STORE_CONNECT_PRIVATE_KEY" >> $CM_ENV echo "DELIMITER" >> $CM_ENV echo "CERTIFICATE_PRIVATE_KEY<> $CM_ENV echo "$CERTIFICATE_PRIVATE_KEY" >> $CM_ENV echo "DELIMITER" >> $CM_ENV echo "GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS<> $CM_ENV echo "$GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS" >> $CM_ENV echo "DELIMITER" >> $CM_ENV ... publishing: app_store_connect: api_key: $APP_STORE_CONNECT_PRIVATE_KEY key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER issuer_id: $APP_STORE_CONNECT_ISSUER_ID google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS_HOLDER track: $GOOGLE_PLAY_TRACK in_app_update_priority: 0 ``` ## Troubleshooting writing variables to CM_ENV On the Codemagic build machine the environment variables written to `CM_ENV` are written to the file `~/.codemagic` In order to see how values get written to $CM_ENV, you can test it on your local machine by setting up a cm.env file as follows: ```bash export CM_ENV=/tmp/cm.env ``` Then run commands to test writing to $CM_ENV. Open `/tmp/cm.env` to see what has been written to the file. ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-kmm-app/ title: KMM apps description: How to build a Kotlin Multiplatform Mobile app with codemagic.yaml last_modified: 2025-05-26 ================================================================================ # KMM apps > How to build a Kotlin Multiplatform Mobile app with codemagic.yaml This guide will illustrate all of the necessary steps to successfully build and publish a Kotlin Multiplatform Mobile app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/kotlin-multiplatform-mobile). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. ### Option: Android #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` #### Signing Android apps using Gradle To sign your Android app, simply modify your **`androidApp/build.gradle.kts`** as follows: ```Groovy ... android { ... defaultConfig { ... } signingConfigs { create("release") { 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"] } } buildTypes { release { ... signingConfig = signingConfigs.getByName("release") } } } ... ``` %!s() ### Option: iOS #### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. %!s() ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ##### Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > # Configure scripts to build the app Add the following scripts to your `codemagic.yaml` file in order to prepare the build environment and start the actual build process. In this step you can also define the build artifacts you are interested in. These files will be available for download when the build finishes. For more information about artifacts, see [here](../yaml/yaml-getting-started/#artifacts). ### Option: Android One very useful method of calculating the code version is to use Codemagic command line tools to get the latest build number from Google Play and increment it by one. You can find the full sample project with the instructions on alternative ways to perform Android build versioning [in our repository](https://github.com/codemagic-ci-cd/android-versioning-example). The prerequisite is a valid **Google Cloud Service Account**. Please follow these steps: 1. Go to [this guide](https://docs.codemagic.io/yaml-publishing/google-play/) and complete the steps in the **Google Play** section. 2. Skip to the **Creating a service account** section in the same guide and complete those steps also. 3. You now have a `JSON` file with the credentials. 4. Open Codemagic UI and create a new Environment variable `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. 5. Paste the content of the downloaded `JSON` file in the **_Value_** field, set the group name (e.g. **google_play**) and make sure the **Secret** option is checked. --- 6. Add the **google_play** variable group to the `codemagic.yaml` ```yaml workflows: android-workflow-id: # .... environment: groups: - google_play ``` 7. Modify the build script to calculate the build number and use it as gradlew arguments. ```yaml scripts: # .... - name: Build Android release script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z $LATEST_GOOGLE_PLAY_BUILD_NUMBER ]; then # fallback in case no build number was found from Google Play. # Alternatively, you can `exit 1` to fail the build # BUILD_NUMBER is a Codemagic built-in variable tracking the number # of times this workflow has been built UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi ./gradlew bundleRelease \ -PversionCode=$UPDATED_BUILD_NUMBER \ -PversionName=1.0.$UPDATED_BUILD_NUMBER ``` 8. Modify the `androidApp/build.gradle.kts` file to get the build number values and apply them: ```kotlin val latestGooglePlayBuildNumber = Integer.valueOf(System.getenv("LATEST_GOOGLE_PLAY_BUILD_NUMBER") ?: System.getenv("BUILD_NUMBER") ?: "0") .... android { .... defaultConfig { ... versionCode = latestGooglePlayBuildNumber + 1 versionName = "1.0.${latestGooglePlayBuildNumber + 1}" ``` %!s() ### Option: iOS In order to get the latest build number from App Store or TestFlight, you will need the App Store credentials as well as the **Application Apple ID**. This is an automatically generated ID assigned to your app and it can be found under **General > App Information > Apple ID** under your application in App Store Connect. 1. Add the **Application Apple ID** to the `codemagic.yaml` as a variable 2. Add the script to get the latest build number using `app-store-connect` and configure the new build number using `agvtool`. 3. Your `codemagic.yaml` will look like this: ```yaml workflows: ios-workflow: name: iOS Workflow integrations: app_store_connect: environment: vars: APP_STORE_APPLE_ID: 1555555551 scripts: - name: Increment build number script: | #!/bin/sh cd $CM_BUILD_DIR LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number "$APP_STORE_APPLE_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build ipa for distribution script: | # build command ``` ## Publishing Codemagic offers a wide array of options for app publishing and the list of partners and integrations is continuously growing. For the most up-to-date information, check the guides in the **Configuration > Publishing** section of these docs. To get more details on the publishing options presented in this guide, please check the [Email publishing](../yaml-publishing/email), the [Google Play Store](../yaml-publishing/google-play) publishing and the [App Store Connect](../yaml-publishing/app-store-connect). #### Email publishing If the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to Google Play and App Store %!s() ### Option: Android Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` %!s() ### Option: iOSCodemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: %!s() ### Option: AndroidWhile this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/knowledge-others/upload-custom-artifacts/ title: Uploading custom artifacts description: How to upload files to be included in your build artifacts ZIP file last_modified: 2022-10-12 ================================================================================ # Uploading custom artifacts > How to upload files to be included in your build artifacts ZIP file You can use a script to upload custom artifacts, such as screenshots, to `$CM_EXPORT_DIR` and include them in the build artifacts ZIP file generated by Codemagic. For example, in a [codemagic.yaml script](../getting-started/yaml/#scripts) step or Flutter workflow editor **post-test** script, use this command to copy build screenshots to `$CM_EXPORT_DIR` to be exported: ```yaml scripts: - name: Copy custom artifacts script: | #!/usr/bin/env sh cp -r build/screenshots $CM_EXPORT_DIR/screenshots ``` ================================================================================ source: https://docs.codemagic.io/rn-codepush/advanced-sync-options/ title: Advanced: sync options description: Customize CodePush sync behavior and UX last_modified: 2026-04-13 ================================================================================ # Advanced: sync options > Customize CodePush sync behavior and UX The default integration wraps your root component with CodePush and relies on `sync()` with minimal configuration. That is a reasonable starting point, but the default install modes often clash with what teams and users expect—which can quietly undermine adoption. ### Why change the defaults - `ON_NEXT_RESUME` (used in common “check on every resume” setups) can restart the app when the user returns from the background, sometimes without a clear warning. That feels abrupt and can be mistaken for a crash. - `ON_NEXT_RESTART` (the default for optional updates) waits until the process is killed and reopened. In practice users rarely fully restart mobile apps, so updates can sit pending for a long time unless you add your own prompts or restart strategy. Those behaviors are documented, but they rarely match the mental model of “CodePush silently keeps everyone current.” When updates feel intrusive or never show up, teams often stop trusting or using OTA. Crafting the update workflow—install timing, optional dialogs, progress, mandatory handling—is usually what makes CodePush worth using deliberately for both end users and the shipping team. The sections below summarize the most useful levers. Option names and behavior are defined by [`@code-push-next/react-native-code-push`](https://www.npmjs.com/package/@code-push-next/react-native-code-push)—use that package’s README, TypeScript types, and changelog as the source of truth. For rollouts, mandatory releases, and `targetBinaryVersion`, see [Production control](/rn-codepush/production-control/). For CLI publishing and release metadata such as descriptions, see [Releasing updates](/rn-codepush/releasing-updates/). --- ## Resume and suspend installs — `minimumBackgroundDuration` If you use `InstallMode.ON_NEXT_RESUME` or `ON_NEXT_SUSPEND`, the runtime can apply an update when the app returns from the background. `minimumBackgroundDuration` (in seconds) sets how long the app must have been in the background before a restart is allowed. That avoids interrupting a user who only briefly switched away. - Helps make resume-based installs feel less abrupt. - Only applies to install modes that tie installation to background or resume behavior; it does not change `ON_NEXT_RESTART` or `IMMEDIATE` the same way. Combine with `installMode` / `mandatoryInstallMode` in the options object passed to `codePush()` or `codePush.sync()`. --- ## Server-managed copy in the update UI — `appendReleaseDescription` If you enable an update dialog (`updateDialog` — a boolean or an options object), you can set `appendReleaseDescription: true` so the release description you pass **when you publish with the CLI** is appended to the message shown to the user. - Keeps changelog-style text on the server: set or change the description on your next CLI publish (for example with **`release-react`**); the app does not need a new binary to show new text. - Use with `descriptionPrefix` if you want a fixed label before the server description. Before enabling interactive dialogs in store-distributed apps, check your store’s policies on in-app update prompts. --- ## Download progress — `downloadProgressCallback` and HOC hooks `codePush.sync()` can take a sync status callback and a download progress callback. The progress callback receives an object with `receivedBytes` and `totalBytes`—use it to drive a progress bar or status text during download. Confirm parameter order and names in [`@code-push-next/react-native-code-push`](https://www.npmjs.com/package/@code-push-next/react-native-code-push) (TypeScript types). **Function components** should use this explicit `sync(options, syncStatusCallback, downloadProgressCallback)` style rather than relying on HOC lifecycle hooks. If you use the higher-order component pattern (`codePush({ ... })(App)`), **class components** can implement `codePushDownloadDidProgress` and `codePushStatusDidChange` on the component for progress and coarse sync states (checking, downloading, installing, up to date, and so on). Those hooks do not apply when you only wrap a **function component** with the HOC. --- ## First run and pending updates — `isFirstRun`, `isPending`, `getUpdateMetadata` After an update is installed, `LocalPackage` metadata includes: - `isFirstRun` — useful for showing a one-time “What’s new” after a new bundle becomes active. - `isPending` — indicates there is still an update waiting to take effect (for example after install modes that defer activation). You can also call `codePush.getUpdateMetadata(updateState)` with `UpdateState.PENDING` or `UpdateState.RUNNING` to inspect metadata without relying only on the object returned from `getCurrentPackage()`-style flows. Prefer `getUpdateMetadata` in current SDK versions where `getCurrentPackage` is deprecated. --- ## Binary version mismatch — `handleBinaryVersionMismatchCallback` `sync()` can take a `handleBinaryVersionMismatchCallback` invoked when the installed binary is too old for the latest enabled release. This comes from `targetBinaryVersion` targeting a newer native version than the user has installed. Use it to log, show a “please update from the store” message, or branch your own logic instead of failing silently. This complements server-side targeting described in [Production control](/rn-codepush/production-control/): the server decides what is offered; the callback lets the client react when the user’s binary is outside that window. --- ## Blocking restarts — `disallowRestart()` and `allowRestart()` `codePush.disallowRestart()` prevents CodePush from programmatically restarting the app (including after `IMMEDIATE` installs or when `restartApp` would run) until `codePush.allowRestart()` is called. Typical pattern: call `disallowRestart` when a critical flow starts (onboarding, checkout), `allowRestart` when it ends—optionally flushing a pending restart that was queued. Alternatively, prefer `InstallMode.ON_NEXT_RESTART` and call `restartApp` only when your app knows it is safe; `disallowRestart` is for cases where sync runs globally but you still need a no-interruption window. --- ## Mandatory updates — server flag and `mandatoryInstallMode` Publishing a release as mandatory with the CLI (see [Mandatory updates](/rn-codepush/production-control/#mandatory-updates)) stores that flag on the server and changes client behavior: users are not offered a normal “ignore” path for that release. On the client, `mandatoryInstallMode` controls when that mandatory update is applied (for example immediate vs on next resume). **Mandatory propagation:** if a device is still on an older bundle while a **newer mandatory** release exists in the deployment history, the **latest compatible** update the server offers to that client can still be treated as **mandatory** to install, even when that latest release was **not** published with the `--mandatory` flag. (See [Mandatory update propagation](/rn-codepush/production-control/#mandatory-update-propagation) in Production control.) You can change the mandatory flag **after** a release is published using the CLI **`patch`** or **`promote`** commands—see [Production control](/rn-codepush/production-control/) and [CLI quick reference](/rn-codepush/cli-quick-reference/). No app binary change is required to turn mandatory on or off for a given release; it is a property of the release you set when publishing or patching **through the CodePush CLI**. --- ## Summary | Goal | Primary API surface | |------|---------------------| | Less intrusive resume-based installs | `minimumBackgroundDuration`, `installMode` / `mandatoryInstallMode` | | Show release notes from the server | `updateDialog`, `appendReleaseDescription` | | Show download or sync progress | `sync` status + download callbacks (function components); HOC `codePushDownloadDidProgress` / `codePushStatusDidChange` (class components only) | | “What’s new” or pending state | `isFirstRun`, `isPending`, `getUpdateMetadata` | | Wrong store binary vs OTA channel | `handleBinaryVersionMismatchCallback` + [targeting](/rn-codepush/production-control/#targeting-builds) | | No restart during critical UX | `disallowRestart` / `allowRestart` | | Force policy without new binary | Mandatory flag via CLI publish, `patch`, or `promote`; `mandatoryInstallMode` on the client | Bare `sync()` is fine for experiments and internal builds; for production UX and predictable rollouts, explicit options usually matter. The client options above are how you regain control over timing, messaging, and safety without abandoning CodePush’s built-in pipeline. ================================================================================ source: https://docs.codemagic.io/yaml-distributing/aws/ title: Amazon S3 publishing using codemagic.yaml description: How to publish build artifacts to Amazon S3 using codemagic.yaml last_modified: 2026-04-01 ================================================================================ # Amazon S3 publishing using codemagic.yaml > How to publish build artifacts to Amazon S3 using codemagic.yaml In order to publish your web application to AWS S3, you need to configure your access credentials in Codemagic. You can follow the [instructions](https://aws.amazon.com/getting-started/hands-on/backup-to-s3-cli/) provided by Amazon to create your account and get the necessary details. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `AWS_ACCESS_KEY_ID`. 3. Enter the required value as **_Variable value_**. 4. Enter the variable group name, e.g. **_aws_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the process to also add the `AWS_SECRET_ACCESS_KEY` variable. 8. Add the script below to your `scripts` section before your build script to update the S3 bucket. `` refers to a specific folder or file to be synced. Replace `` with your actual bucket name. Note that all the artifact files that Codemagic generates during the build are located in `CM_BUILD_OUTPUT_DIR`. ```yaml environment: groups: - aws_credentials scripts: - name: Update S3 bucket script: | aws s3 sync s3:// ``` Now, each time you build the workflow, the app artifact will be published to your Amazon S3 bucket. Note that the minimal required permission policy attached to the AWS IAM is as follows: ```json { "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::/*" } ] } ``` ================================================================================ source: https://docs.codemagic.io/integrations/fastlane-integration/ title: Fastlane integration description: How to use Fastlane in codemagic.yaml last_modified: 2026-02-16 ================================================================================ # Fastlane integration > How to use Fastlane in codemagic.yaml **Fastlane** is an open source platform aimed at simplifying Android and iOS deployment. If your development team uses Fastlane, it can be used as part of your CI/CD pipeline to build and deploy your applications. Fastlane is preinstalled on the Codemagic build servers. ## Configuring Fastlane in Codemagic In order to use Fastlane with Codemagic, you need to configure the following environment variables: - `MATCH_PASSWORD` - the password used to encrypt/decrypt the repository used to store your distribution certificates and provisioning profiles. - `MATCH_KEYCHAIN` - an arbitrary name to use for the keychain on the build server, e.g "codemagic_keychain" - `MATCH_SSH_KEY` - an SSH private key used for cloning the Match repository that contains your distribution certificates and provisioning profiles. The public key should be added to your Github account. See [here](https://docs.codemagic.io/configuration/access-private-git-submodules/) for more information about accessing Git dependencies with SSH keys. - `APP_STORE_CONNECT_PRIVATE_KEY` - the App Store Connect API key. Copy the entire contents of the .p8 file and paste into the environment variable value field. Make sure to mark it secret in order to encrypt the value. - `APP_STORE_CONNECT_KEY_IDENTIFIER` - the key identifier of your App Store Connect API key. - `APP_STORE_CONNECT_ISSUER_ID` - the issuer of your App Store Connect API key.
1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `MATCH_PASSWORD`. 3. Enter the required value as **_Variable value_**. 4. Enter the variable group name, e.g. **_fastlane_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to add other required variables 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - fastlane - app_store_connect_credentials ``` For further information about using variable groups, please click [here](https://docs.codemagic.io/variables/environment-variable-groups/). ## Cocoapods If you are using dependencies from Cocoapods, it might be necessary to include the "cocoapods" gem in your Gemfile to prevent scope conflict issues. ```ruby gem "fastlane" gem "cocoapods" ``` ## Fastlane plugins If you are using any Fastlane plugins, you should create a script in your `codemagic.yaml` to install them as follows: ```yaml scripts: - name: Install Fastlane plugins script: | cd ios # change to ios/android folder as required bundle add fastlane-plugin-s3 bundle add fastlane-plugin-dropbox ``` ## Running your Fastlane lane In the `codemagic.yaml`, you should install your dependencies with `bundle install` and then execute the Fastlane lane with `bundle exec fastlane ` as follows: ```yaml scripts: - name: Run fastlane script: | bundle install bundle exec fastlane beta ``` If you need to use a specific version of bundler as defined in the `Gemfile.lock` file, you should install it with `gem install bundler:` as follows: ```yaml scripts: - name: Run fastlane script: | gem install bundler:2.2.27 bundle install bundle exec fastlane beta ``` ## Artifacts To gather the .ipa and debug symbols from your build, add the **artifacts** section to your codemagic.yaml as follows: ```yaml artifacts: - ./*.ipa - ./*.dSYM.zip ``` You can find more information about configuring artifacts [here](../yaml-basic-configuration/yaml-getting-started#artifacts) ## Sample project A sample project that shows how to configure Fastlane is available [here](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/fastlane-integration-demo-project). Please refer to the **readme.md**, **Fastfile** and **codemagic.yaml** in the sample project for configuration instructions for your project. ================================================================================ source: https://docs.codemagic.io/knowledge-others/partner-center-authentication/ title: Authenticating with Microsoft services using an Azure AD tenant description: Setting up authentication to Microsoft services last_modified: 2024-07-29 ================================================================================ # Authenticating with Microsoft services using an Azure AD tenant > Setting up authentication to Microsoft services An Azure Active Directory (Azure AD) tenant is required when setting up publishing to Microsoft Store. The tenant is used to access Azure AD to set up the necessary credentials to allow Codemagic to generate temporary access tokens for managing application submissions. ## Setting up the tenant 1. To get started, go to the [Microsoft Partner Center](https://partner.microsoft.com/en-us/dashboard/home), open **Account settings** from the settings menu, and then select **Tenants** under the **Organization profile**. 2. If you already have an existing tenant, you can choose to associate it with your Partner Center account, but we recommend creating a new tenant for use with Codemagic. Click **Create** and fill in all the required information to create a new tenant. 3. The newly created tenant can now be used to access [Azure AD](https://portal.azure.com/) by logging in with the email and password that you created for your tenant. 4. When logged in, navigate to **App registrations** and select **+ New registration**. Give the registration a name, and limit the access to a single tenant under **Supported account types**. For our usecase, the **Redirect URI** can be left blank. Proceed by clicking **Register**. 5. Under **Essentials** you can copy and store the values of the **Directory (tenant) ID** and **Application (client) ID** for later use. Proceed to **Certificates & secrets** on the left-side menu to create your **client secret** by clicking **+ New client secret**. Give the secret a name, and if you do not wish to recreate the secret after a certain time period, set the expiry to **custom** with a long expiry date. Copy and store the **Value** of the newly created secret. 6. As the last step, navigate back to the [Microsoft Partner Center](https://partner.microsoft.com/en-us/dashboard/home) while logged in as the tenant. Navigate to **Account settings > User management > Azure Ad applications** and click **Create Azure Ad application**. In the window that opens, select the application you created in the **Azure AD** portal, click **Next**, and give the application the **developer** role. You have now successfully linked your Azure AD and Microsoft Partner Center accounts and gotten the values for the Tenant ID, Client ID and client secret parameters that have to be used when connecting the Partner Center integration or setting up publishing in `codemagic.yaml`. ================================================================================ source: https://docs.codemagic.io/flutter-notification/email-and-slack-notifications/ title: Email and Slack notifications description: How to configure build status updates with links to artifacts in the Flutter workflow editor last_modified: 2026-06-26 ================================================================================ # Email and Slack notifications > How to configure build status updates with links to artifacts in the Flutter workflow editor ## Email Email publishing settings can be found in **App settings > Notifications > Email**. Email publishing is the only publishing option that is enabled by default. Codemagic uses the email specified as the default one in the service you used to log in (Github, Bitbucket, Gitlab). You can add multiple email addresses. If the build finishes successfully, release notes (if passed) and the generated artifacts will be published to the provided email. The artifact download links in email are, by default, valid for 24 hours. You can configure the lifetime of publicly accessible artifact download links by selecting your personal account or team and navigating to **Settings > Artifact download links**. If the build fails, you will be sent a link to the build logs. Check the **Publish artifacts even if tests fail** option in the workflow editor to publish artifacts even when one or more tests fail. If that option is unchecked, generated artifacts (if there are any) will be attached only to successful builds. ### MS Teams To be able to receive emails from Codemagic to your MS Teams account, please go to your MS Teams account and select **Anyone can send emails to this address** in **Get email address > Advanced settings**. Use only the part in angle brackets from the whole address line (e.g. `My awesome company <543l5kj43.some.address@somedomain.teams.ms>`). ## Slack In order to set up publishing to Slack, you first need to connect the Slack workspace. Navigate to **Personal Account > Settings > Integrations > Slack** to connect Slack for your personal apps or **[Your team] > Settings > Team integrations > Slack** to connect Slack for team apps. Once your Slack workspace is connected, you can enable Slack publishing and select a channel for publishing in **App settings > Notifications > Slack** when using the workflow editor. In order to publish to **private channels**, you need to invite the Codemagic app to the channels, otherwise, the app does not have access to private channels. To invite the Codemagic app to private channels, write `@codemagic` in the channel. If you are in the Codemagic web app, refresh the page, and the new channel will become available in the dropdown menu. If the build finishes successfully, release notes (if passed) and the generated artifacts will be published to the specified channel. The artifact download links in Slack notifications are, by default, valid for 24 hours. You can configure the lifetime of publicly accessible artifact download links by selecting your personal account or team and navigating to **Settings > Artifact download links**. If the build fails, a link to the build logs is published. Check **Publish artifacts even if tests fail** to publish artifacts even when one or more tests fail. If the option is unchecked, generated artifacts (if any) will be attached to successful builds only. To receive a notification when a build starts, check the checkbox **Notify when the build starts**. ## Published artifacts When you set up email or Slack publishing, Codemagic publishes the following artifacts: - `app`, `ipa`, `apk`, the archive with Flutter web build directory, Linux application bundle files, Windows MSIX packages, and .exe files. ** NOTE: We only send emails on successful builds when there are above-mentioned artifact types ** ================================================================================ source: https://docs.codemagic.io/integrations/jenkins-integration/ title: Jenkins integration description: How to integrate Codemagic into your Jenkins workflows using the Codemagic REST API last_modified: 2026-07-06 ================================================================================ # Jenkins integration > How to integrate Codemagic into your Jenkins workflows using the Codemagic REST API Trigger Codemagic builds from Jenkins pipeline stages using the [REST API](/rest-api/builds/). Poll build status from Jenkins, or report results back from `codemagic.yaml` publishing scripts. ## Create a Codemagic API key You need a Codemagic API key to authenticate REST API requests from Jenkins. Every Codemagic account has an API key available in the Account settings. ## Find your Application ID The Application ID uniquely identifies your app in Codemagic API calls. 1. Navigate to your app in Codemagic 2. Look at the app URL: https://codemagic.io/app/xxxxxxxxxxxxxxxxxxxxxxxx 3. Copy the UUID at the end - this is your `AppID`. ## Find your workflow key The workflow key identifies which workflow to trigger. Pass it as `workflowId` in API requests. 1. Navigate to your `codemagic.yaml` file (in Codemagic or in your repository) 2. Copy the **workflow key** under `workflows:` (e.g., `sample-workflow`). This is the value for `workflowId` in API calls—not the optional display `name:` field. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow ``` ## Configuring access to Codemagic in Jenkins Store your Codemagic API key as a Jenkins Secret text credential with ID `codemagic-api-key`. 1. Go to Manage Jenkins → Credentials → System → Global credentials. 2. Click Add Credentials. 3. Set Kind to **Secret text** 4. Set Scope to **Global** 5. Set Secret to `your-codemagic-api-key` 6. Set ID to **codemagic-api-key**. 7. Click OK. ## Trigger a Codemagic build A Pipeline job can send a request to Codemagic with the app, workflow, and branch or tag to build. Learn more about required parameters: [Builds API documentation](/rest-api/builds/#start-a-new-build) > > **Note:** When you start a build through the API, `appId`, `workflowId`, and `branch` or `tag` in the request determine what runs. Trigger and branch filters in `codemagic.yaml` are **not** applied to API-started builds. > The following example triggers a Codemagic build, passes Jenkins metadata as environment variables, and stores the returned `buildId`. JSON is parsed with Groovy's built-in `JsonSlurper` (no extra Jenkins plugin required). If you already use [Pipeline Utility Steps](https://plugins.jenkins.io/pipeline-utility-steps/), `readJSON text: body` is equivalent. For API-only pipelines that do not use the repository on the agent, add `options { skipDefaultCheckout(true) }` to skip an unnecessary SCM checkout. ```groovy pipeline { agent any options { skipDefaultCheckout(true) } environment { CODEMAGIC_APP_ID = 'YOUR_APP_ID' // change to your AppID CODEMAGIC_WORKFLOW = 'YOUR_WORKFLOW_KEY' // workflow key from codemagic.yaml CODEMAGIC_BRANCH = 'YOUR_BRANCH_NAME' // change to your branch name } stages { stage('Trigger Codemagic build') { steps { withCredentials([string(credentialsId: 'codemagic-api-key', variable: 'CODEMAGIC_API_KEY')]) { script { def result = sh( script: """ curl -s -w "\\nHTTP_CODE:%{http_code}" \ -X POST \ -H "Content-Type: application/json" \ -H "x-auth-token: \$CODEMAGIC_API_KEY" \ -d '{ \"appId\": \"${CODEMAGIC_APP_ID}\", \"branch\": \"${CODEMAGIC_BRANCH}\", \"workflowId\": \"${CODEMAGIC_WORKFLOW}\", \"environment\": { \"variables\": { \"BUILD_NUMBER\": \"${env.BUILD_NUMBER}\", \"TRIGGERED_BY\": \"jenkins\" }, \"groups\": [ \"YOUR_VARIABLE_GROUP\" ] } }' \ https://api.codemagic.io/builds """, returnStdout: true ).trim() def parts = result.split('HTTP_CODE:') def body = parts[0].trim() def httpCode = parts[1].trim() if (httpCode == '200') { def build = new groovy.json.JsonSlurper().parseText(body) env.CODEMAGIC_BUILD_ID = build.buildId as String echo "Codemagic build triggered: https://codemagic.io/app/${CODEMAGIC_APP_ID}/build/${build.buildId}" } else { error "Codemagic API returned HTTP ${httpCode}: ${body}" } } } } } } } ``` For release pipelines that build from a Git tag, send `tag` instead of `branch` in the JSON body. You can pass software version overrides in the `environment` object, and `instanceType` at the **top level** of the request body (not inside `environment`). See [Pass custom build parameters](/rest-api/builds/#pass-custom-build-parameters). Variables you pass from Jenkins are available in Codemagic build scripts alongside [built-in environment variables](/yaml-basic-configuration/environment-variables/) (`CM_TRIGGER_SOURCE` is `api` for API-started builds). That includes Jenkins callback variables for the [publishing script](#report-results-back-to-jenkins) when you want per-build URLs without editing Codemagic settings: ```json "environment": { "variables": { "BUILD_NUMBER": "42", "JENKINS_CALLBACK_URL": "https://jenkins.example.com/job/codemagic-callback", "JENKINS_USER": "ci-bot", "JENKINS_API_TOKEN": "…", "JENKINS_TRIGGER_BUILD": "42" } } ``` Store secrets in a Codemagic [environment variable group](/yaml-basic-configuration/environment-variables/) when the values are fixed across builds. If a Jenkins run is aborted while a Codemagic build is in flight, call [Cancel build](/rest-api/builds/#cancel-build) with the stored `buildId`. ## Poll build status Poll `GET https://codemagic.io/api/v3/builds/{buildId}` until the build reaches a terminal status. The v3 response wraps the build under `data`; read **`data.status`**, not a top-level `status` field. | Status | Meaning | | ------ | ------- | | `initializing`, `queued`, `preparing`, `fetching`, `testing`, `building`, `publishing`, `finishing` | In progress — keep polling | | `finished` | Build completed successfully | | `failed`, `canceled`, `timeout`, `skipped` | Build did not complete successfully | There is no separate `success` status — treat `finished` as success. The example below adds a wait stage after the trigger. `codemagicBuildStatus` is marked `@NonCPS` and returns a plain `String` so Jenkins can safely call `sleep()` between polls (parsed JSON objects cannot be held across `sleep()` in Declarative Pipelines). ```groovy @NonCPS String codemagicBuildStatus(String jsonBody) { def parsed = new groovy.json.JsonSlurper().parseText(jsonBody) return parsed.data.status as String } pipeline { agent any environment { CODEMAGIC_APP_ID = 'YOUR_APP_ID' CODEMAGIC_WORKFLOW = 'YOUR_WORKFLOW_KEY' // workflow key from codemagic.yaml CODEMAGIC_BRANCH = 'YOUR_BRANCH_NAME' } stages { stage('Trigger Codemagic build') { steps { withCredentials([string(credentialsId: 'codemagic-api-key', variable: 'CODEMAGIC_API_KEY')]) { script { // ... same trigger script as above ... } } } } stage('Wait for Codemagic build') { steps { withCredentials([string(credentialsId: 'codemagic-api-key', variable: 'CODEMAGIC_API_KEY')]) { script { def terminalStatuses = ['finished', 'failed', 'canceled', 'timeout', 'skipped'] def status = '' while (!terminalStatuses.contains(status)) { def body = sh( script: """ curl -s \ -H "x-auth-token: \$CODEMAGIC_API_KEY" \ https://codemagic.io/api/v3/builds/${env.CODEMAGIC_BUILD_ID} """, returnStdout: true ).trim() status = codemagicBuildStatus(body) echo "Codemagic build status: ${status}" if (!terminalStatuses.contains(status)) { sleep(time: 30, unit: 'SECONDS') } } if (status != 'finished') { error "Codemagic build ${env.CODEMAGIC_BUILD_ID} ended with status: ${status}" } } } } } } } ``` ## Report results back to Jenkins Codemagic runs builds in the cloud. The publishing script sends a POST request to Jenkins when the build finishes, so Jenkins must be reachable at a **public HTTPS URL** (reverse proxy, ingress, and so on). A `localhost` Jenkins URL will not work. ### Create the callback job Create a parameterized Pipeline job that receives the Codemagic result—for example, `codemagic-callback` at `https://jenkins.example.com/job/codemagic-callback`. Define these **string parameters**: | Parameter | Description | | --------- | ----------- | | `CM_BUILD_ID` | Codemagic build ID | | `CM_BUILD_STATUS` | `success` or `failure` | | `CM_ARTIFACT_LINKS` | JSON list of artifact names and URLs ([built-in variable](/yaml-basic-configuration/environment-variables/)) | | `JENKINS_TRIGGER_BUILD` | Optional. Jenkins build number that triggered the Codemagic build | ```groovy pipeline { agent any parameters { string(name: 'CM_BUILD_ID', defaultValue: '') string(name: 'CM_BUILD_STATUS', defaultValue: '') string(name: 'CM_ARTIFACT_LINKS', defaultValue: '') string(name: 'JENKINS_TRIGGER_BUILD', defaultValue: '') } stages { stage('Handle Codemagic result') { steps { echo "Codemagic build ${params.CM_BUILD_ID}: ${params.CM_BUILD_STATUS}" if (params.CM_BUILD_STATUS != 'success') { error "Codemagic build failed" } } } } } ``` ### Configure callback credentials Store `JENKINS_CALLBACK_URL`, `JENKINS_USER`, and `JENKINS_API_TOKEN` in a Codemagic environment variable group, or pass them in the [start-build request](#trigger-a-codemagic-build) `environment.variables` object. - **`JENKINS_CALLBACK_URL`** — Job URL **without** `/buildWithParameters`. Example: `https://jenkins.example.com/job/codemagic-callback`. The publishing script appends `/buildWithParameters`. - **`JENKINS_USER`** — Jenkins username for API access. - **`JENKINS_API_TOKEN`** — A [Jenkins API token](https://www.jenkins.io/doc/book/system-administration/authenticating-scripted-clients/) for that user (**not** the account password). Generate one under the user's profile (for example, click the username → **Security** → **API Token** → **Add new Token**). API token authentication bypasses CSRF protection on `buildWithParameters`; using a password often returns `403` unless CSRF is disabled (not recommended for production). ### Notify Jenkins from codemagic.yaml Add a `publishing` script that runs when the Codemagic build finishes. [Publishing scripts](/yaml-basic-configuration/yaml-getting-started/#publishing) run regardless of build status unless you add conditions. The example below runs build steps first, then creates `~/SUCCESS` only if they all pass. If a script step fails, `~/SUCCESS` is not created and the publishing script reports `failure` to Jenkins. ```yaml workflows: sample-workflow: scripts: - name: Build app script: | # ... your build steps ... - name: Mark build successful script: touch ~/SUCCESS publishing: scripts: - name: Notify Jenkins script: | if [ -f "$HOME/SUCCESS" ]; then STATUS=success else STATUS=failure fi HTTP_CODE=$(curl -s -o /tmp/jenkins-response.txt -w "%{http_code}" \ -X POST "$JENKINS_CALLBACK_URL/buildWithParameters" \ --user "$JENKINS_USER:$JENKINS_API_TOKEN" \ --data-urlencode "CM_BUILD_ID=$CM_BUILD_ID" \ --data-urlencode "CM_BUILD_STATUS=$STATUS" \ --data-urlencode "CM_ARTIFACT_LINKS=$CM_ARTIFACT_LINKS" \ --data-urlencode "JENKINS_TRIGGER_BUILD=$JENKINS_TRIGGER_BUILD") if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then cat /tmp/jenkins-response.txt exit 1 fi ``` `CM_BUILD_ID` and `CM_ARTIFACT_LINKS` are [built-in Codemagic environment variables](/yaml-basic-configuration/environment-variables/). `CM_ARTIFACT_LINKS` is a JSON-encoded list of artifact names and download URLs. If pull request gating runs on GitHub rather than Jenkins, you can report build status with [GitHub Checks](/yaml-notification/github-checks/) instead of—or in addition to—a Jenkins callback. ## Configuring Fastlane Codemagic has Fastlane preinstalled, you can define lanes in `codemagic.yaml` and trigger that workflow from Jenkins with the API steps above. For Match, App Store Connect API keys, and sample `codemagic.yaml` snippets, see [Fastlane integration](/integrations/fastlane-integration/). ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-snap-package/ title: Linux Snap packages description: How to build and release a snap package with codemagic.yaml last_modified: 2025-05-27 ================================================================================ # Linux Snap packages > How to build and release a snap package with codemagic.yaml This guide will illustrate the basic steps necessary for building and publishing your app as a Snap package. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/flutter-snapcraft-example/). > > **Note**: Snap is only available on Linux instances. Make sure to have `instance_type: linux` or `instance_type: linux_x2` in your `codemagic.yaml`. See the build machine specification [here](../specs/versions-linux/). > ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Configure Snap To set up Snap packaging, create a `snapcraft.yaml` file with the necessary configurations according to [Snapcraft guide for Flutter](https://snapcraft.io/docs/flutter-applications) or follow the general [`snapcraft.yaml` guide](https://snapcraft.io/docs/creating-snapcraft-yaml). Optionally, run the `snapcraft snap` command locally to ensure that everything is set up. You should store the `snapcraft.yaml` file in the repository root. Another option is to store `snapcraft.yaml` in the `.snap` folder that is located in repository root. ## Building snap packages Include the `snapcraft snap` command in the `scripts` section of your `codemagic.yaml` file as in the example below. The output of this command is a `.snap` artifact that can later be used for publishing to the Snapcraft Snap Store. ```yaml workflows: snap-build: name: Snapcraft Build instance_type: linux environment: vars: SNAPCRAFT_BUILD_ENVIRONMENT: host scripts: - name: Create a snap script: | snapcraft snap --output flutter-codemagic-example.snap artifacts: - '**/*.snap' ``` Additionally, you may want to install the generated `.snap` package onto your machine for testing. The package will not be code signed unless you publish it to Snap Store, so you would need to use the `--dangerous` flag to install the package without code signing: ```bash snap install your-package.snap --dangerous ``` > > **Note**: In case you are packaging a **Flutter application**, be sure to set `SNAPCRAFT_BUILD_ENVIRONMENT` environment variable to `host`. It is required to avoid virtualization. Read more about virtualization options [here](https://flutter.dev/docs/deployment/linux). Additionally, Snapcraft manages all the dependencies according to `snapcraft.yaml` configuration. There is no need to include the Flutter version in `codemagic.yaml`. > ## Publishing to Snap Store Snap packages can be published to the [Snap Store](https://snapcraft.io/). 1. Generate your Snapcraft credentials file by running the following command locally and providing your Snapcraft account username and password: ```bash snapcraft export-login snapcraft-login-credentials ``` 2. Run the following command and carefully copy/paste the output: ```Shell cat snapcraft-login-credentials | base64 ``` 3. Open your Codemagic app settings, and go to the **Environment variables** tab. 4. Enter the desired **_Variable name_**, e.g. `SNAPCRAFT_LOGIN_CREDENTIALS`. 5. Paste the `base64` encoded credentials from Step 2. as **_Variable value_**. 6. Enter the variable group name, e.g. **_snapcraft_credentials_**. Click the button to create the group. 7. Make sure the **Secret** option is selected. 8. Click the **Add** button to add the variable. 9. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - snapcraft_credentials ``` 10. In the `scripts` section, add steps to base64 decode the credentials file, log in to Snapcraft via CLI, build the snap package and release it to the desired channel. ```yaml scripts: - name: Authenticate with Snap Store script: | echo $SNAPCRAFT_LOGIN_CREDENTIALS | base64 \ --decode > /home/builder/snapcraft-login-credentials snapcraft login --with /home/builder/snapcraft-login-credentials - name: Create a Snap package script: | snapcraft snap --output flutter-codemagic-example.snap - name: Publish to Snap Store script: | snapcraft upload flutter-codemagic-example.snap --release stable ``` ================================================================================ source: https://docs.codemagic.io/yaml-distributing/post-publish/ title: Post-publish scripts description: How to add post-publish scripts in codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Post-publish scripts > How to add post-publish scripts in codemagic.yaml Codemagic has a number of integrations for publishing but you can also publish elsewhere with custom scripts. > > **Note:** Post-publish scripts will be executed even if a build fails. They will stop from being executed only when a build is canceled or times out. You can specify additional conditions using if statements in scripts themselves. > Below are just a few post-publish script examples to illustrate the most common options: #### Publish only if .apk was created ```yaml publishing: email: recipients: - name@example.com scripts: name: Check for apk script: | apkPath=$(find build -name "*.apk" | head -1) if [[ -z ${apkPath} ]] then echo "No .apk was found" else echo "Publishing .apk artifacts" fi ``` #### Report build status ```yaml scripts: - name: Report build start script: # build started . . . - name: Build finished successfully script: touch ~/SUCCESS publishing: scripts: - name: Report build status script: | if [ -f ~/SUCCESS ] ; then # build successful else # build failed fi ``` #### Get artifact links ```yaml publishing: scripts: - name: To get artifact URL script: | ARTIFACT_TYPE=".apk" ARTIFACT_URL=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .url') ``` ================================================================================ source: https://docs.codemagic.io/knowledge-git/private-packages/ title: Using private packages / dependencies description: How to use Github packages for private dependencies last_modified: 2025-10-21 ================================================================================ # Using private packages / dependencies > How to use Github packages for private dependencies Accessing GitHub packages for private dependencies requires the following steps: 1. Create a personal access token in [GitHub](https://github.com/settings/tokens) 2. Open your Codemagic app settings, and go to the **Environment variables** tab. 3. Enter the desired **_Variable name_**, e.g. `GITHUB_TOKEN`. 4. Copy and paste the token as **_Variable value_**. 5. Enter the variable group name, e.g. **_github_credentials_**. Click the button to create the group. 6. Make sure the **Secret** option is selected. 7. Click the **Add** button to add the variable. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - github_credentials ``` 9. Create a **.npmrc** file with the following contents (where @owner is your GitHub username): ```INI registry=https://registry.npmjs.org/ @owner:registry=https://npm.pkg.github.com/ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} ``` or the code below for private registries with your **NPM_TOKEN**: ```INI registry=https://my-private-registry.example.com/ //my-private-registry.example.com/:_authToken=$NPM_TOKEN ``` ###### Debugging issues It is important to note that the Yarn ecosystem behaves differently depending on which version you use. As Yarn 2+ uses Plug'n'Play (PnP) system, it might check `yarnrc.yml` by ignoring `.npmrc`, so it needs to be configured instead: ```INI npmScopes: package_name: npmRegistryServer: "REGISTRY_URL" npmAuthToken: "${NPM_TOKEN}" ``` You can check if you are authorized successfully by running `npm whoami --registry=https://REGISTRY_URL` and if the private package has been published to the registry by running `npm view @PACKAGE_NAME`. An easy way to debug private registry-related issues is by [enabling remote access to the builder machines](https://docs.codemagic.io/troubleshooting/accessing-builder-machine-via-ssh/) at runtime. > > > **Note:** If your builds work fine locally when running `yarn install`, then double-check if you are using the same yarn version with your Codemagic builds. You can downgrade or upgrade it at runtime if necessary: > > ```yaml > - name: Change Yarn version > script: | > corepack disable > npm uninstall -g yarn > npm install -g yarn@1.22.19 > ``` > > ================================================================================ source: https://docs.codemagic.io/knowledge-others/binary-names-update/ title: Custom binary names description: How to change produced binary names for Android and iOS last_modified: 2024-09-16 ================================================================================ # Custom binary names > How to change produced binary names for Android and iOS ## iOS In order to change the file name for the generated **.ipa** artifact, edit the **CFBundleDisplayName** key in the `Info.plist` file. If the app is configured with **flavors**, the **CFBundleName** key needs to be configured with a custom name. ## Android In order to change the artifact file name for Android apps, edit the **archiveBaseName** property in the `app/build.gradle` file. For example, to generate a binary name using your app package name and version: ```Groovy defaultConfig { setProperty("archivesBaseName", applicationId + "-v" + versionCode + "(" + versionName + ")") } ``` To use some arbitrary custom name, set the property as follows: ```Groovy setProperty("archivesBaseName", "YOUR_CUSTOM_NAME") ``` #### Flutter As Flutter does not allow binary names to be changed in `build.gradle`, a temporary workaround is to use the `mv` command. Make sure to reference the new .apk file in the `artifacts` section: ```yaml scripts: - name: Rename the apk and aab file script: | mv build/app/outputs/flutter-apk/app-release.apk \ build/app/outputs/flutter-apk/my_renamed_binary_name-release.apk mv build/app/outputs/bundle/release/app-release.aab \ build/app/outputs/bundle/release/my_renamed_binary_name-release.aab artifacts: - build/app/outputs/flutter-apk/my_renamed_binary_name-release.apk - build/app/outputs/bundle/release/my_renamed_binary_name-release.aab ``` ================================================================================ source: https://docs.codemagic.io/integrations/jira-integration/ title: Jira integration description: How to integrate your workflows with Jira using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Jira integration > How to integrate your workflows with Jira using codemagic.yaml **Jira** is an issue tracking and project management product developed by Atlassian. Many software development teams use it to maintain the visibility of their projects. It offers a REST API that can be used in conjunction with your **Codemagic** workflows to add comments, upload attachments, or transition the status of an issue, story, or epic. > > **Note:** You can find a complete example project showcasing Jira integration in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/jira_integration_demo_project). > ## Configure environment variables To get started, you will need a Jira account (you can [sign up](https://www.atlassian.com/software/jira) for free) and a [Jira API Token](https://id.atlassian.com/manage-profile/security/api-tokens). There are four **environment variables** that need to be configured for the Jira integration: `JIRA_AUTH`, `JIRA_BASE_URL`, `JIRA_ISSUE` and `JIRA_TRANSITION_ID`. To add a variable, follow these steps: 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `JIRA_AUTH`. 3. Enter the required value as **_Variable value_**. 4. Enter the variable group name, e.g. **_jira_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the process to add all of the required variables. #### JIRA_AUTH environment variable The `JIRA_AUTH` environment variable is a `base64` encoded string which consists of the email address you log into Jira with and the Jira API token you created: `email@example.com:` You can encode these credentials in the **macOS Terminal** using: ```bash echo -n 'email@example.com:' | openssl base64 ``` Alternatively, use an online tool to base64 encode this string. This value is used in the Authorization header used in cURL requests to the Jira API. #### JIRA_BASE_URL environment variable This is the subdomain you chose when you set up your Jira account e.g. "YOUR_SUBDOMAIN.atlassian.net". Put the subdomain including "atlassian.net" in the `JIRA_BASE_URL` environment variable. #### JIRA_ISSUE environment variable Issues, epics, and stories have a unique id, usually in the format **'projectKey-id'**, and are visible on your issues either in the bottom right or top left when looking at an issue. Put this value in the `JIRA_ISSUE` environment variable. #### JIRA_TRANSITION_ID environment variable If you want to transition your issue to another status, you will need to know what transition ids are available. You can obtain the available transition ids using a cURL request as documented in the [Jira API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-get). Once you know the transition id then put this value in the `JIRA_TRANSITION_ID` environment variable. ## Adding formatted comments to a Jira issue Create a **.templates** folder in the root of your project. In this folder, create a template file called **jira.json**, which adds formatted comments to a Jira issue. An example **jira.json** file can be found in our [Sample project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/blob/main/integrations/jira_integration_demo_project/.templates/jira.json). The Atlassian Document Format (ADF) is used to format the comment layout and style. Click [here](https://developer.atlassian.com/cloud/jira/platform/apis/document/structure/) for more information about ADF and how to modify this template. ![A formatted Jira issue comment](../uploads/jira_issue_comment.png) **Note** that it contains strings beginning with `$`, which the scripts use to replace values in the JSON using `sed` before it is added as JSON payload to the `cURL` requests. ## Publishing to Jira Publishing to Jira is performed by a script in the `publishing:` section in the `codemagic.yaml`. The example script shown below contains several actions which set environment variables, update the comment template, and then use cURL requests to add a comment and upload files to a specific Jira issue. ### Using jq to parse $CM_ARTIFACT_LINKS First, it uses **jq** (a command-line tool for parsing JSON) to parse the contents of the Codemagic built-in environment variable `$CM_ARTIFACT_LINKS` to find information such as the artifact URL, filename, bundle id, and version name and store the values in environment variables. See this link about the JSON data that [$CM_ARTIFACT_LINKS](../yaml-basic-configuration/environment-variables#artifact-links) contains. ### Setting additional environment variables Additional environment variables are then set, such as the build number, build date, and commit number. These environment variables are used to replace values in the **jira.json** comment template using **sed**, a stream editor for parsing and transforming text. ### Making cURL requests to the Jira API 1. The script performs a request to add a comment to the Jira issue specified using the jira.json as the payload. 2. Another request is used to transition the issue to a different status. 3. The script checks to see if XML test results have been generated. See [here](../testing-yaml/testing/) for information about using `test_report` to generate a test report .xml output. If **xml test results** are available, then they will be uploaded to the Jira issue. 4. If **release notes** have been created, then these are uploaded to the Jira issue. ```yaml publishing: scripts: - name: Post to JIRA script: | #!/bin/sh set -e set -x ARTIFACT_TYPE=".ipa" # Get URL, Name, Bundle Id and Version name from $CM_ARTIFACT_LINKS ARTIFACT_URL=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .url') ARTIFACT_NAME=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .name') TYPE=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .type') BUNDLE=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .bundleId') VERSION_NAME=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'"$ARTIFACT_TYPE"'")) | .versionName') BUILD_VERSION=$(( ${BUILD_NUMBER} + 1 )) # Set the build date BUILD_DATE=$(date +"%Y-%m-%d") # Escape forward slash characters in URL to prevent errors when using sed # to replace the template value TEST_URL=$(echo "${IPA_URL}" | sed 's#/#\\/#g') # Get first 7 digits of commit number COMMIT=$(echo "${CM_COMMIT}" | sed 's/^\(........\).*/\1/;q') # Get the name of the test .xml file so we can attach it to a Jira issue if [ $ARTIFACT_TYPE == ".ipa" ] then XML_TEST_RESULTS=$(find -f build/ios/test/*.xml) else XML_TEST_RESULTS=$(find -f app/build/test-results/**/*.xml) fi # Get the Git commit message for this build GIT_COMMIT_MESSAGE=$(git log --format=%B -n 1 $CM_COMMIT) # Populate the values in the .json template which will be used as the # JSON payload that will be set as a comment in Jira. sed -i.bak "s/\$BUILD_DATE/$BUILD_DATE/" .templates/jira.json sed -i.bak "s/\$ARTIFACT_NAME/$ARTIFACT_NAME/" .templates/jira.json sed -i.bak "s/\$ARTIFACT_URL/$TEST_URL/" .templates/jira.json sed -i.bak "s/\$CM_COMMIT/$COMMIT/" .templates/jira.json sed -i.bak "s/\$GIT_COMMIT_MESSAGE/$GIT_COMMIT_MESSAGE/" .templates/jira.json sed -i.bak "s/\$VERSION_NAME/$VERSION_NAME/" .templates/jira.json sed -i.bak "s/\$BUILD_VERSION/$BUILD_VERSION/" .templates/jira.json sed -i.bak "s/\$BUNDLE/$BUNDLE/" .templates/jira.json sed -i.bak "s/\$TYPE/$TYPE/" .templates/jira.json # Add a comment to Jira # See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-comments/#api-rest-api-3-comment-list-post for details curl -X POST https://$JIRA_BASE_URL/rest/api/3/issue/$JIRA_ISSUE/comment -H "Authorization: Basic $JIRA_AUTH" -H "X-Atlassian-Token: nocheck" -H "Content-Type: application/json" --data @.templates/jira.json | jq "." # Transition Jira issue to another status # See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-transitions-post for details curl -X POST https://$JIRA_BASE_URL/rest/api/3/issue/$JIRA_ISSUE/transitions -H "Authorization: Basic $JIRA_AUTH" -H "X-Atlassian-Token: nocheck" -H "Content-Type: application/json" --data '{"transition":{"id":"'"$JIRA_TRANSITION_ID"'"}}' | jq "." # Attach XML test results to the Jira issue # See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-attachments/#api-rest-api-3-issue-issueidorkey-attachments-post for details if [[ -z ${XML_TEST_RESULTS} ]] then echo "No test results available to upload to JIRA" else curl -X POST https://$JIRA_BASE_URL/rest/api/3/issue/$JIRA_ISSUE/attachments -H "Authorization: Basic $JIRA_AUTH" -H "X-Atlassian-Token: nocheck" -F "file=@$XML_TEST_RESULTS" | jq "." fi # Attach Release Notes to the Jira issue # See https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-attachments/#api-rest-api-3-issue-issueidorkey-attachments-post for details if [[ -e release_notes.txt ]] then curl -X POST https://$JIRA_BASE_URL/rest/api/3/issue/$JIRA_ISSUE/attachments -H "Authorization: Basic $JIRA_AUTH" -H "X-Atlassian-Token: nocheck" -F "file=@release_notes.txt" | jq "." else echo "No release_notes.txt available to upload to JIRA" fi ``` ================================================================================ source: https://docs.codemagic.io/flutter-notification/publish-release-notes/ title: Release notes publishing with Flutter workflow editor description: How to publish build release notes using the Flutter workflow editor last_modified: 2023-12-15 ================================================================================ # Release notes publishing with Flutter workflow editor > How to publish build release notes using the Flutter workflow editor Create custom release notes to notify users of the changes as you publish a new version of your app. Release notes can be published to: - **email**. The release notes will be included in the publishing email of a successful build if you have publishing to email configured in **App settings > Notifications > Email**. - **Slack**. The release notes will be included in the Slack notification of a successful build if you have publishing to Slack configured in **App settings > Notifications > Slack**. - **App Store Connect**. The release notes will be published to App Store Connect if you have publishing to App Store Connect configured in **App settings > Distribution > App Store Connect**. - **Google Play**. The release notes will be published to Google Play Console if you have publishing to Google Play configured in **App settings > Distribution > Google Play**. - **Firebase App Distribution**. The release notes will be published to Firebase console if you have publishing to Firebase App Distribution configured in **App settings > Distribution > Firebase App Distribution**. ## Setting up release notes There are three supported options to set up release notes: 1. Create a `release_notes.txt` file and add it to the project working directory, which is either the repository root directory or the **Project path** specified in the **Build** section in your workflow settings. Codemagic will fetch the content of that file and publish it with the build when it's present. - For email, Slack and Firebase App Distribution, the release notes will be published as is. - For Google Play, the release notes will be published under the `en-US` language localization code. > > **Note:** For App Store Connect, supported languages and codes are listed [here](https://developer.apple.com/documentation/appstoreconnectapi/betabuildlocalizationcreaterequest/data/attributes). For Google Play Console, supported languages and codes are listed [here](https://support.google.com/googleplay/android-developer/table/4419860?hl=en). > 2. Create a `release_notes_.txt` file for every language used, e.g. `release_notes_en-GB.txt`, `release_notes_it.txt`, and add them to the project working directory, which is either the repository root directory or the **Project path** specified in the **Build** section in your workflow settings. - Release notes with the `en-US` language code will be published to email, Slack and Firebase App Distribution in case a file with the `en-US` language code exists. If not, the first found release notes will be published. - For Google Play, all the release notes will be published with corresponding language codes. - For both App Store Connect and Google Play, only the release notes with the supported language codes will be published, omitting language codes that are not supported. 3. Create a `release_notes.json` file with the following content: ```json [ { "language": "en-GB", "text": "British English release notes text" }, { "language": "en-US", "text": "The US English release notes text" } ] ``` Add this file to the project working directory, which is either the repository root directory or the **Project path** specified in the **Build** section in your workflow settings. Notes with missing `language` or `text` fields will not be taken into account. - Release notes with the `en-US` language code will be published to email, Slack and Firebase App Distribution, given that a file with the `en-US` language code exists. If not, the first found release notes will be published. - For both App Store Connect and Google Play, only the release notes with the supported language codes will be published, omitting language codes that are not supported. - It is required to include `What's New` notes for the primary locale while setting up Release notes. ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-unity-app/ title: Unity apps description: How to build Unity mobile apps with codemagic.yaml last_modified: 2026-08-07 ================================================================================ # Unity apps > How to build Unity mobile apps with codemagic.yaml Unity is a cross-platform game engine developed by Unity Technologies. It can be used to create mobile applications that run on iOS and Android. This guide will illustrate all of the necessary steps to successfully build and publish a Unity app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. You can find a complete project showcasing these steps in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/unity/unity-demo-project). ## Unity licensing requirements Building Unity apps in a cloud CI/CD environment requires a Unity **Plus** or a **Pro** license. Your license is used to activate Unity on the Codemagic build server so the iOS and Android projects can be exported. The license is returned during the publishing step of the workflow which is always run **except if the build is cancelled**. You can use [Unity dashboard](https://id.unity.com/en/serials) to check the number of free seats on your license or to manually return a seat if necessary. ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. ### Option: Android #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` ### Option: iOS #### Creating the App Store Connect API key Signing iOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. %!s() ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ##### Using provisioning profiles To apply the profiles to your project during the build, add the following script before your build scripts: ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles # ... your build commands ``` > > See additional configuration options for setting up code signing settings to use given provisioning profiles [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/xcode-project/use-profiles.md) > To distribute signed iOS applications solely to internal testers without the need for Apple's beta review (TestFlight Internal Testing Only): ```yaml scripts: # ... your dependencies installation - name: Set up code signing settings on Xcode project script: xcode-project use-profiles --custom-export-options='{"testFlightInternalTestingOnly": true}' # ... your build commands ``` > > **Note:** Builds marked as TestFlight Internal Only will display "internal" next to the build number and can exclusively be added to internal tester groups. They cannot be submitted for external testing or distributed to customers. > ### Option: macOS #### Creating the App Store Connect API key Signing macOS applications requires [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. It is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > ### Automatic vs Manual code signing Signing macOS apps requires a `Signing certificate` (App Store **development** or **distribution** certificate in `.p12` format) and a `Provisioning profile`. In **Manual code signing** you save these files as Codemagic `Environment variables` and manually reference them in the appropriate build steps. In **Automatic code signing**, Codemagic takes care of Certificate and Provisioning profile management for you. Based on the `certificate private key` that you provide, Codemagic will automatically fetch the correct certificate from the App Store or create a new one if necessary. #### Certificate types There are several certificate types you can choose to sign your macOS app, depending on the distribution method you plan to use. - `MAC_APP_DEVELOPMENT` certificate allows you to build your app for internal testing and debugging. - `MAC_APP_DISTRIBUTION` certificate is used to sign a Mac app before submitting it to the Mac App Store - `MAC_INSTALLER_DISTRIBUTION` is used to sign and submit a Mac Installer Package to the Mac App Store - `DEVELOPER_ID_APPLICATION` is used to sign a Mac app before distributing it outside the Mac App Store - `DEVELOPER_ID_INSTALLER` is used to sign a Mac Installer Package before distributing it outside the Mac App Store For example, in order to publish to Mac App Store, the application must be signed with a `Mac App Distribution` certificate using a `Mac App Store` provisioning profile. If you want to create a `.pkg` Installer package, you must use a `Mac Installer Distribution` certificate. #### Obtaining the certificate private key To enable Codemagic to automatically fetch or create the correct signing certificate on your behalf, you need to provide the corresponding `certificate private key`. You then have to save that key as a Codemagic environment variable. %!s() ### Option: Create a new keyIf the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to Google Play and App Store %!s() ### Option: Android Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` %!s() ### Option: iOSCodemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` #### App Store post processing When publishing your app to TestFlight or the App Store, you will be asked if your app uses encryption. You can automate your answer to this question by setting the key `ITSAppUsesNonExemptEncryption` in your app's `Info.plist` file and set the value to `NO` if the app doesn't use encryption. For more details about complying with encryption export regulations, please see [here](https://developer.apple.com/documentation/security/complying_with_encryption_export_regulations). A Unity post-processing script can be used to set values in the `Info.plist` of the Xcode project. Create a new file `/Assets/Editor/PostProcessing.cs` with the following content: ```csharp using UnityEditor; using UnityEditor.Callbacks; using UnityEditor.iOS.Xcode; using System.IO; public class IosBuildPostprocessor { [PostProcessBuild(1)] public static void EditPlist(BuildTarget target, string path) { if (target != BuildTarget.iOS) return; string plistPath = path + "/Info.plist"; PlistDocument plist = new PlistDocument(); plist.ReadFromFile(plistPath); PlistElementDict rootDict = plist.root; // Add ITSAppUsesNonExemptEncryption to Info.plist rootDict.SetString("ITSAppUsesNonExemptEncryption", "false"); File.WriteAllText(plistPath, plist.WriteToString()); } } ``` ## How caching works for Unity Caching certain directories can significantly speed up the build process by avoiding unnecessary recompilation or re-downloading of dependencies. Here are some directories that you should consider caching: - `Library`: The Library directory in your Unity project contains various generated files, including the Unity package cache, script compilation artifacts, and build settings. - `Temp`: The Temp directory holds temporary files generated during the build process. Caching this directory can prevent redundant regeneration of temporary data, such as asset import caches, asset bundle dependencies, and shader compilations. ### Using Codemagic's caching system You can cache files for each workflow you have by specifying the paths you want to cache like this: ```yaml cache: cache_paths: - $CM_BUILD_DIR/Library - $CM_BUILD_DIR/Temp ``` Please refer to the **cache usage limits** [here](../knowledge-codemagic/caching/#cache-usage-limits). ### Using your own external storage system If your caching step is being skipped because it's exceeding the maximum allowed [cache usage limit](../knowledge-codemagic/caching/#cache-usage-limits) then you can use some external storage to store your caching files. In the following example we are going to use **AWS S3**. #### Using AWS S3 In order to use **AWS S3**, you need to configure your access credentials in Codemagic. You can follow the [instructions](https://aws.amazon.com/getting-started/hands-on/backup-to-s3-cli/) provided by Amazon to create your account and get the necessary credentials. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `AWS_ACCESS_KEY_ID`. 3. Enter the required value as **_Variable value_**. 4. Enter the variable group name, e.g. **_aws_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the process to also add the `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION` variables. 8. Import the **_aws_credentials_** group. Add the script below to your `scripts` section before your build script to check if S3 bucket has an old cached file. ```yaml - name: Check S3 bucket for cached files script: | if echo $(aws s3 ls s3://) | grep -q library-.tar.gz ; then echo "Caching files were found in the S3 bucket."; aws s3 cp s3:///library-.tar.gz ${CM_BUILD_DIR} gunzip < library-.tar.gz | tar -xv else echo "No caching files were found in the S3 bucket."; fi ``` > > Replace `` with your actual bucket name and `` with your app name. > At the publishing section add this script to make a copy of your Library folder and upload it. ```yaml publishing: scripts: - name: Uploading caching files to S3 bucket script: | tar -cv Library/ | gzip > library-.tar.gz aws s3 cp library-.tar.gz s3:// ``` It's important to note that the effectiveness of caching depends on the nature of your project and how frequently different directories change. It's recommended to experiment with caching different directories and measure the impact on your build times to find the optimal configuration for your Codemagic pipeline. ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. %!s() ### Option: AndroidWhile this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/knowledge-others/script-to-create-env-file/ title: Creating a local .env file description: How to create a local .env file last_modified: 2026-06-05 ================================================================================ # Creating a local .env file > How to create a local .env file You can create a `.env` file during the build process by adding a script in the pre-build phase of the Workflow editor or within your `yaml` file. This script will generate a local `.env` file and populate it with the necessary variables during the build. ```yaml scripts: - name: Create local .env file script: | echo "MY_VAR=$MY_VAR" > .env echo "ANOTHER_VAR=$MY_ANOTHER_VAR" >> .env echo "AND_ANOTHER_VAR=$AND_ANOTHER_VAR" >> .env ``` > > NOTE: using `>>` after the first line appends lines to the file > The variables with $ in the above script can be imported from Codemagic UI. For more details, refer to this [document](../yaml-basic-configuration/using-environment-variables/). `For Windows`, PowerShell requires a different command for this case: ```powershell cmd.exe /c "echo "MY_VAR=$env:VAR_NAME" > .env" ``` ================================================================================ source: https://docs.codemagic.io/knowledge-firebase/firebase-crashlytics-dsym-uploading/ title: Firebase Crashlytics dSYM uploading description: Enhancing Crash Log Debugging with dSYM files last_modified: 2026-06-26 ================================================================================ # Firebase Crashlytics dSYM uploading > Enhancing Crash Log Debugging with dSYM files **dSYM** files store the debug symbols for your app. They contain mapping information to decode a stack-trace into a readable format. The purpose of **dSYM** is to replace symbols in the crash logs with the specific methods so they will be readable and helpful for debugging the crash. A sample project for uploading **dSYM** files to Firebase Crashlytics can be found in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/firebase_crashlytics_demo_project). ### How to upload dSYM artifacts to Firebase Crashlytics using codemagic.yaml Flutter automatically generates the app’s dSYM file when building an iOS archive with: ```yaml flutter build ipa ``` or ```yaml flutter build ios --release ``` Crashlytics must also be added to your app: ```yaml flutter pub add firebase_crashlytics ``` or by adding **firebase_crashlytics** dependency manually in the **pubspec.yaml** file: ```yaml dependencies: flutter: sdk: flutter firebase_crashlytics: ^latest ``` As soon as your build finishes successfully, debug symbols are generated. However, if you want them to be displayed in the Codemagic UI on the build page, then the following path needs to be configured in `codemagic.yaml` under the artifacts section: ```yaml artifacts: - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM ``` In order to upload the dSYM files to Firebase Crashlytics, add the following script to your `codemagic.yaml` configuration file: ```yaml publishing: scripts: echo "Locating dSYM artifacts..." dsymPath=$(find $CM_BUILD_DIR/build/ios/archive/Runner.xcarchive/dSYMs -name "Runner.app.dSYM" | head -1) if [[ -z "$dsymPath" ]]; then echo "No app dSYM file found, skipping upload." else echo "Uploading dSYM file: $dsymPath" $CM_BUILD_DIR/ios/Pods/FirebaseCrashlytics/upload-symbols \ -gsp ios/Runner/GoogleService-Info.plist \ -p ios "$dsymPath" fi ``` > > **Note:** The sample path uses `Runner.xcarchive` because Flutter iOS projects use `Runner` as the default app target. > If your project was renamed or you manually changed the iOS target name, make sure to update the path accordingly. > The above-mentioned **dsymPath** is Flutter specific and it could change depending on what platform the app is built on. For example, in React Native or Native iOS applications you might use the dsymPath as: ```yaml dsymPath=$(find $CM_BUILD_DIR/build/ios/xcarchive/*.xcarchive -name "*.dSYM" | head -1) ``` Besides, as **Pods** is not located inside the **ios** directory for native iOS apps, the following path needs to be changed as well: ```yaml ls -d -- ios/Pods/* ``` to ```yaml ls -d -- $CM_BUILD_DIR/* ``` If necessary, you can use remote access to the build machine to find the correct path. More information can be found [here](https://docs.codemagic.io/troubleshooting/accessing-builder-machine-via-ssh). For Native iOS apps, in the case of using SwiftPackageManager (SPM) instead of CocoaPods, the following script needs to be added in a post-publishing script: ```yaml publishing: scripts: - name: Upload debug symbols to Firebase Crashlytics script: | echo "Find build artifacts" dsymPath=$(find build/ios/xcarchive/* | head -1) echo "dsyms expected in:" ls -d -- $dsymPath/dSYMs/* dsymFile=$(find $dsymPath/dSYMs -name "*.dSYM" | head -1) if [[ -z ${dsymFile} ]] then echo "No debug symbols were found, skip publishing to Firebase Crashlytics" else echo "Publishing debug symbols in $dsymFile to Firebase Crashlytics" echo $dsymFile ls -d -- $CM_BUILD_DIR/* $HOME/Library/Developer/Xcode/DerivedData/**/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/upload-symbols \ -gsp $CM_BUILD_DIR/ -p ios $dsymFile fi ``` ### How to upload dSYM artifacts to Firebase Crashlytics using Workflow Editor In order to upload the dSYM files to Firebase Crashlytics, add the following script to your **post-publish** script in the Flutter workflow editor: ```yaml echo "Locating dSYM artifacts..." dsymPath=$(find $CM_BUILD_DIR/build/ios/archive/Runner.xcarchive/dSYMs -name "Runner.app.dSYM" | head -1) if [[ -z "$dsymPath" ]]; then echo "No app dSYM file found, skipping upload." else echo "Uploading dSYM file: $dsymPath" $CM_BUILD_DIR/ios/Pods/FirebaseCrashlytics/upload-symbols \ -gsp ios/Runner/GoogleService-Info.plist \ -p ios "$dsymPath" fi ``` ================================================================================ source: https://docs.codemagic.io/knowledge-others/install-unity-version/ title: Installing a different Unity version description: How to install a different Unity version last_modified: 2026-06-05 ================================================================================ # Installing a different Unity version > How to install a different Unity version ## Quick install (macOS only) If you need to install Unity, you would need to specify the preferred version in your `codemagic.yaml` file like this: ```yaml workflows: unity-workflow: ... environment: unity: YOUR-DESIRED-UNITY-VERSION # e.g. 2021.3.6f1 ``` This will automatically install the specified Unity version to the build machine and set the `UNITY_HOME` to `/Applications/Unity/Hub/Editor//Unity.app` and you can continue building your app as described [here](../yaml-quick-start/building-a-unity-app/). **The available Unity versions are the following:** ### Option: v6000 - LTS versions newer than `6000.0.37f1` are automatically available ### Option: 2023.X - `2023.1.10f1` - `2023.1.17f1` ### Option: 2022.X - `2022.2.16f1` - `2022.3.5f1` - `2022.3.7f1` - `2022.3.10f1` - `2022.3.11f1` - `2022.3.17f1` - `2022.3.19f1` - `2022.3.21f1` - `2022.3.22f1` - `2022.3.29f1` - `2022.3.30f1` - `2022.3.47f1` - `2022.3.62f2` ### Option: 2021.X - `2021.3.4f1` - `2021.3.6f1` - `2021.3.7f1` - `2021.3.9f1` - `2021.3.10f1` - `2021.3.11f1` - `2021.3.12f1` - `2021.3.13f1` - `2021.3.15f1` - `2021.3.20f1` - `2021.3.23f1` - `2021.3.24f1` - `2021.3.27f1` - `2021.3.28f1` - `2021.3.45f2` ### Option: 2020.X - `2020.3.15f2` - `2020.3.21f1` - `2020.3.38f1` - `2020.3.40f1` - `2020.3.41f1` If you can't find your desired Unity version in the list, please contact us via the chat widget in the dashboard, on [GitHub Discussions](https://github.com/orgs/codemagic-ci-cd/discussions) or in [Discord](https://codemagic.io/discord/). > > **Notes:** > - These versions are the `Unity Editor (macOS x86_64)`, and have only the `macOS`, `Android`, and `iOS` modules. > - Mac machines with Apple silicon support Unity built for `x86_64` architecture. > - If your app requires additional modules then you need to install them using [Unity Hub CLI](./-others/install-unity-version/#unity-installation-script) like this: `/Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless install-modules --version -m windows-mono`, this will install the windows modules for the specified` `. > ## Download and install from Unity Hub It is possible to use the Unity Hub CLI to download and install a different Unity Editor version and target support files for that version. License activation and return takes place with the Unity version already installed on the machine, but building of the Xcode project or Android binary will use the version of Unity you install. ### Getting the Unity version number and changeset id In order to install a different version, you can use the info from the `ProjectSettings/ProjectVersion.txt` file which has the unity version and changeset that the project uses. You only need to add this script. ### Option: Mac ```yaml scripts: - name: Retrieve Used Unity Version script: | UNITY_VERSION=$(echo $(sed -n '1p' ProjectSettings/ProjectVersion.txt) | cut -c 18-) UNITY_VERSION_CHANGESET=$(echo $(sed -n '2p' ProjectSettings/ProjectVersion.txt) | cut -d "(" -f2 | cut -d ")" -f1 | xargs) echo "UNITY_VERSION=$UNITY_VERSION" >> $CM_ENV echo "UNITY_VERSION_CHANGESET=$UNITY_VERSION_CHANGESET" >> $CM_ENV echo "UNITY_HOME=/Applications/Unity/Hub/Editor/${UNITY_VERSION}/Unity.app" >> $CM_ENV #to update the default Unity home. ``` ### Option: Windows ```yaml scripts: - name: Retrieve Used Unity Version script: | $env:UNITY_VERSION=(Get-Content ProjectSettings/ProjectVersion.txt -TotalCount 1).Substring(17) $env:UNITY_VERSION_CHANGESET=([regex] "\((.*)\)").match((Get-Content ProjectSettings/ProjectVersion.txt -TotalCount 2)).groups[1].value Add-Content -Path $env:CM_ENV -Value "UNITY_VERSION=$UNITY_VERSION" Add-Content -Path $env:CM_ENV -Value "UNITY_VERSION_CHANGESET=$UNITY_VERSION_CHANGESET" Add-Content -Path $env:CM_ENV -Value "UNITY_HOME=C:\Program Files\Unity\Hub\Editor\$env:UNITY_VERSION\Editor" ``` ### Activating Unity Even though you are installing a different version of Unity to build your apps with, you should activate your license using the default Unity version already installed on the machine. Unity Hub CLI commands do not work correctly if a license is not already active on the machine. ### Unity installation script After activating the Unity license as usual, add the following script to install the desired version and modules you wish to use. The example below uses Unity Hub CLI commands to install the specified Unity version as well as the Android and iOS Build Support modules. ### Option: Mac ```yaml scripts: - name: Install Unity version script: | # To install Unity and its required modules, such as Android-Open-JDK yes Y | /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless install --version $UNITY_VERSION --changeset $UNITY_VERSION_CHANGESET -a arm64 # -a x86_64 yes Y | /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless install-modules --version $UNITY_VERSION -m ios android -a arm64 # -a x86_64 # If you do not need Android-Open-JDK or specific modules # yes n | /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless install --version $UNITY_VERSION --changeset $UNITY_VERSION_CHANGESET -a arm64 # -a x86_64 # yes n | /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless install-modules --version $UNITY_VERSION -m ios android -a arm64 # -a x86_64 ``` > > **Note:** `yes Y` automatically accepts all prompts while `yes n` skips prompts, ensuring no additional downloads or installations. > > ### Option: Windows ```yaml scripts: - name: Install Unity version script: | New-Item ".\install-unity.bat" #create an empty batch file Set-Content install-unity.bat "`"$env:UNITY_HUB`" -- --headless install -v $env:UNITY_VERSION --changeset $env:UNITY_VERSION_CHANGESET" Add-Content install-unity.bat "`"$env:UNITY_HUB`" -- --headless install-modules --version $env:UNITY_VERSION -m ios android" Start-Process -FilePath ".\install-unity.bat" -Wait -NoNewWindow #start executing the batch file ``` ### Building with the newly installed Unity version Use the Unity version you installed on the machine: ### Option: Mac ```yaml scripts: - name: Build the Unity app script: | $UNITY_HOME/Contents/MacOS/Unity -batchmode -quit -logFile -projectPath . -executeMethod BuildScript.$BUILD_SCRIPT -nographics ``` ### Option: Windows ```yaml scripts: - name: Build the Unity app script: | cmd.exe /c "$env:UNITY_VERSION" -batchmode -quit -logFile -projectPath . -executeMethod BuildScript.$env:BUILD_SCRIPT -nographics ``` ### Android Workflow configuration sample ### Option: Mac ```yaml workflows: unity-android-workflow: name: Unity Android Workflow instance_type: linux_x2 max_build_duration: 120 environment: groups: # Add the group environment variables in Codemagic UI (in Application or Team variables) - https://docs.codemagic.io/variables/environment-variable-groups/ - unity # <-- (Includes UNITY_HOME, UNITY_SERIAL, UNITY_EMAIL and UNITY_PASSWORD) - google_play # <-- (Includes GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS <-- Put your google-services.json) vars: UNITY_VERSION: 2019.4.38f1 UNITY_VERSION_CHANGESET: fdbb7325fa47 BUILD_SCRIPT: BuildAndroid PACKAGE_NAME: "io.codemagic.unity" # <-- Put your package name here e.g. com.domain.myapp android_signing: - unity_test triggering: events: - push - tag - pull_request branch_patterns: - pattern: develop include: true source: true scripts: - name: Activate Unity License script: | $UNITY_HOME/Contents/MacOS/Unity -batchmode -quit -logFile -serial ${UNITY_SERIAL} -username ${UNITY_EMAIL} -password ${UNITY_PASSWORD} - name: Install Unity version, build support modules, ndk and jdk script: | /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless install --version ${UNITY_VERSION} --changeset ${UNITY_VERSION_CHANGESET} /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless install-modules --version ${UNITY_VERSION} -m android android-sdk-ndk-tools android-open-jdk - name: Set build number and export Unity script: | export NEW_BUILD_NUMBER=$(($(google-play get-latest-build-number --package-name "$PACKAGE_NAME" --tracks=alpha) + 1)) $UNITY_HOME/Contents/MacOS/Unity -batchmode -quit -logFile -projectPath . -executeMethod BuildScript.$BUILD_SCRIPT -nographics -buildTarget Android artifacts: - android/*.aab - android/*.apk publishing: scripts: - name: Deactivate Unity License script: | $UNITY_HOME/Contents/MacOS/Unity -batchmode -quit -logFile - -returnlicense -username ${UNITY_EMAIL} -password ${UNITY_PASSWORD} ``` ### Option: Windows ```yaml unity-android-workflow: name: Unity Install Older Version Workflow max_build_duration: 120 instance_type: windows_x2 environment: groups: # Add the group environment variables in Codemagic UI (either in Application/Team variables) - https://docs.codemagic.io/variables/environment-variable-groups/ - unity # <-- (Includes UNITY_HOME, UNITY_SERIAL, UNITY_EMAIL and UNITY_PASSWORD) vars: UNITY_VERSION: 2021.3.3f1 UNITY_VERSION_CHANGESET: af2e63e8f9bd BUILD_SCRIPT: BuildAndroid PACKAGE_NAME: "io.codemagic.unity" # <-- Put your package name here e.g. com.domain.myapp android_signing: - unity_test triggering: events: - push branch_patterns: - pattern: "*" include: true cancel_previous_builds: false scripts: - name: Activate Unity License (installed version) script: | cmd.exe /c "$env:$UNITY_HOME/Unity.exe" -batchmode -serial $env:UNITY_SERIAL -username $env:UNITY_EMAIL -password $env:UNITY_PASSWORD -quit -nographics - name: Install Unity version script: | New-Item ".\install-unity.bat" #create an empty batch file Add-Content install-unity.bat "`"C:\Program Files\Unity Hub\Unity Hub.exe`" -- --headless install -v $env:UNITY_VERSION --changeset $env:UNITY_VERSION_CHANGESET" Add-Content install-unity.bat "`C:\Program Files\Unity Hub\Unity Hub.exe`" -- --headless install-modules --version $env:UNITY_VERSION -m android android-sdk-ndk-tools android-open-jdk" Start-Process -FilePath ".\install-unity.bat" -Wait -NoNewWindow #start executing the batch file - name: Build Unity Using (installed version) script: | cmd.exe /c "C:\Program Files\Unity\Hub\Editor\$env:$UNITY_VERSION\Editor\Unity.exe" -batchmode -quit -logFile "$env:CM_BUILD_DIR\\android\\log.txt" -projectPath . -executeMethod BuildScript.$env:BUILD_SCRIPT -nographics artifacts: - android/*.aab - android/*.apk - android/*.txt publishing: scripts: - name: Deactivate new Unity License using a Command Prompt script: | cmd.exe /c "C:\Program Files\Unity\Hub\Editor\$env:$UNITY_VERSION\Editor\Unity.exe" -batchmode -quit -returnlicense -nographics ``` ================================================================================ source: https://docs.codemagic.io/integrations/katalon-integration/ title: Katalon integration description: How to integrate your workflows with Katalon using codemagic.yaml last_modified: 2026-06-05 ================================================================================ # Katalon integration > How to integrate your workflows with Katalon using codemagic.yaml **Katalon** is designed to create and reuse automated test scripts for UI without coding. A sample project that shows how to configure Katalon integration is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/katalon_integration_demo_project). ## Configure Katalon access In order to create a project and retrieve the API key that is used when uploading tests to the Katalon testing environment, you need to [sign up](https://katalon.com/) with Katalon. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `KATALON_API_KEY`. 3. Enter the API key string as **_Variable value_**. 4. Enter the variable group name, e.g. **_katalon_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to add the `KATALON_PROJECT_ID`. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - katalon_credentials ``` 9. Katalon requires that you create a `testops-config.json` file in your project root. In order to avoid exposing your API key in the repository, add a script to create the required file during build time. ```yaml scripts: - name: Create testops-config for Katalon script: | cat >> "testops-config.json" << EOF { "apiKey": "$KATALON_API_KEY", "projectId": "$KATALON_PROJECT_ID", "reportFolder": "testops-report" } EOF ``` ## Jest, Mocha and Jasmine testing In order to execute **jest**, **mocha** and **jasmine** tests and upload the test results to **Katalon**, you need to go through the following steps: #### Install Katalon TestOps plugin ```yaml scripts: - name: Create testops-config for Katalon script: | npm i -s @katalon/testops-jest ``` #### Create files for Jest For Jest, add the following to the `testops-config.json` file created earlier (add these lines to the **Create testops-config for Katalon** script): ```json module.exports = { "reporters": ["default", "@katalon/testops-jest"] } ``` For Jest, also create a file named `./tests/setup.js` with the following content: ```javascript import TestOpsJasmineReporter from "@katalon/testops-jasmine"; const reporter = new TestOpsJasmineReporter(); jasmine.getEnv().addReporter(reporter); ``` #### Run the appropriate command ### Option: Jest ```yaml scripts: - name: Run Katalon command script: npx jest ``` ### Option: Jasmine ```yaml scripts: - name: Run Katalon command script: npx jasmine ``` ### Option: Mocha ```yaml scripts: - name: Run Katalon command script: npx mocha --reporter @katalon/testops-mocha ``` ## Junit reports In order to collect Junit XML reports and submit them to **Katalon**, add the following steps to your scripts section of `codemagic.yaml`: 1. Execute and save test reports to a file by using **test_report** flag. More info about **test_report** flag can be found [here](../yaml-testing/testing/): 2. Install Katalon Report Uploader docker image and complete the upload process ```yaml scripts: - name: Generate test report script: | ./gradlew test test_report: app/build/test-results/**/*.xml - name: Upload to Katalon script: | docker run -t --rm \ -v $CM_BUILD_DIR/app/build/test-results/testReleaseUnitTest/:/katalon/report \ -e PASSWORD=$KATALON_API_KEY \ -e PROJECT_ID=$KATALON_PROJECT_ID\ -e TYPE=junit \ -e REPORT_PATH=/katalon/report katalonstudio/report-uploader:0.0.8 ``` ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-vr-oculus-app/ title: Oculus VR apps with Unity description: How to build a Unity Oculus VR app with codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Oculus VR apps with Unity > How to build a Unity Oculus VR app with codemagic.yaml Unity is a cross-platform game engine developed by Unity Technologies. It allows you to quickly create various types of applications and games and, in particular, it lets you design XR (AR or VR) experiences. The process of building Oculus VR apps with Unity closely follows the steps for building a regular Unity Android project with a couple of extra steps. This guide will illustrate all of the necessary steps to successfully build and publish an Oculus Unity VR app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. ## Prerequisites * Building Unity apps in a cloud CI/CD environment requires a Unity **Plus** or a **Pro** license. Your license is used to activate Unity on the Codemagic build server so the iOS and Android projects can be exported. The license is returned during the publishing step of the workflow which is always run **except if the build is cancelled**. You can use [Unity dashboard](https://id.unity.com/en/serials) to check the number of free seats on your license or to manually return a seat if necessary. * You will also need an Oculus developer account. This account will be used to publish the built Unity app to the Oculus app release channel. You can sign up for the Oculus developer program [here](https://developer.oculus.com/). * An Oculus app associated with your Unity VR app configured for new build uploads in release channels. To learn more about Oculus developer apps and release channels, check out [the Oculus official docs](https://developer.oculus.com/resources/publish-intro/). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Code signing All applications have to be digitally signed before they are made available to the public to confirm their author and guarantee that the code has not been altered or corrupted since it was signed. #### Generating a keystore You can create a keystore for signing your release builds with the Java Keytool utility by running the following command: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` Keytool then prompts you to enter your personal details for creating the certificate, as well as provide passwords for the keystore and the key. It then generates the keystore as a file called **codemagic.keystore** in the directory you're in. The key is valid for 10,000 days. #### Uploading a keystore 1. Open your Codemagic Team settings, and go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **Android keystores** tab. 3. Upload the keystore file by clicking on **Choose a file** or by dragging it into the indicated frame. 4. Enter the **Keystore password**, **Key alias** and **Key password** values as indicated. 5. Enter the keystore **Reference name**. This is a unique name used to reference the file in `codemagic.yaml` 6. Click the **Add keystore** button to add the keystore. For each of the added keystores, its common name, issuer, and expiration date are displayed. > > **Note**: The uploaded keystore cannot be downloaded from Codemagic. It is crucial that you independently store a copy of the keystore file as all subsequent builds released to Google Play should be signed with the same keystore. > > However, keep the keystore file private and do not check it into a public repository. > #### Referencing keystores in codemagic.yaml To tell Codemagic to fetch the uploaded keystores from the **Code signing identities** section during the build, list the reference of the uploaded keystore under the `android_signing` field. Add the following code to the `environment` section of your `codemagic.yaml` file: ```yaml workflows: android-workflow: name: Android Workflow # .... environment: android_signing: - keystore_reference ``` Default environment variables are assigned by Codemagic for the values on the build machine: - Keystore path: `CM_KEYSTORE_PATH` - Keystore password: `CM_KEYSTORE_PASSWORD` - Key alias: `CM_KEY_ALIAS` - Key alias password: `CM_KEY_PASSWORD` ## Configuring Unity license Each Unity build will have to activate a valid Unity Plus or a Unity Pro license using your **Unity email**, **Unity serial number** and the **Unity password**. 1. You can add these as global environment variables in the **Global variables and secrets** section of your Codemagic team settings. Likewise, you can add the environment variables at the application level by clicking the **Environment variables** tab. 2. Enter `UNITY_EMAIL` as the **_Variable name_**. 3. Enter the email address used with your Unity ID as **_Variable value_**. 4. Enter the variable group name, e.g. **_unity_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to also add `UNITY_SERIAL` and `UNITY_PASSWORD` variables. 8. Add the **unity_credentials** variable group to the `codemagic.yaml`: ```yaml environment: groups: - unity_credentials ``` > > **Note:** The `UNITY_HOME` environment variable is already set on the build machines. > > On the macOS Unity base image `UNITY_HOME` is set to `/Applications/Unity/Hub/Editor/2020.3.28f1/Unity.app`. > ## Activating and deactivating the license #### Activation To activate a Unity license on the build machine, add the following step at the top of your `scripts:` section in `codemagic.yaml`: ```yaml scripts: - name: Activate Unity license script: | $UNITY_BIN -batchmode -quit -logFile \ -serial ${UNITY_SERIAL?} \ -username ${UNITY_EMAIL?} \ -password ${UNITY_PASSWORD?} ``` #### Deactivation To deactivate a Unity license on the build machine, add the following script step in the `publishing:` section in `codemagic.yaml`: ### Option: Linux instancesIf the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Oculus distribution Meta Platforms Technologies provides several options for selling and distributing apps on their platform. To learn more about different options, please visit their [official page](https://developer.oculus.com/policy/distribution-options/). To distribute your app to one of their stores, you can use the **Oculus Platform Utility**. This example will showcase distribution to the **Meta Quest Store** but you can find documentation on other available options in the [official Oculus platform utility docs](https://developer.oculus.com/resources/publish-reference-platform-command-line-utility/). ##### Configure Oculus credentials Follow [the official guide](https://developer.oculus.com/resources/publish-reference-platform-command-line-utility/#credentials) to obtain either an **Oculus app ID / App secret** combination or an **Oculus user token**. 1. You can add these as global environment variables in the **Global variables and secrets** section of your Codemagic team settings. Likewise, you can add the environment variables at the application level by clicking the **Environment variables** tab. 2. Enter `OCULUS_APP_ID` as the **_Variable name_**. 3. Enter the corresponding value as **_Variable value_**. 4. Enter the variable group name, e.g. **_oculus_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the process to also add either the `OCULUS_APP_SECRET` or the `OCULUS_USER_TOKEN` variable. 8. Add the **unity_credentials** variable group to the `codemagic.yaml`: ```yaml environment: groups: - oculus_credentials vars: OCULUS_RELEASE_CHANNEL: ALPHA ``` ##### Publish the app Add following script steps to the `publishing:` section in your `codemagic.yaml` file to download the Oculus Platform Utility tool and to upload your app to the store: ```yaml publishing: scripts: - name: Deactivate License script: #... - name: Install Oculus CLI tools script: | wget -O ovr-platform-util \ "https://www.oculus.com/download_app/?id=1462426033810370&access_token=OC%7C1462426033810370%7C" chmod +x ./ovr-platform-util - name: Publish app on an Oculus test release channel script: | ./ovr-platform-util upload-quest-build \ --app_id $OCULUS_APP_ID \ --app_secret $OCULUS_APP_SECRET \ --apk android/android.apk \ --channel $OCULUS_RELEASE_CHANNEL ``` > > **Note:** If you are using Oculus user token to authenticate, replace the last script step with the following: > > ```yaml > > - name: Publish app on an Oculus test release channel > script: | > ./ovr-platform-util upload-quest-build \ > --app_id $OCULUS_APP_ID \ > --token $OCULUS_USER_TOKEN \ > --apk android/android.apk \ > --channel $OCULUS_RELEASE_CHANNEL > > ``` > > ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. ```yaml workflows: unity-oculus-workflow: name: Unity Oculus Workflow max_build_duration: 120 environment: android_signing: - keystore_reference groups: - unity_credentials - oculus_credentials vars: UNITY_BIN: $UNITY_HOME/Contents/MacOS/Unity OCULUS_RELEASE_CHANNEL: ALPHA # <-- Put your release channel name here (cannot be "store" = Production) scripts: - name: Activate Unity License script: | $UNITY_BIN -batchmode -quit -logFile \ -serial ${UNITY_SERIAL?} \ -username ${UNITY_EMAIL?} \ -password ${UNITY_PASSWORD?} - name: Set the build number script: | export NEW_BUILD_NUMBER=$BUILD_NUMBER - name: Build the project script: | $UNITY_BIN -batchmode \ -quit \ -logFile \ -projectPath . \ -executeMethod BuildScript.BuildAndroid \ -nographics \ -buildTarget Android artifacts: - android/*.apk publishing: scripts: - name: Deactivate License script: | /Applications/Unity\ Hub.app/Contents/Frameworks/UnityLicensingClient_V1.app/Contents/MacOS/Unity.Licensing.Client \ --return-ulf \ --username ${UNITY_USERNAME?} \ --password ${UNITY_PASSWORD?} - name: Install Oculus CLI tools script: | wget -O ovr-platform-util \ "https://www.oculus.com/download_app/?id=1462426033810370&access_token=OC%7C1462426033810370%7C" chmod +x ./ovr-platform-util - name: Publish app on a Oculus test release channel script: | ./ovr-platform-util upload-quest-build \ --app_id $OCULUS_APP_ID \ --app_secret $OCULUS_APP_SECRET \ --apk android/android.apk \ --channel $OCULUS_RELEASE_CHANNEL email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` ## Next steps While this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/building-a-dotnet-maui-app/ title: .NET MAUI apps description: How to build a .NET MAUI app with codemagic.yaml last_modified: 2026-06-26 ================================================================================ # .NET MAUI apps > How to build a .NET MAUI app with codemagic.yaml This guide will illustrate all of the necessary steps to successfully build and publish a .NET MAUI app with Codemagic. It will cover the basic steps such as build versioning, code signing and publishing. You can find a complete project showcasing these steps in our [sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/dotnet-maui/dotnet-maui-android-ios/). ## Adding the app to Codemagic The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## Creating codemagic.yaml In order to use `codemagic.yaml` for build configuration on Codemagic, it has to be committed to your repository. The name of the file must be `codemagic.yaml` and it must be located in the root directory of the repository. Detailed explanation can be found [here](../yaml/yaml-getting-started). > > **Tip** > You can find codemagic.yaml examples in [Codemagic Sample Projects](https://github.com/codemagic-ci-cd/codemagic-sample-projects/) repository. > If you prefer to write your `codemagic.yaml` file from scratch, you can start with this minimal configuration. ```yaml workflows: sample-workflow: name: Codemagic Sample Workflow max_build_duration: 120 instance_type: mac_mini_m2 ``` > > **Tip** > You can have more than one workflow in the same `codemagic.yaml` file. If you are building for both Android and iOS, simply enter both workflows as: > ```yaml workflows: android-workflow-id: name: Android Sample Workflow # ....... # ....... # ....... ios-workflow-id: name: iOS Sample Workflow # ...... ``` Scan for the `codemagic.yaml` file by selecting a branch to scan and clicking the **Check for configuration** file button at the top of the page. Note that you can have different configuration files in different branches. ## Install .NET SDK In order to build .NET apps in Codemagic, you first need to install the .NET SDK. The easiest way to do it is by downloading and running the official Install script. ```yaml environment: vars: DOTNET_PATH: $CM_BUILD_DIR/dotnet DOTNET: $CM_BUILD_DIR/dotnet/dotnet scripts: - name: Install .NET SDK script: | wget https://dot.net/v1/dotnet-install.sh chmod +x dotnet-install.sh ./dotnet-install.sh --install-dir $DOTNET_PATH ``` ## Install MAUI Once you have the .NET SDK installed, you can proceed to install the required .NET workloads. ### Option: AndroidIt is recommended to create a dedicated App Store Connect API key for Codemagic in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api). To do so: 1. Log in to App Store Connect and navigate to **Users and Access > Integrations >> App Store Connect API**. 2. Click on the + sign to generate a new API key. 3. Enter the name for the key and select an access level. We recommend choosing `App Manager` access rights, read more about Apple Developer Program role permissions [here](https://help.apple.com/app-store-connect/#/deve5f9a89d7). 4. Click **Generate**. 5. As soon as the key is generated, you can see it added to the list of active keys. Click **Download API Key** to save the private key for later. Note that the key can only be downloaded once. > > Take note of the **Issuer ID** above the table of active keys as well as the **Key ID** of the generated key as these will be required when setting up the Apple Developer Portal integration in the Codemagic UI. > #### Adding the App Store Connect API key to Codemagic 1. Open your Codemagic Team settings, go to **Team integrations** > **Developer Portal** > **Manage keys**. 2. Click the **Add key** button. 3. Enter the `App Store Connect API key name`. This is a human readable name for the key that will be used to refer to the key later in application settings. 4. Enter the `Issuer ID` and `Key ID` values. 5. Click on **Choose a .p8 file** or drag the file to upload the App Store Connect API key downloaded earlier. 6. Click **Save**. #### Adding the code signing certificate Codemagic lets you upload code signing certificates as PKCS#12 archives containing both the certificate and the private key which is needed to use it. When uploading, Codemagic will ask you to provide the certificate password (if the certificate is password-protected) along with a unique **Reference name**, which can then be used in the `codemagic.yaml` configuration to fetch the specific file. %!s() ### Option: Upload certificate 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Upload the certificate file by clicking on **Choose a .p12 or .pem file** or by dragging it into the indicated frame. 4. Enter the **Certificate password** and choose a **Reference name**. 5. Click **Add certificate** ### Option: Generate new certificate If you have added the **App Store Connect API key** to Codemagic, you can also generate a new `Apple Development` or `Apple Distribution` certificate. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Generate certificate**. 4. Provide a **Reference name** for the certificate. 5. Choose the **Certificate type**. 6. Select the **App Store Connect API key** to use. 7. Click **Create certificate**. Once the certificate has been created, Codemagic will allow you to download the certificate and provides the password for it. After downloading, please follow the steps in the **Upload certificate** tab to upload the certificate to Codemagic. > > **Note**: The certificate can be downloaded **only once**, right after creating it. >
> > **Note**: Apple limits the number of `Apple Distribution` certificates to 3. If you have already reached the maximum number of certificates, the following error will be displayed: > > > ```bash > > There is a problem with the request entity - You already have a current Distribution certificate or a pending certificate request. > > ``` > > > Similar errors can also arise in rarer cases with `Apple Development` certificates. To resolve the error, either remove some old certificate from the Apple Developer Portal or upload an existing certificate manually. > ### Option: Fetch from Developer Portal Existing signing certificates previously generated by Codemagic can be automatically fetched from Apple Developer Portal based on your team's App Store Connect API key. Fetching a certificate that was not generated by Codemagic is not possible because each certificate is linked with a private signing key to which Codemagic has no access. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS certificates** tab. 3. Click **Fetch certificate**. 4. Select a certificate from the **Development certificates** or **Distribution certificates** list. 5. Click **Fetch selected**. #### Adding the provisioning profile Codemagic allows you to upload a provisioning profile to be used for the application or to fetch a profile from the Apple Developer Portal. The profile's type, team, bundle id, and expiration date are displayed for each profile added to Code signing identities. Furthermore, Codemagic will let you know whether a matching code signing certificate is available in Code signing identities (a green checkmark in the **Certificate** field) or not. ### Option: Upload a profile You can upload provisioning profiles with the `.mobileprovision` extension, providing a unique **Reference name** is required for each uploaded profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Upload the provisioning profile file by clicking on **Choose a .mobileprovision file** or by dragging it into the indicated frame. 4. Enter the **Reference name** for the profile. 5. Click **Add profile**. > > **Note:** If your app contains app extensions, an additional provisioning profile is required for each extension. Codemagic will use the bundle identifier to find the relevant provisioning profiles. If your bundle identifier is `com.example.app`, the matching profiles are the ones with `com.example.app` and `com.example.app.*` as bundle identifier. > ### Option: Fetch from Developer Portal You can automatically fetch the provisioning profiles from the Apple Developer Portal based on your team's App Store Connect API key. The bundle identifier is listed for every available profile along with its name. The profiles are displayed grouped by category: `Development profiles`, `Ad Hoc profiles`, `App Store profiles`, and `Enterprise profiles`. For each selected profile, it is necessary to provide a unique **Reference name**, which can be later used in `codemagic.yaml` to fetch the profile. 1. Open your Codemagic Team settings, go to **codemagic.yaml settings** > **Code signing identities**. 2. Open **iOS provisioning profiles** tab. 3. Click **Fetch profiles** 4. Select the desired profile(s) and enter a **Reference name** for each one. 5. Click **Download selected**. (scroll down if necessary)
> > **Note:** When you make essential changes to a provisioning profile, such as modifying the app ID, adding/removing capabilities from the profile identifier, or changing the certificates assigned to that profile, the provisioning profile becomes invalid. In such situations, you need to generate a new provisioning profile with these updates and then re-upload it to Codemagic. > #### Referencing certificates and profiles in codemagic.yaml To fetch all uploaded signing files matching a specific distribution type and bundle identifier during the build, define the `distribution_type` and `bundle_identifier` fields in your `codemagic.yaml` configuration. Note that it is necessary to configure **both** of the fields. ```yaml workflows: ios-workflow: name: iOS Workflow # .... environment: ios_signing: distribution_type: app_store # or: ad_hoc | development | enterprise bundle_identifier: com.example.id ``` > > **Note:** If you are publishing to the **App Store** or you are using **TestFlight** to distribute your app to test users, set the `distribution_type` to `app_store`. > > When using a **third party app distribution service** such as Firebase App Distribution, set the `distribution_type` to `ad_hoc` > When defining the bundle identifier `com.example.id`, Codemagic will fetch any uploaded certificates and profiles matching the extensions as well (e.g. `com.example.id.NotificationService`). ## Configure scripts to build the app Add the following scripts to your `codemagic.yaml` file in order to prepare the build environment and start the actual build process. In this step you can also define the build artifacts you are interested in. These files will be available for download when the build finishes. For more information about artifacts, see [here](../yaml/yaml-getting-started/#artifacts). ### Build versioning If you are going to publish your app to App Store Connect or Google Play, each uploaded artifact must have a new version satisfying each app store’s requirements. Codemagic allows you to easily automate this process and increment the version numbers for each build. For more information and details, see [here](../configuration/build-versioning). In .NET MAUI, app version and build number are determined by `ApplicationDisplayVersion` and `ApplicationVersion` properties set either in the `.csproject` file or passed via command line. Using Codemagic CLI, you can easily fetch the latest published build version from the respective store and automatically increment it for each new build. ### Code signing In order to code sign the app, the appropriate properties must be configured either in the `csproject` file or passed via command line. #### Android When using the default Codemagic code signing method (codesigning identities), the required environment variables will already be available for use in command line arguments. #### iOS When using the default Codemagic code signing method (codesigning identities), the correct certificate and provisioning profile will be automatically prepared. However, since the dotnet build command requires referencing the signing certificate and the provisioning profile by name, two additional script commands are necessary to get those values. Alternatively, you can enter the correct values as strings manually. ### Build script example This is an example of the final script, including build versioning, code signing and the app building steps. ### Option: Android Codemagic offers a wide array of options for app publishing and the list of partners and integrations is continuously growing. For the most up-to-date information, check the guides in the **Configuration > Publishing** section of these docs. To get more details on the publishing options presented in this guide, please check the [Email publishing](../yaml-publishing/email), the [Google Play Store](../yaml-publishing/google-play) publishing and the [App Store Connect](../yaml-publishing/app-store-connect). #### Email publishing If the build finishes successfully, release notes (if passed), and the generated artifacts will be published to the provided email address(es). If the build fails, an email with a link to build logs will be sent. If you don’t want to receive an email notification on build success or failure, you can set `success` to `false` or `failure` to `false` accordingly. ```yaml workflows: sample-workflow-id: environment: # ... scripts: # ... publishing: email: recipients: - user_1@example.com - user_2@example.com notify: success: true failure: false ``` #### Publishing to Google Play and App Store %!s() ### Option: Android Publishing apps to Google Play requires you to set up a service account in Google Play Console and save the content of the `JSON` key file to a secret environment variable as explained above in **Android Build Versioning** steps 1-5. Configuring Google Play publishing is simple as you only need to provide credentials and choose the desired track. If the app is in `draft` status, please also include the `submit_as_draft: true` or promote the app status in Google Play. ```yaml react-native-android: # ... publishing: # ... google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` %!s() ### Option: iOSCodemagic enables you to automatically publish your iOS or macOS app to [App Store Connect](https://appstoreconnect.apple.com/) for beta testing with [TestFlight](https://developer.apple.com/testflight/) or distributing the app to users via App Store. Codemagic uses the **App Store Connect API key** for authenticating communication with Apple's services. You can read more about generating an API key from Apple's [documentation page](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api). Please note that: 1. for App Store Connect publishing, the provided key needs to have [App Manager permission](https://help.apple.com/app-store-connect/#/deve5f9a89d7), 2. and in order to submit your iOS application to App Store Connect, it must be code signed with a distribution [certificate](https://developer.apple.com/support/certificates/). The following snippet demonstrates how to authenticate with and upload the IPA to App Store Connect, submit the build to beta tester groups in TestFlight and configure releasing the app to App Store. See additional configuration options for App Store Connect publishing [here](https://github.com/codemagic-ci-cd/cli-tools/blob/master/docs/app-store-connect/publish.md). > **Note:** Please note that you will need to create an **app record** in App Store Connect before you can automate publishing with Codemagic. It is recommended to upload the very first version of the app manually. Suppose you have set up an **app record** but have not manually uploaded the app's first version. In that case, manual configuration of the settings must be done on App Store Connect after the build is complete, such as uploading the required screenshots and providing the values for the privacy policy URL and application category. ```yaml # Integration section is required to make use of the keys stored in # Codemagic UI under Apple Developer Portal integration. integrations: app_store_connect: publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration # Configuration related to TestFlight (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to TestFlight beta review. Required for distributing to beta groups. # Note: This action is performed during post-processing. submit_to_testflight: true # Optional boolean, defaults to false. Set to true to automatically expire # previous build in review or waiting for review in Testflight before # submitting a new build to beta review. Expired builds will no longer be available for testers. # Note: This action is performed during post-processing. expire_build_submitted_for_review: true # Specify the names of beta tester groups that will get access to the build # once it has passed beta review. beta_groups: - group name 1 - group name 2 # Configuration related to App Store (optional) # Optional boolean, defaults to false. Whether or not to submit the uploaded # build to App Store review. Note: This action is performed during post-processing. submit_to_app_store: true # Optional boolean, defaults to false. Set to true to cancel the previous # submission (if applicable) when submitting a new build to App Store review. # This allows automatically submitting a new build for review if a previous submission exists. # Note: This action is performed during post-processing. cancel_previous_submissions: true # Optional, defaults to MANUAL. Supported values: MANUAL, AFTER_APPROVAL or SCHEDULED release_type: SCHEDULED # Optional. Timezone-aware ISO8601 timestamp with hour precision when scheduling # the release. This can be only used when release type is set to SCHEDULED. # It cannot be set to a date in the past. earliest_release_date: 2021-12-01T14:00:00+00:00 # Optional. The name of the person or entity that owns the exclusive rights # to your app, preceded by the year the rights were obtained. copyright: 2021 Nevercode Ltd # Optional boolean. Whether or not to release an App Store version update in phases. # With this option turned on, your version update will be released over a 7-day period # to a percentage of your users (selected at random by their Apple ID) with automatic # updates turned on. Learn more from # https://developer.apple.com/help/app-store-connect/update-your-app/release-a-version-update-in-phases. # If not specified, then App Store version default phased release configuration is reused. phased_release: true ``` ## Conclusion Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to build, code sign, automatically version and publish your project using Codemagic CI/CD. Save your work, commit the changes to the repository, open the app in the Codemagic UI and start the build to see it in action. Your final `codemagic.yaml` file should look something like this: ```yaml workflows: maui-ios: name: Dotnet MAUI iOS max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: codemagic-api environment: ios_signing: distribution_type: app_store bundle_identifier: io.codemagic.maui.weather vars: DOTNET_PATH: $CM_BUILD_DIR/dotnet DOTNET: $CM_BUILD_DIR/dotnet/dotnet APP_STORE_APPLE_ID: 6444530615 BUNDLE_ID: "io.codemagic.maui.weather" scripts: - name: Install dotnet sdk script: | wget https://dot.net/v1/dotnet-install.sh chmod +x dotnet-install.sh ./dotnet-install.sh --install-dir $DOTNET_PATH - name: Install MAUI script: | $DOTNET nuget locals all --clear $DOTNET workload install ios maui \ --source https://aka.ms/dotnet6/nuget/index.json \ --source https://api.nuget.org/v3/index.json - name: Set Info.plist values script: | # Automatically fill out the encryption compliance setting PLIST=$CM_BUILD_DIR/src/WeatherTwentyOne/Platforms/iOS/Info.plist PLIST_BUDDY=/usr/libexec/PlistBuddy $PLIST_BUDDY -c "Add :ITSAppUsesNonExemptEncryption bool false" $PLIST - name: Set build version and build the app script: | LATEST_BUILD_NUMBER=$(app-store-connect get-latest-testflight-build-number "$APP_STORE_APPLE_ID") if [ -z $LATEST_BUILD_NUMBER ]; then UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_BUILD_NUMBER + 1)) fi CERT_NAME=$(keychain list-certificates | jq -r '.[] | .common_name') PROFILE_NAME=$(find ~/Library/MobileDevice/Provisioning\ Profiles -name "*.mobileprovision" -execdir sh -c '/usr/libexec/PlistBuddy -c "print :Name" /dev/stdin <<< $(security cms -D -i {})' \;) cd src $DOTNET publish -f net6.0-ios \ -c Release \ -p:BuildIpa=True \ -p:ApplicationDisplayVersion="1.0.0" \ -p:ApplicationVersion=$UPDATED_BUILD_NUMBER \ -p:RuntimeIdentifier=ios-arm64 \ -p:CodesignKey="$CERT_NAME" \ -p:CodesignProvision="$PROFILE_NAME" \ -o ../artifacts artifacts: - ./artifacts/*.ipa publishing: app_store_connect: auth: integration maui-android: name: Dotnet MAUI Android max_build_duration: 120 instance_type: mac_mini_m2 environment: android_signing: - codemagic-key groups: - google_play vars: DOTNET_PATH: $CM_BUILD_DIR/dotnet DOTNET: $CM_BUILD_DIR/dotnet/dotnet PACKAGE_NAME: "io.codemagic.maui.weather" scripts: - name: Install dotnet sdk script: | wget https://dot.net/v1/dotnet-install.sh chmod +x dotnet-install.sh ./dotnet-install.sh --install-dir $DOTNET_PATH - name: Install MAUI script: | $DOTNET nuget locals all --clear $DOTNET workload install android maui \ --source https://aka.ms/dotnet6/nuget/index.json \ --source https://api.nuget.org/v3/index.json - name: Build script: | LATEST_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME") if [ -z $LATEST_BUILD_NUMBER ]; then UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_BUILD_NUMBER + 1)) fi cd src $DOTNET publish -f net6.0-android \ -c Release \ -p:AndroidKeyStore=True \ -p:AndroidSigningKeyStore=$CM_KEYSTORE_PATH \ -p:AndroidSigningKeyAlias=$CM_KEY_ALIAS \ -p:AndroidSigningKeyPass=$CM_KEY_PASSWORD \ -p:AndroidSigningStorePass=$CM_KEYSTORE_PASSWORD \ -p:ApplicationVersion=$UPDATED_BUILD_NUMBER \ -p:ApplicationDisplayVersion="1.0.0" \ -o ../artifacts artifacts: - /Users/builder/clone/artifacts/*Signed.aab publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal submit_as_draft: true ``` ## Next steps While this basic workflow configuration is incredibly useful, it is certainly not the end of the road and there are numerous advanced actions that Codemagic can help you with. We encourage you to investigate [Running tests with Codemagic](../yaml-testing/testing) to get you started with testing, as well as additional guides such as the one on running tests on [Firebase Test Lab](../yaml-testing/firebase-test-lab) or [Registering iOS test devices](../yaml-testing/ios-provisioning). Documentation on [using codemagic.yaml](../yaml/yaml-getting-started) teaches you to configure additional options such as [changing the instance type](../yaml/yaml-getting-started/#instance-type) on which to build, or configuring builds to be [automatically triggered](https://docs.codemagic.io/yaml/yaml-getting-started/#triggering) on repository events. %!s() ================================================================================ source: https://docs.codemagic.io/knowledge-others/flutter-shader-generation/ title: Flutter Shader Compilation description: How to build Android and iOS apps with Flutter shader compilation enabled. last_modified: 2022-09-27 ================================================================================ # Flutter Shader Compilation > How to build Android and iOS apps with Flutter shader compilation enabled. Flutter provides command line tools for app developers to collect shaders in the **SkSL** (Skia Shader Language) format that end users may require. The SkSL shaders can then be bundled into the app and pre-compiled when an end-user first launches the app, reducing compilation jank in subsequent animations. You can check the official Flutter documentation for more details [here](https://docs.flutter.dev/perf/shader). Steps to build with Flutter shader compilation. 1. Build the app in `profile` mode in your local machine with **actual device connected**. Play around with the app to trigger as many animations as you need, especially the ones with compilation jank. ```bash flutter run --profile --cache-sksl --purge-persistent-cache ``` 2. Press **M** at the `flutter run` command line to save the captured SkSL shaders to a file called `flutter_01.sksl.json` in your root directory. 3. Commit the file to your Github Repository. 4. Build the app with SkSL warm-up with your Codemagic Workflow by passing the additional argument `--bundle-sksl-path flutter_01.sksl.json` to your build command. For e.g ```yaml scripts: - name: Build Flutter script: | flutter build ipa --bundle-sksl-path flutter_01.sksl.json ``` > > **Note:** The flutter profile mode is available only on actual iOS/Android Devices. It might not run properly on the simulator/emulator. You can check the official Flutter documentation for the flutter profile mode [here](https://github.com/flutter/flutter/wiki/Flutter%27s-modes). > > You can refer to the FAQs related to Flutter shader compilation [here](https://docs.flutter.dev/perf/shader#frequently-asked-questions). > ================================================================================ source: https://docs.codemagic.io/integrations/kobiton-integration/ title: Kobiton integration description: How to integrate your workflows with Kobiton using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Kobiton integration > How to integrate your workflows with Kobiton using codemagic.yaml **Kobiton** is a mobile testing platform that accelerates delivery and testing of mobile apps by offering manual and automated testing on real devices, in cloud & on-premises. A sample project that shows how to configure Kobiton integration is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/kobiton_integration_demo_project). ## Configure Kobiton access Once you [sign up](https://kobiton.com/) with Kobiton, make note of your **username** and **API access token**. You need to combine these to get the `base64` encoded authentication string formatted as: `username:api_token` You can encode these credentials in the **macOS Terminal** using: ```bash echo -n ':' | openssl base64 ``` Alternatively, use an [online tool](https://mixedanalytics.com/knowledge-base/api-connector-encode-credentials-to-base-64/) to base64 encode this string. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `KOBITON_CREDENTIALS`. 3. Copy and paste the `base64` encoded authentication string as **_Variable value_**. 4. Enter the variable group name, e.g. **_kobiton_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - kobiton_credentials ``` ## Configure your project **Kobiton** offers to test your generated binaries **(.ipa, .apk, .aab and zip)** on real devices by automating them. To get started, you need to inject the following capabilities into your project’s test scripts such as Appium: ### Option: Android ```java String kobitonServerUrl = "https://nihalnevercode:c0eb5ab4-3f3f-43c0-9325-1ea473349ca8@api.kobiton.com/wd/hub"; DesiredCapabilities capabilities = new DesiredCapabilities(); // The generated session will be visible to you only. capabilities.setCapability("sessionName", "Automation test session"); capabilities.setCapability("sessionDescription", ""); capabilities.setCapability("deviceOrientation", "portrait"); capabilities.setCapability("captureScreenshots", true); capabilities.setCapability("useConfiguration", ""); capabilities.setCapability("autoWebview", true); capabilities.setCapability("browserName", "chrome"); capabilities.setCapability("deviceGroup", "KOBITON"); // For deviceName, platformVersion Kobiton supports wildcard // character *, with 3 formats: *text, text* and *text* // If there is no *, Kobiton will match the exact text provided capabilities.setCapability("deviceName", "Galaxy S21 Ultra 5G"); capabilities.setCapability("platformVersion", "12"); capabilities.setCapability("platformName", "Android"); ``` ### Option: iOS ```java String kobitonServerUrl = "https://nihalnevercode:c0eb5ab4-3f3f-43c0-9325-1ea473349ca8@api.kobiton.com/wd/hub"; DesiredCapabilities capabilities = new DesiredCapabilities(); // The generated session will be visible to you only. capabilities.setCapability("sessionName", "Automation test session"); capabilities.setCapability("sessionDescription", ""); capabilities.setCapability("deviceOrientation", "portrait"); capabilities.setCapability("browserName", "safari"); capabilities.setCapability("deviceGroup", "KOBITON"); // For deviceName, platformVersion Kobiton supports wildcard // character *, with 3 formats: *text, text* and *text* // If there is no *, Kobiton will match the exact text provided capabilities.setCapability("deviceName", "iPad Air 2 (Wi-Fi)"); capabilities.setCapability("platformVersion", "15.3.1"); capabilities.setCapability("platformName", "iOS"); ``` These capabilities will allow Kobiton to detect which platform you want to execute your test scripts with. Device-specific capabilities for Java can be found in the **Kobiton devices list** by clicking **device settings** and then **Automation Settings**. ## Upload apps to Kobiton The process of uploading your artifacts to **Kobiton** requires the following steps: - Set the `APP_URL` and `APP_PATH` to upload to AWS S3 bucket - Upload artifacts to AWS S3 - Upload to Kobiton environment - \[Optional\] Get the URL in Codemagic Logs to be directed to test details To perform these steps, add the required scripts to your `codemagic.yaml` file: ```yaml scripts: - name: Set the app URL and PATH script: | CURL_RESULT=$(curl -X POST https://api.kobiton.com/v1/apps/uploadUrl \ -H 'Authorization: Basic $KOBITON_CREDENTIALS' \ -H 'Content-Type: application/json' \ -d '{"filename": "your_desired_binary_name.ipa"}' | jq -r) APP_URL=$(jq -r '.url' <<<"$CURL_RESULT") APP_PATH=$(jq -r '.appPath' <<<"$CURL_RESULT") - name: Upload artifacts to AWS script: | curl -X PUT “$APP_URL” \ -H 'content-type: application/octet-stream' \ -H 'x-amz-tagging: unsaved=true' \ -T "build/ios/ipa/kobition_integration.ipa" - name: Upload to Kobiton script: | curl -X POST https://api.kobiton.com/v1/apps \ -H 'Authorization: Basic $KOBITON_CREDENTIALS' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -d '{"appPath": “’”$APP_PATH”’”}’ - name: Get URL for logs script: | curl -X POST https://api.kobiton.com/v1/revisitPlans/create \ -H 'Authorization: Basic $KOBITON_CREDENTIALS' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' # Response should be formatted as: # {"testRunId":123168,"testRunDetailLink":"https://portal.kobiton.com/plans/123168/executions"} ``` > > **Note:** The above example uploads an `.ipa` to Kobiton. Adjust the paths and file names if you are building on Android or using a different artifact type. > After a successful upload, you should get **appId** and **versionId** in the Codemagic logs. After the whole process, check your App section in the Kobiton UI and you should see your uploaded binary there. ================================================================================ source: https://docs.codemagic.io/knowledge-firebase/load-firebase-configuration/ title: Loading Firebase configuration description: How to load Firebase configuration files into environment variables in a Flutter workflow editor pre-build script last_modified: 2026-06-05 ================================================================================ # Loading Firebase configuration > How to load Firebase configuration files into environment variables in a Flutter workflow editor pre-build script Instead of committing the Firebase configuration files to your repository, you can upload them to Codemagic as **environment variables** and reference them in a custom script. Save the **contents** of Firebase config files as environment variables, e.g. `ANDROID_FIREBASE_SECRET` and `IOS_FIREBASE_SECRET` in the Codemagic UI (either in Application or Team variables) and select **Secret**. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `ANDROID_FIREBASE_SECRET` or `IOS_FIREBASE_SECRET`. 3. Copy and paste the config file content as **_Variable value_**. 4. Enter the variable group name, e.g. **_firebase_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - firebase_credentials ``` 8. Add the following **pre-build** script echoing your variables to load the Firebase configuration in Codemagic. ```yaml scripts: - name: Load Firebase configuration script: | #!/usr/bin/env sh set -e # exit on first failed command echo $ANDROID_FIREBASE_SECRET > $CM_BUILD_DIR/android/app/google-services.json echo $IOS_FIREBASE_SECRET > $CM_BUILD_DIR/ios/Runner/GoogleService-Info.plist ``` In case your project is in a nested folder structure, adjust the script accordingly: ```yaml scripts: - name: Load Firebase configuration script: | #!/usr/bin/env sh set -e # exit on first failed command PROJECT_ROOT=$CM_BUILD_DIR/myproject/path # ADD YOUR PROJECT FOLDER PATH HERE echo $ANDROID_FIREBASE_SECRET > $PROJECT_ROOT/android/app/google-services.json echo $IOS_FIREBASE_SECRET > $PROJECT_ROOT/ios/Runner/GoogleService-Info.plist ``` ================================================================================ source: https://docs.codemagic.io/knowledge-others/slack-api-integration/ title: Custom Slack Integration with Codemagic description: How to customize slack messages for codemagic builds last_modified: 2026-06-26 ================================================================================ # Custom Slack Integration with Codemagic > How to customize slack messages for codemagic builds Customize Slack notifications for publishing into your Codemagic build pipeline by building a Slack app from scratch via webhooks. ### Step 1: Create a new Slack App To create a new Slack app, go to the Slack app settings page [here](https://api.slack.com/apps). **Create new App > From scratch** ![Start from scratch](../uploads/choose-scratch-option.png) Give it a name for e.g. **Codemagic CI/CD** and select the workspace of your choice to install the app. Click create App. ![Create a new slack app](../uploads/create-new-slack-app.png) Go to your **App settings > Basic Information > Display Information** and fill all the general details. ![Create a new slack app](../uploads/general-info.png) ### Step 2: Add a new webhook to the slack app. You will see that the newly created app is added and visible under App settings page [here](https://api.slack.com/apps). Select the App, it will take you to a dedicated app settings page. **Activate** the Incoming webhook request. ![Create a new slack app](../uploads/incoming-webhooks.png) Navigate to **Incoming Webhooks > Add new webhook to the workspace**. This will generate the webhook url. Copy the webhook url and add it as an ENV variable e.g. SLACK_WEBHOOK_URL. ![Create a new slack app](../uploads/webhooks-permission.png) ### Step 3: Setting required variables. Codemagic exports several built-in environment variables during the build that you can use in scripts to customize the build process. You can refer to the documentation [here](../variables/environment-variables/) For our example, we will be passing the below variables for our custom slack integration. 1. $CM_BUILD_ID - UUID of the build 2. $CM_BRANCH - The current branch being built, for pull requests it is the source branch 3. $CM_REPO_SLUG - The slug of the repository that is currently being built in the form `owner_name/repository_name`. Unset for repositories added from custom source 4. $CM_COMMIT - Commit hash that is currently being built by Codemagic, for pull request builds it is the hash of the source commit. 5. $CM_PROJECT_ID - UUID of the project that is being built 6. $ARTIFACT_URL - Android Artifact Link ```yaml ARTIFACT_URL=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'".apk"'")) | .url') ``` ### Step 4: Create the JSON Payload Navigate to Slack Block Kit builder [here](https://app.slack.com/block-kit-builder) to create a template or you can use the below reference template. You need to substitute the variables in the JSON Payload as shown below. ```json { "attachments": [ { "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "Build with build id " } }, { "type": "divider" }, { "type": "section", "block_id": "section567", "text": { "type": "mrkdwn", "text": " Merge pull request" } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Android Artifact Link* <'"$ARTIFACT_URL"'|Download>" } }, ] } ] } ``` ### Step 5: Making the cURL Request You can specify the JSON Payload in your post processing script, if you are using the workflow editor or add it as script step in the `publishing` section in your workflow if you are using yaml. ```yaml publishing: scripts: - name: Publish to Slack script: | ARTIFACT_URL=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith("'".ipa"'")) | .url') curl -0 -v -X POST $SLACK_WEBHOOK_URL \ -H 'Content-type: application/json' \ --data-raw ' { "attachments": [ { "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "Build with build id " } }, { "type": "divider" }, { "type": "section", "block_id": "section567", "text": { "type": "mrkdwn", "text": " Merge pull request" } }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Android Artifact Link* <'"$ARTIFACT_URL"'|Download>" } }, ] } ] }' ``` ================================================================================ source: https://docs.codemagic.io/integrations/lambdatest-integration/ title: LambdaTest integration description: How to integrate your workflows with LambdaTest using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # LambdaTest integration > How to integrate your workflows with LambdaTest using codemagic.yaml **LambdaTest** is a cloud-based mobile testing platform that provides the ability to test your applications on real mobile devices. LambdaTest can be used as a part of your Codemagic CI/CD pipeline to test your applications. **LambdaTest** offers two testing environments, **Real Time** and **App Automation**. Applications can be submitted to both testing environments through Codemagic using a cURL request. A sample project that shows how to configure LambdaTest integration is available [in our Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/lambdatest_integration_demo_project). ## Configure LambdaTest in Codemagic Registering with LambdaTest is required in order to be able to get the username and access token. You can sign up for free [here](https://www.lambdatest.com/). The `LAMBDATEST_AUTH` environment variable is a `base64` encoded string which consists of the **username** you log into LambdaTest with and the LambdaTest API token you created: `username:api_token` You can encode these credentials in the **macOS Terminal** using: ```bash echo -n ':' | openssl base64 ``` Alternatively, use an [online tool](https://mixedanalytics.com/knowledge-base/api-connector-encode-credentials-to-base-64/) to base64 encode this string. This value is used in the Authorization header used in cURL requests to the LambdaTest API. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `LAMBDATEST_AUTH`. 3. Copy and paste the `base64` encoded authentication string as **_Variable value_**. 4. Enter the variable group name, e.g. **_lambdatest_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - lambdatest_credentials ``` ## LambdaTest Real Time You can test your **.ipa** and **.apk** directly on real devices by submitting them to the **LambdaTest** environment via a cURL request: ```yaml scripts: - name: Submitting app to LambdaTest: script: | curl --location --request POST 'https://manual-api.lambdatest.com/app/upload/realDevice' \ --header 'Authorization: Basic $LAMBDATEST_AUTH' --form 'name="lambda1"' \ --form 'appFile=@"app/build/outputs/apk/release/app-release.apk"' ``` As soon as your **.ipa** and **.apk** are successfully built, they will appear in the **LambdaTest UI** under **Real Device => Real Time**. Any preferred devices can be selected for testing with **Real Time**. ## LambdaTest App Automation In order to see your tests being uploaded to the **App Automation**, tests need to be included in your project. As soon as tests are detected, they will be automatically uploaded to the **App Automation** section and all the results can be viewed there. However, in order to enable it, some capabilities must be injected into your project's test scripts: ### Option: Android ```java DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("platformName", "Android"); capabilities.setCapability("deviceName", "Google Pixel 3"); capabilities.setCapability("isRealMobile", true); capabilities.setCapability("platformVersion","10"); capabilities.setCapability("app","lt://APP100202151634649275590734"); capabilities.setCapability("deviceOrientation", "PORTRAIT"); capabilities.setCapability("console",true); capabilities.setCapability("network",true); capabilities.setCapability("visual",true); ``` ### Option: iOS ```java DesiredCapabilities capabilities = new DesiredCapabilities(); capabilities.setCapability("platformName", "iOS"); capabilities.setCapability("deviceName", "iPhone 16"); capabilities.setCapability("isRealMobile", true); capabilities.setCapability("platformVersion","10"); capabilities.setCapability("app","lt://APP100202151634649275590734"); capabilities.setCapability("deviceOrientation", "PORTRAIT"); capabilities.setCapability("console",true); capabilities.setCapability("network",true); capabilities.setCapability("visual",true); ``` These capabilities will allow **LambdaTest** to detect which platform you want to execute your test scripts with. In these capabilities, the main part is the **app URL**, which is generated in the response of the cURL request: ```bash {"app_id":"APP10020171164383758036593","name":"lambda1","type":"android","app_url":"lt://APP10020171444643838005433352"} ``` ================================================================================ source: https://docs.codemagic.io/knowledge-git/plasticscm-sync-with-git/ title: Sync Plastic SCM with Git description: How to Sync Plastic SCM with Git last_modified: 2026-06-05 ================================================================================ # Sync Plastic SCM with Git > How to Sync Plastic SCM with Git [Plastic SCM](https://www.plasticscm.com/) is a full-featured DVCS (Distributed Version Control Software) which also supports the Git network protocol. Plastic SCM can push and pull changes directly to any remote Git server. This is because Plastic supports the `https://` and `git://` protocols for pushing and pulling changesets. This feature immediately turns Plastic SCM into a DVCS fully compatible with Git. The advantage of this is that you can use Plastic or Git on your workstation and still participate in Git projects (GitHub, CodePlex, and many more). Check out the official [GitSync documentation](https://www.plasticscm.com/documentation/gitsync/plastic-scm-version-control-gitsync-guide). To do so, you can right click on any branch in the `Branches` tab and **Sync with Git**. ![How to sync Plastic SCM with Git](../uploads/plastic-sync-with-git.png) Then you need to add your `Git repository URL`, `User Name`, and `Password` to access that repository. ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/white-label-getting-started/ title: White label apps description: How to white-label your application using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # White label apps > How to white-label your application using codemagic.yaml These are the steps you need to get started white labeling your application using Codemagic. 1. [Add your base app to Codemagic](#1-add-your-base-app-to-codemagic) 2. [Storing client’s assets somewhere Codemagic can access](#1-storing-clients-assets) 3. [Create a unique environment variable group for each client (via UI or API)](#3-create-a-new-unique-environment-variables-group-for-each-client-via-ui-or-api) 4. [Setup your `codemagic.yaml` workflows to dynamically build for all clients](#4-setup-your-codemagicyaml-workflows-to-dynamically-build-for-all-clients) 5. [Start new builds via API, passing the client Id, and the environment variable group name](#5-start-new-builds-via-api) ## 1. Add your base app to Codemagic You don’t have to create a Codemagic application for each client you want to white-label for, only one application linked with your base code is required. The apps you have available on Codemagic are listed on the Applications page. Click **Add application** to add a new app. 1. If you have more than one team configured in Codemagic, select the team you wish to add the app to. 2. Connect the repository where the source code is hosted. Detailed instructions that cover some advanced options are available [here](../../getting-started/adding-apps). 3. Select the repository from the list of available repositories. Select the appropriate project type. 4. Click **Finish: Add application** ## 2. Storing client assets Instead of adding each customer's assets to the base app repository, you should store the assets required for rebranding the app somewhere accessible by Codemagic. This could be an encrypted S3 or GCP storage bucket or a headless CMS. Each customer should be assigned a unique identifier which can be passed to the white-label workflow when the build is started. You should create a zip archive for each client that uses their unique identifier in the file name, e.g. `assets_001.zip` for client `001`. When a build is started for a specific customer's app, this unique identifier will be sent in the API request payload and the correct asset archive will be downloaded and used to rebrand the app. > > 💡 The zip archive typically contains these folders: > > - **`android_assets/`**. This folder contains the Android icons from `/android/app/src/main/res/`. > - **`ios_assets/`**. This folder contains the iOS icons from `/ios/Runner/Assets.xcassets/AppIcon.appiconset/`. > > Other assets such as fonts, images, etc. can also be added to this zip archive. > > Avoid adding any sensitive files such as certificates, profiles, key stores, or other sensitive data in this archive. > > ## 3. Create a unique environment variable group for each client During the white-label build, Codemagic uses client-specific data to set or replace various values in the base code and to sign and publish the app to the stores. You should create a uniquely named environment variable group for each of your clients that contains secret environment variables for items such as certificates, profiles, API keys, or other client-specific credentials. This group might contain the following environment variables: - Android package name. `PACKAGE_NAME`. - Android Keystore information. `CM_KEYSTORE` (base64 encoded), `CM_KEY_ALIAS`, `CM_KEY_PASSWORD`, `CM_KEYSTORE_PASSWORD`, `CM_KEYSTORE_PATH`. - The content of the Google Cloud service JSON file to publish to Play Store. `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`, learn how to get it [here](../yaml-publishing/google-play/#configure-google-play-api-access). - iOS app details. `APP_STORE_ID`, `BUNDLE_ID`. - App Store Connect API key. `APP_STORE_CONNECT_KEY_IDENTIFIER`, `APP_STORE_CONNECT_ISSUER_ID`, `APP_STORE_CONNECT_PRIVATE_KEY`, learn how to create a new key [here](../yaml-code-signing/alternative-code-signing-methods/#:~:text=Creating%20the%20App%20Store%20Connect%20API%20key). - iOS Distribution certificate private key. `CERTIFICATE_PRIVATE_KEY`, learn how to obtain it [here](../yaml-code-signing/alternative-code-signing-methods/#:~:text=Obtaining%20the%20Certificate%20private%20key). - **.env** file if your app uses some secrets at runtime. `DOTENV_FILE` (base64 encoded). To add these values you can either use the [Codemagic UI](https://docs.codemagic.io/yaml-basic-configuration/configuring-environment-variables/#configuring-environment-variables) or use the [Codemagic REST API](https://codemagic.io/api/v3/schema#/) to add these groups and values programmatically, which could be advantageous if you have a large number of clients or wish to add these values from your own backend system or client dashboard. To add an environment variable using the Codemagic REST API, you need your API access token, the application id, the client group unique name, and the variable name and value. - The access token is available in the Codemagic UI in **Account settings > API token**. You can then store this as an environment variable if you are calling the REST API from other workflows. - Once you have added your app in Codemagic, open its settings and copy the **application id** from the browser address bar - `https://codemagic.io/app//settings` - The client group name is the group that holds all variables for this client e.g. `WL_001`, `WL_002`. An example of adding a secret variable to an application group looks like this: ```bash curl --request POST \ --url https://codemagic.io/api/v3/variable-groups/{variable_group_id}/variables \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --header 'x-auth-token: $CODEMAGIC_AUTH_TOKEN' \ --data '{ "secure": true, "variables": [ { "name": "string", "value": "string" } ] }' ``` > > 💡 To find **{variable_group_id}**, a group needs to be created before uploading variables. More information can be found [here](https://codemagic.io/api/v3/schema#/) under the Secrets and Environment Vars dropdown. > > > > 💡 > Files such as **Android keystores**, or **.env** files should be base64 encoded and can be passed like this: > > `{ "name": "", "value":`**`$(cat fileName | base64) ...`** > > And then decode it during the build like this: > > `echo $VAR | base64 --decode > /path` > > ## 4. Setup your codemagic.yaml workflows to dynamically build for all clients Your codemagic.yaml file contains various workflows for building your app for all clients e.g. `android-qa-workflow`, `ios-release-workflow`. In most cases, white label automation is done using shell scripts to perform tasks such as downloading assets, copying files such as logos, images, fonts, etc. to a new location, or changing string values in projects. Here you will find some common script samples we are using in our final [sample project](https://github.com/codemagic-ci-cd/white-label-demo-project/blob/main/codemagic.yaml). ### Downloading assets from Amazon S3 The Amazon CLI tools are pre-installed on Codemagic’s machines which makes it easy to store assets such as images, fonts, logos, etc. in an encrypted S3 bucket and then download these to the build machine when building each white label version. The following is an example of downloading a zip archive from Amazon S3 during the build where the `CLIENT_ID` variable is provided when the build is triggered using the Codemagic REST API: ```yaml environment: groups: - aws_credentials vars: S3_BUCKET_NAME: cmwhitelabel CLIENT_ASSETS_FOLDER: client_assets ... scripts: - name: Get assets from AWS S3 bucket script: | aws s3 cp s3://$S3_BUCKET_NAME/assets_${CLIENT_ID}.zip assets.zip unzip assets.zip -d $CLIENT_ASSETS_FOLDER ``` > > Use this script if you're using a headless CMS instead: > > ```yaml > > scripts: > - name: Get assets from Contentful CMS > script: | > FILE_URL=$(curl --request GET --header "Authorization: Bearer $CONTENTFUL_API_TOKEN" "https://cdn.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/environments/master/assets" | jq '.items[].fields' | jq -r --arg id "assets_$CLIENT_ID" '. | select (.title==$id) | .file.url' | cut -c 3-) > curl -H "Authorization: Bearer $CONTENTFUL_API_TOKEN" $FILE_URL --output assets.zip > > > ``` > > > > ### Changing the Android package name To natively change the Android package name, we can utilize a build automation tool like Gradle to modify the necessary files. In this example, we're first creating a file called `changePackage.gradle` in the root directory of the Android project, which updates the `applicationId` property of the defaultConfig block in your app's build configuration, then adding this line to the `app/build.gradle` file to apply the `changePackage.gradle` script during the build process. ```yaml - name: Change Android package name script: | echo "android { defaultConfig { applicationId '${PACKAGE_NAME}' } }" > android/changePackage.gradle echo "apply from: rootProject.file('changePackage.gradle')" >> android/app/build.gradle ``` ### Changing the iOS bundle ID The automation scripts used in a white label workflow will often need to modify the content of a configuration file. This can be achieved using the `sed` stream editor utility, which can perform basic text transformations such as replacing or adding text in a file. For example, if you want to change the bundle identifier used in the Xcode project by modifying the `project.pbxproj` file, the following script will set the `PRODUCT_BUNDLE_IDENTIFIER` with a value stored in the environment variable called `$BUNDLE_ID`. ```yaml - name: Set bundle id script: sed -i '' -e 's/PRODUCT_BUNDLE_IDENTIFIER \= [^\;]*\;/PRODUCT_BUNDLE_IDENTIFIER = '${BUNDLE_ID}';/' ios/Runner.xcodeproj/project.pbxproj ``` ### Changing app name ### Option: Android Using `sed`, the following script will replace the line in the `AndroidManifest.xml` that starts with `android:label=` with a new line contains the new app name `$APP_NAME`. ```yaml - name: Change Android app name script: sed -i.bak "s/android:label=.*/android:label=\"$APP_NAME\"/g" android/app/src/main/AndroidManifest.xml ``` ### Option: iOS **PlistBuddy** is a utility on macOS that can be used to perform operations on plist files. This approach can be used with native Swift/Objective-C apps, but please note that setting values directly in a Flutter project may cause problems with your project and you should consider using `sed` instead. ```yaml - name: Change iOS app name script: /usr/libexec/PlistBuddy -c "Set :CFBundleName $APP_NAME" -c "Set :CFBundleDisplayName $APP_NAME" ios/${XCODE_SCHEME}/Info.plist ``` ### Changing app icons ### Option: Android For Android apps, you should run a script to update the icons located in `android/app/src/main/res` where you will find a number of directories that contain an icon for specific resolutions such as `drawable-hdpi`, `drawable-mdpi`, `drawable-xhdpi`, `drawable-xxhdpi`, `drawable-xxxhdpi`. Your script to update the icons in your Android project might look something like this: ```yaml name: Change Android app icons script: cp -r ./$CLIENT_ASSETS_FOLDER/android_assets/* ./android/app/src/main/res ``` ### Option: iOS For iOS apps, if you look at an Xcode project using Finder, you will see that the icons added in Xcode are located in `//Assets.xcassets/AppIcon.appiconset`. This means that after downloading icon assets for a specific client’s build, you can change them on disk by simply deleting the existing `AppIcon.appiconset` directory, and then copying the assets into the `Assets.xcassets` directory. ```yaml name: Change iOS app icons script: cp -r ./$CLIENT_ASSETS_FOLDER/ios_assets ios/Runner/Assets.xcassets/ ```
> > 💡 You can also use the [flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons) package to generate the icons. > > ### Automatic build versioning Each new app version that is published to Google Play or the Apple App Store needs to have a unique build number. You can use Codemagic’s CLI tools to retrieve the previous build number and then increment this for each new build. For example, the following shows how to increment the build number when building Flutter apps: ### Option: Android ```yaml name: Flutter build aab with automatic versioning script: | flutter build appbundle --release \ --build-name=1.0.0 \ --build-number=$(($(google-play get-latest-build-number --package-name "$PACKAGE_NAME" --tracks="$GOOGLE_PLAY_TRACK") + 1)) ``` ### Option: iOS ```yaml name: Flutter build ipa with automatic versioning script: | flutter build ipa --release \ --build-name=1.0.0 \ --build-number=$(($(app-store-connect get-latest-testflight-build-number "$APP_STORE_ID") + 1)) \ --export-options-plist=/Users/builder/export_options.plist ``` ### Publishing to customer stores You can automate the process of publishing each client’s app to their store account with Codemagic. ### Option: Play Store Make sure you add each client’s service account JSON key file to their environment variables group so Codemagic can authenticate and publish the app to their store. ```yaml publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: ``` Read more on this [here](https://docs.codemagic.io/yaml-publishing/google-play/). ### Option: App Store If you’re using the automatic iOS code signing method, then each client’s environment group already has their App Store Connect account credentials, and they’ll be used to publish the app to this account. ```yaml publishing: app_store_connect: api_key: $APP_STORE_CONNECT_PRIVATE_KEY key_id: $APP_STORE_CONNECT_KEY_IDENTIFIER issuer_id: $APP_STORE_CONNECT_ISSUER_ID ``` Read more on this [here](https://docs.codemagic.io/yaml-publishing/app-store-connect/).
> > > ⚠️ Neither Apple nor Google provides APIs that programmatically allow an app to be created. Therefore, you will need to create and upload the first version of each app manually. After that Codemagic can fully automate the white-label process. > ### Full YAML sample Having followed all of the above steps, you now have a working `codemagic.yaml` file that allows you to download client assets from AWS S3 bucket, changing app name and icons, replacing existing package name and bundle ID, build, code sign, automatically version and publish to each customer stores accounts. Your final `codemagic.yaml` file should look something like this: ### Option: Android %!s() ================================================================================ source: https://docs.codemagic.io/knowledge-others/dart-define-from-file-secrets/ title: Importing variables from JSON description: How to import variables from a JSON file with dart-define-from-file last_modified: 2026-06-26 ================================================================================ # Importing variables from JSON > How to import variables from a JSON file with dart-define-from-file You can use Flutter's `dart-define-from-file` functionality to provide variables in JSON format for your app at build time. You can store your JSON configuration securely in Codemagic and make it available in your pipeline at build time. > > We would only recommend this approach for configuration settings and **avoid including sensitive values** such as API keys in your application whenever possible. > ## Configure the settings.json file Create the desired JSON configuration file. ```bash { "value_one": "abc", "value_two": "xyz" } ``` ## Base64 encode your settings.json file Open your Terminal and Base64 encode your JSON file as follows. This will also copy it to your clipboard, making it easier for you to paste the value into Codemagic. ```bash cat settings.json | base64 | pbcopy ``` ## Add your JSON as an environment variable in Codemagic You can now add the Base64 encoded file as an environment variable in Codemagic as follows: 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**. 3. Enter the **_Variable value_**. 4. Enter the variable group name, e.g. **_json_**. Click the button to create the group. 5. If the **Secret** option is selected, the variable will be protected by encryption. Its value will not be visible in Codemagic UI or build logs, it will be transferred securely to the build machine and made available only while the build is running. The whole build machine will be destroyed after build ends. 6. Click the **Add** button to add the variable. ## Import the environment variable group in codemagic.yaml Import your variable group in your codemagic.yaml as follows: ```yaml workflows: workflow-name: environment: groups: - json_config ``` ## Using your settings.json to build your app You will now need to save the settings.json file to disk so it can be used in your workflow. Assuming you named your variable `JSON_CONFIG` you can do this as follows: ```yaml workflows: workflow-name: ... scripts: - name: Export JSON configuration script: echo "$JSON_CONFIG" | base64 --decode > settings.json ... - name: Flutter build for iOS script: | flutter build ipa --release \ --build-name=1.0.0 \ --build-number=$(($(app-store-connect get-latest-testflight-build-number "$APP_ID") + 1)) \ --dart-define-from-file=settings.json --export-options-plist=/Users/builder/export_options.plist ``` Your `settings.json` file is saved to the same directory as your app and this is referenced in `dart-define-from-file`. ## Using Workflow Editor You can add your Base64 encoded settings.json as an environment variable in the Workflow Editor, and then script to decode the value to disk in the **Post-clone script** section. ```yaml echo "$JSON_CONFIG" | base64 --decode > settings.json ``` In the **Build section** use `dart-define-from-file` in the **Build arguments** ================================================================================ source: https://docs.codemagic.io/integrations/maestro-integration/ title: Maestro integration description: How to integrate your workflows with Maestro using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Maestro integration > How to integrate your workflows with Maestro using codemagic.yaml [**Maestro UI testing framework**](https://maestro.dev/) lets you test your iOS and Android mobile apps using simple to-create test flows that are written in a declarative form using YAML. In order to run your tests in CI you can utilize [Maestro Cloud](https://app.maestro.dev/), which allows you to easily run your Flows without having to manage iOS and Android devices in your own CI. For more information on how to get started with Maestro and Maestro Cloud, please refer to the [Maestro documentation](https://docs.maestro.dev/). A sample project that shows how to configure Maestro integration is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/maestro_sample_project). ## Get Maestro Cloud API Key In order to use Maestro Cloud to run your tests on, you will need to sign up here and get the `API Key` from your [console](https://app.maestro.dev/), click on your email, **View API Key** and copy the value. After getting your `API KEY` you need to add it to your [environment variables](/variables/environment-variable-groups/#storing-sensitive-valuesfiles) in a group named ***maestro*** for example. #### Configure environment variables 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `MDEV_API_KEY`. 3. Enter the desired variable value as **_Variable value_**. 4. Enter the variable group name, e.g. **_maestro_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - maestro ``` ## Managing Maestro flows After you have created your YAML tests flows inside the `.maestro` directory, you need to check the directory into your project repository. ## Installing Maestro CLI Before you use maestro commands, you need first to simply install the CLI on the building machine using this command. ```yaml scripts: - name: Download Maestro script: curl -Ls "https://get.maestro.mobile.dev" | bash ``` ## Uploading to Maestro Cloud First, you need to build your **Android (.apk) / iOS (.app)** apps, then use the `maestro cloud` command to test your app. ### Option: Android See how to build your native android app [here](../yaml-quick-start/building-a-native-android-app/) or your Flutter app [here](../yaml-quick-start/building-a-flutter-app/). Add the following script to your `publishing` section: ```yaml publishing: scripts: - name: Run tests on Maestro cloud script: | export PATH="$PATH":"$HOME/.maestro/bin" apkPath="/build/app/outputs/apk/release/app-release.apk" maestro cloud \ --apiKey $MDEV_API_KEY \ $apkPath \ .maestro/ ``` Don't forget to change the value of the `apkPath` to your actual apk path. ### Option: iOS For iOS, you need to upload your x86-compatible Simulator `.app` directory. Here's the script on how you can build it. ```yaml scripts: - name: Build unsigned .app script: | xcodebuild \ -workspace "ios/$XCODE_WORKSPACE" \ -scheme "$XCODE_SCHEME" \ -configuration "Debug" \ -sdk iphonesimulator \ -derivedDataPath ios/output - name: Run tests on Maestro cloud script: | export PATH="$PATH":"$HOME/.maestro/bin" iosAppPath="$ios/output/..." maestro cloud \ --apiKey $MDEV_API_KEY \ $iosAppPath \ .maestro/ ``` Don't forget to add the environment variables that holds your XCode workspace name under `$XCODE_WORKSPACE` and the Scheme name under `$XCODE_SCHEME`. See the complete sample project [here](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/maestro_sample_project/codemagic.yaml). If your Codemagic build has failed at the Maestro cloud step, then your tests have failed. Otherwise, everything went well and you can check out the build page for more details. ================================================================================ source: https://docs.codemagic.io/integrations/ms-teams-integration/ title: Microsoft Teams integration description: How to integrate your workflows with Microsoft Teams using codemagic.yaml last_modified: 2026-02-16 ================================================================================ # Microsoft Teams integration > How to integrate your workflows with Microsoft Teams using codemagic.yaml **Microsoft Teams** is a communication and collaboration platform that allows teams to chat, share files, and integrate with external services. If your team uses Microsoft Teams, you can configure Codemagic to send build status notifications directly to a Teams channel using an **Incoming Webhook**. ## Create an Incoming Webhook in Teams To receive messages in a Teams channel, you first need to configure the **Incoming Webhook**: 1. In Microsoft Teams, open the channel you want to post notifications to. ![Ms teams 1](../uploads/ms_teams1.png) 2. Click **More options** (⋮) → **Connectors** → **Edit**. 3. Add an **Incoming Webhook**. ![Ms teams 2](../uploads/ms_teams2.png) 4. Copy the generated **Webhook URL**. ## Configuring access to Teams in Codemagic 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `TEAMS_WEBHOOK_URL`. 3. Paste the **Webhook URL** you copied from Teams as the **_Variable value_**. 4. Enter the variable group name, e.g. **_teams_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file: ```yaml environment: groups: - teams_credentials ``` ## Post a message to Microsoft Teams You can send messages to a Teams channel using a simple `curl` request to the webhook. The following example shows how you can check the publishing status of a build and send a notification to Teams when publishing succeeds: ```yaml publishing: scripts: # Fetch the artifact URL for the .ipa file ARTIFACT_LINK=$(echo $CM_ARTIFACT_LINKS | jq -r '.[] | select(.name | endswith(".ipa")) | .url') # Get first 7 digits of commit hash COMMIT=$(echo "${CM_COMMIT}" | sed 's/^\(........\).*/\1/;q') # Get commit message COMMIT_MESSAGE=$(git log --format=%B -n 1 $CM_COMMIT) # Get commit author AUTHOR=$(git show -s --format='%ae' $CM_COMMIT) # Send notification to MS Teams curl -H "Content-Type: application/json" \ -d "{ \"title\": \"📦 New Codemagic Build\", \"text\": \"**Branch:** $CM_BRANCH
**Commit:** \`$COMMIT\`
**Author:** $AUTHOR
**Commit message:** $COMMIT_MESSAGE
**Artifact:** Download IPA\" }" \ $TEAMS_WEBHOOK_URL ``` ================================================================================ source: https://docs.codemagic.io/integrations/patrol-integration/ title: Patrol integration description: How to integrate your workflows with Patrol using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # Patrol integration > How to integrate your workflows with Patrol using codemagic.yaml [**Patrol**](https://patrol.leancode.co?utm_source=codemagic&utm_medium=referral) is a powerful, open-source UI testing framework designed specifically for Flutter apps, developed and maintained by [LeanCode](https://leancode.co?utm_source=codemagic&utm_medium=referral), one of the world's leading Flutter development consultancies. Patrol can be seamlessly integrated with Codemagic CI/CD to enable comprehensive automated testing workflows. Patrol allows you to: - Interact with permission dialogs, notifications, and WebViews - Modify device settings, toggle Wi-Fi, and more - All achieved effortlessly using plain Dart code A sample project that shows how to configure Patrol integration is available in Codemagic's [patrol-demo-project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/patrol-demo-project). This sample project includes: - Complete `codemagic.yaml` configuration with multiple integrations - Example Patrol tests - How to sign in iOS before running Patrol on physical device - Integration with device farms (Firebase Test Lab) - Best practices for CI/CD testing workflows Refer to the sample project's README and configuration files for detailed setup instructions and integration examples. ## How to start using Patrol in your workflows ### Prerequisites Before integrating Patrol with Codemagic, ensure you have: - A Flutter project with Patrol tests already set up. If you need help, check [Patrol documentation](https://patrol.leancode.co?utm_source=codemagic&utm_medium=referral) to get started. - Codemagic account and project configured - Access to device farms (optional, for cloud testing) ### Configure codemagic.yaml Add the following configuration to your `codemagic.yaml` file to build Patrol tests and send them to Firebase Test Lab: ```yaml definitions: environment: &environment flutter: 3.27.3 # Replace with your Flutter version java: 17 # Replace with your Java version workflows: patrol_android_build: name: Patrol Android Build and send to Firebase Test Lab instance_type: mac_mini_m2 max_build_duration: 30 environment: <<: *environment steps: - name: Install Patrol CLI script: dart pub global activate patrol_cli 3.6.0 # Replace with your Patrol CLI version for compatibility you can see https://patrol.leancode.co/documentation/compatibility-table - name: Install dependencies script: flutter pub get - name: Authorize Google Cloud SDK env_vars: - google_credentials # <-- (You need to add firebase service account key (json file) to your codemagic secrets) script: | echo "$TEST_LAB_SERVICE_ACCOUNT_KEY" > /tmp/gcloud.json gcloud auth activate-service-account --quiet --key-file /tmp/gcloud.json gcloud --quiet config set project $GCLOUD_PROJECT_ID - name: Build apk for testing script: | patrol build android --verbose echo "APK_PATH=build/app/outputs/apk/dev/debug/app-dev-debug.apk" >> $CM_ENV echo "TEST_APK_PATH=build/app/outputs/apk/androidTest/dev/debug/app-dev-debug-androidTest.apk" >> $CM_ENV - name: Send tests to Firebase test lab script: | gcloud firebase test android run \ --type instrumentation \ --use-orchestrator \ --app $APK_PATH \ --test $TEST_APK_PATH \ --num-flaky-test-attempts 1 \ --timeout 25m \ --device model=MediumPhone.arm,version=35,locale=en,orientation=portrait \ --environment-variables clearPackageData=true artifacts: - build/app/outputs/apk/dev/debug/app-dev-debug.apk - build/app/outputs/apk/androidTest/dev/debug/app-dev-debug-androidTest.apk ``` For more detailed configuration, look at [patrol-demo-project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/patrol-demo-project). ### Device Farm Integration Patrol can be integrated with popular device farms through Codemagic: - **Firebase Test Lab**: Run Patrol tests on Google's device farm - **BrowserStack**: Execute tests on BrowserStack's real device cloud - **emulator.wtf**: Run tests on emulator.wtf's cloud emulators It can also be run on Codemagic itself. There is a [Blog post](https://blog.codemagic.io/how-to-test-native-features-in-flutter-apps-with-patrol-and-codemagic/). ### Getting Help - Visit the [Patrol documentation](https://patrol.leancode.co?utm_source=codemagic&utm_medium=referral) - Join the [Patrol Discord channel](https://discord.com/invite/ukBK5t4EZg) - Check out the [Patrol GitHub repository](https://github.com/leancodepl/patrol) ================================================================================ source: https://docs.codemagic.io/integrations/pcloudy-integration/ title: pCloudy integration description: How to integrate your workflows with pCloudy using codemagic.yaml last_modified: 2026-06-26 ================================================================================ # pCloudy integration > How to integrate your workflows with pCloudy using codemagic.yaml **pCloudy** is a cloud-based mobile testing platform that provides the ability to test your apps on a wide-ranging list of real iOS and Android mobile devices and tablets. A sample project that shows how to configure pCloudy integration is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/pcloudy_integration_demo_project). ## Configure pCloudy access Signing up with pCloudy is required in order to be able to get the **username** and **access token**. You can sign up for free [here](https://www.pcloudy.com/). 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `PCLOUDY_USERNAME`. 3. Enter the desired variable value as **_Variable value_**. 4. Enter the variable group name, e.g. **_pcloudy_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to add the `PCLOUDY_API_TOKEN`. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - pcloudy_credentials ``` ## Uploading artefacts to pCloudy To upload your **.ipa**, **.apk** or **.aab** to pCloudy, add the following script after the build step in your `codemagic.yaml`: ```yaml scripts: - name: pCloudy upload script: | APP_TOKEN=$(curl -u "$PCLOUDY_USERNAME:$PCLOUDY_API_TOKEN" \ https://device.pcloudy.com/api/access | jq -r '.[].token') curl -X POST -F "file=@android/app/build/outputs/apk/release/app-release.apk" \ -F "source_type=raw" \ -F "token=$APP_TOKEN" \ -F "filter=all" https://device.pcloudy.com/api/upload_file ``` To also upload test suites for Android apps, add the `./gradlew assembleAndroidTest` command to build tests and add another cURL command to upload: ```yaml scripts: - name: pCloudy upload script: | APP_TOKEN=$(curl -u "$PCLOUDY_USERNAME:$PCLOUDY_API_TOKEN" \ https://device.pcloudy.com/api/access | jq -r '.[].token') curl -X POST -F "file=@android/app/build/outputs/apk/release/app-release.apk" \ -F "source_type=raw" \ -F "token=$APP_TOKEN" \ -F "filter=all" https://device.pcloudy.com/api/upload_file # Tests curl -X POST -F "file=@android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk" \ -F "source_type=raw" \ -F "token=$APP_TOKEN" \ -F "filter=all" https://device.pcloudy.com/api/upload_file ``` ================================================================================ source: https://docs.codemagic.io/integrations/perfecto-integration/ title: Perfecto integration description: How to integrate your workflows with Perfecto using codemagic.yaml last_modified: 2026-02-16 ================================================================================ # Perfecto integration > How to integrate your workflows with Perfecto using codemagic.yaml **Perfecto** is a cloud-based test automation platform for web and mobile that allows application developers and QA engineers to create and execute tests across devices and browsers at scale. Being a market leader in its area, Perfecto offers many ways to integrate with different stages of the software development and testing lifecycle. It is possible to integrate with Perfecto directly from your **codemagic.yaml** A sample project that shows how to configure Perfecto integration for real device testing is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/perfecto_sample_project). A sample project showcasing Perfecto **App Automate** integration for Flutter apps is available [here](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/perfecto_flutter_sample_project). ## Configuring Perfecto access Signing up with [Perfecto](https://www.perfecto.io/) is required in order to get credentials that are needed during an upload process. 1. Get the Perfecto access token from the Perfecto UI. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `PERFECTO_TOKEN`. 3. Copy and paste the Perfecto token string as **_Variable value_**. 4. Enter the variable group name, e.g. **_perfecto_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - perfecto_credentials ``` ## Uploading to Perfecto Using the following cURL script in a post-build script, **Release APK** and **Release IPA** binaries can be uploaded to the Perfecto platform: ```yaml scripts: - name: Upload to Perfecto script: | curl "https://web.app.perfectomobile.com/repository/api/v1/artifacts" \ -H "Perfecto-Authorization: $PERFECTO_TOKEN" \ -H "Content-Type: multipart/form-data" \ -F "requestPart={\"artifactLocator\":\"PRIVATE:app.aab\",\"artifactType\":\"ANDROID\",\"override\":true}" \ -F "inputStream=@/path/to/your_binary" ``` ## Test Automation The uploaded files can be directly used to start your automation testing. To do this, desired capabilities can be set inside your custom-made test scripts in your project. For example, if your application requires device sensors such as camera or fingerprint reader, then **sensorInstrument** needs to be set: ```dart capabilities.setCapability("sensorInstrument", true); ``` ## Flutter apps integration ### Option: Android In order to set up integration for Flutter specific apps the following steps must be followed: 1. Generate a folder named **PerfectoRunAndroid** (can be named differently) in the root directory of your project. 2. Change dir to **PerfectoRunAndroid** directory and initiate Gradle by executing the following commands in your local terminal: ```bash cd PerfectoRun gradle init ./gradlew wrapper ``` 3. Running the above commands will create the necessary gradle files along with an empty `build.gradle`. Edit the `build.gradle` by adding the following: ```Groovy buildscript { repositories { maven { url "https://repo1.perfectomobile.com/public/repositories/maven/" } google() mavenCentral() } dependencies { classpath "com.perfectomobile.instrumentedtest.gradleplugin:plugin:+" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } // Apply the plugin apply plugin: 'com.perfectomobile.instrumentedtest.gradleplugin' perfectoGradleSettings { configFileLocation "ConfigFile.json" } task clean(type: Delete) { delete rootProject.buildDir } ``` 4. Create a file called `ConfigFile.json` and add the following Json content in there: ```json {   "cloudURL": "web-fra.perfectomobile.com",   "securityToken": "xxxxxxxxxxxx",   "devices": [         {           "platformName" : "Android",           "platformVersion": "^12.*”, “description”:”free”         },         {             "platformName_" : "Android",             "platformVersion_": "^11.*”, “description”:”free”         }   ],   "jobName": "some_job",   "jobNumber": 1,   "branch": "some_branch",   "projectName": "My_Flutter_project",   "projectVersion": "v1.0",   "tags": [     "espresso", "plugin"  ],   "apkPath": "YOUR_APK_PATH",   "testApkPath": "YOUR_TEST_APK_PATH",   "installationDetails" : {"preCleanUp" : "true"},   "postExecution" : {"uninstall" : "false" },   "debug": false,   "failBuildOnFailure": false,   "takeScreenshotOnTestFailure": true,   "shard": false,   "testTimeout" : 60000 } ``` **"securityToken"** contains your Perfecto Token that can be fetched from your Perfecto account. 5. Modify your `codemagic.yaml` file to include post-build scripts to generate **testBuildType** and upload the files to Perfecto ```yaml scripts: - name: Build Android Test release script: | ./gradlew assembleAndroidTest - name: Upload files to Perfecto and run tests script: | cd PerfectoRunAndroid ./gradlew perfecto-android-inst ``` ### Option: iOS In order to set up integration for Flutter specific apps the following steps must be followed: 1. Create another folder in the root directory named **PerfectoRunIos** (can be named differently) 2. Manually create `build.gradle` file with the following content: ```Groovy buildscript { repositories { maven { url "https://repo1.perfectomobile.com/public/repositories/maven" } } dependencies { classpath "com.perfectomobile.instrumentedtest.gradleplugin:plugin:+" } } apply plugin: 'com.perfectomobile.instrumentedtest.gradleplugin' perfectoGradleSettings { configFileLocation "configFile.json" } ``` 3. Create a file called `ConfigFile.json` and add the following Json content in there: ```json { "cloudURL": "beta.perfectomobile.com", "securityToken":"xxxxxxxxxxxx", "appPath":"repository:PATH_TO_IPA", "hostedTestModuleName":"RunnerTests", "isHostedTestModule":true, "devices": [ {"deviceName":"00008020-000D2CC42ED8002E"}, {"deviceName":"00008101-000B05283081401E"} ], "shard": false, "jobName": "Flutter_iOS_Job", "jobNumber": 1, "branch": "Flutter_Branch", "projectName": "My_Flutter_iOS_Project", "projectVersion": "v1.0", "tags": [ "XCUI", "plugin" ], "takeScreenshotOnTestFailure": false, "takeScreenshotOnTestEnd": false, "takeScreenshotOnTestStep": false, "runUITests":true, "runUnitTests":false, "installationDetails": { "resign": true }, "numOfDevices": 2 } ``` 4. Modify your `codemagic.yaml` file to include a script upload the files to Perfecto ```yaml scripts: - name: Upload iOS files to Perfecto and run tests script: | cd PerfectoRunIos gradle perfecto-xctest ``` ## Get Help and Support with Perfecto To test how Perfecto supports Flutter Integration Testing for native mobile applications, [visit their website](https://www.perfecto.io/integrations/flutter) and get access to a [free trial](https://www.perfecto.io/free-trial). Additionally, for video demonstrations and some more information on how to set up Flutter for iOS and Android apps in Perfecto, visit the following documentation pages: 1. [Setting up Flutter for iOS in Perfecto](https://help.perfecto.io/perfecto-help/content/perfecto/automation-testing/flutter-ios.htm) 2. [Setting up Flutter Android in Perfecto](https://help.perfecto.io/perfecto-help/content/perfecto/automation-testing/flutter-android.htm) ================================================================================ source: https://docs.codemagic.io/integrations/rock-integration/ title: Rock (formerly RNEF) integration description: How to integrate your workflows with Rock using codemagic.yaml last_modified: 2026-06-18 ================================================================================ # Rock (formerly RNEF) integration > How to integrate your workflows with Rock using codemagic.yaml Rock (formerly published as RNEF — React Native Enterprise Framework) is a modular CLI toolkit from [Callstack](https://www.callstack.com/) designed for enterprise React Native teams. Its headline feature for CI is a **remote build cache**: native artifacts (APK, AAB, APP, IPA) are fingerprinted, stored in S3-compatible storage, and automatically reused across machines and CI runs, skipping full native builds for commits that only touch JavaScript. Callstack reports cache hits of up to 96% of builds on large codebases. Rock's default CI templates target GitHub Actions (the `callstackincubator/ios` and `callstackincubator/android` actions). On Codemagic, you install the Rock CLI via npm and invoke its commands directly in your `codemagic.yaml` scripts — no GitHub Actions wrapper required. The remote cache is pointed at AWS S3 or Cloudflare R2, both of which Codemagic can reach via encrypted environment variables. This guide covers: - [Configuring `rock.config.mjs` for S3 or R2](#step-1--configure-rockconfigmjs-for-s3) - [Setting up signing assets and environment variables in Codemagic](#step-2--add-signing-assets-and-environment-variables-in-codemagic) - [Workflows in codemagic.yaml](#step-3--create-codemagicyaml) - [Code signing using Codemagic's built-in signing management](#step-2--add-signing-assets-and-environment-variables-in-codemagic) - [Monorepo layout notes](#monorepo-layout) - [Re.Pack and Brownfield packaging](#optional-repack-and-super-app-builds) --- ## Prerequisites - A React Native project already configured with Rock. If you are migrating from Community CLI, follow the [migration guide](https://www.rockjs.dev/docs/getting-started/migrating-from-community-cli) to initialise `rock.config.mjs` before proceeding. - An AWS S3 bucket (or Cloudflare R2 bucket) accessible with static credentials. For S3, the IAM user needs `s3:PutObject`, `s3:GetObject`, `s3:DeleteObject`, and `s3:ListBucket` permissions on the target bucket. - For Android release builds: a keystore file uploaded to Codemagic (see Step 2 below). - For iOS device/distribution builds: an Apple Developer certificate and provisioning profile uploaded to Codemagic (see Step 2 below). --- ## How the Remote Cache Works Rock computes a **fingerprint** of your native project using `@expo/fingerprint`. This hash captures everything that would require a native rebuild — native dependencies, `Podfile.lock`, build configuration, Gradle files, and so on. Pure JavaScript changes do not affect the fingerprint. On each CI run, Rock: 1. Computes the current native fingerprint. 2. Looks for a cached artifact in your S3 bucket matching that fingerprint. 3. If found, downloads and uses it — skipping the native build entirely. 4. If not found, performs a full native build and uploads the resulting artifact to S3 for future use. Only the first build after a native dependency change pays the full build-time cost. All subsequent runs on the same native state — including builds across branches and pull requests — reuse the cached artifact. --- ## Step 1 — Configure `rock.config.mjs` for S3 Rock's S3 provider is a separate package: ```bash npm install @rock-js/provider-s3 ``` Open (or create) your `rock.config.mjs` and add the `remoteCacheProvider` field. Reference credentials from environment variables so they remain out of source control: ```js // rock.config.mjs import { platformIOS } from '@rock-js/platform-ios'; import { platformAndroid } from '@rock-js/platform-android'; import { pluginMetro } from '@rock-js/plugin-metro'; import { providerS3 } from '@rock-js/provider-s3'; export default { platforms: { ios: platformIOS(), android: platformAndroid(), }, bundler: pluginMetro(), remoteCacheProvider: providerS3({ bucket: process.env.ROCK_S3_BUCKET, region: process.env.ROCK_S3_REGION, accessKeyId: process.env.ROCK_S3_ACCESS_KEY_ID, secretAccessKey: process.env.ROCK_S3_SECRET_ACCESS_KEY, }), }; ``` ### Using Cloudflare R2 Instead of S3 R2 exposes an S3-compatible API. Add an `endpoint` option pointing to your R2 account and set `region` to `auto`: ```js remoteCacheProvider: providerS3({ endpoint: `https://${process.env.CF_ACCOUNT_ID}.r2.cloudflarestorage.com`, bucket: process.env.ROCK_S3_BUCKET, region: 'auto', accessKeyId: process.env.ROCK_S3_ACCESS_KEY_ID, secretAccessKey: process.env.ROCK_S3_SECRET_ACCESS_KEY, }), ``` --- ## Step 2 — Add Signing Assets and Environment Variables in Codemagic ### Remote Cache Credentials In the Codemagic UI, navigate to **Teams → your team → Global variables and secrets** (or per-application under **App settings → Environment variables**). Create a group called `rock_s3_cache` and add the following variables, marking each as **Secret**: | **Variable** | **Description** | |---|---| | `ROCK_S3_BUCKET` | S3 or R2 bucket name | | `ROCK_S3_REGION` | AWS region (e.g. `eu-west-1`; use `auto` for R2) | | `ROCK_S3_ACCESS_KEY_ID` | IAM or R2 access key ID | | `ROCK_S3_SECRET_ACCESS_KEY` | IAM or R2 secret access key | | `CF_ACCOUNT_ID` | Cloudflare account ID (R2 only) | ### Android Keystore Upload your release keystore to Codemagic once and reference it by name in every workflow — no manual base64 encoding or decode steps required. In the Codemagic UI, go to **Teams → your team → Code signing identities → Android keystores** and upload your `.jks` or `.keystore` file. Give it a reference name, for example `rock_release_keystore`. Codemagic will prompt for the store password, key alias, and key password at upload time and store them encrypted. When the `android_signing` block references this keystore by name in `codemagic.yaml`, Codemagic automatically injects four environment variables at build time: | Variable | Content | |---|---| | `CM_KEYSTORE_PATH` | Absolute path to the keystore file on the build machine | | `CM_KEYSTORE_PASSWORD` | Keystore store password | | `CM_KEY_ALIAS` | Key alias | | `CM_KEY_PASSWORD` | Key password | ### iOS Certificate and Provisioning Profile In the Codemagic UI, go to **Teams → your team → Code signing identities → iOS certificates** and upload your `.p12` distribution certificate. Give it a reference name, for example `distribution_cert`. Then go to **iOS provisioning profiles** and upload your `.mobileprovision` file with a reference name such as `distribution_profile`. When the `ios_signing` block references these by name in `codemagic.yaml`, Codemagic places the files on the build machine, installs the certificate into a temporary keychain automatically, and exposes the file paths via whatever `environment_variable` names you specify in the YAML. ### App Store Connect API Key In the Codemagic UI, go to **Teams → your team → Team integrations → Developer Portal** and click **Connect**. Upload your .p8 API key file and provide the associated Key ID and Issuer ID. Give the integration a name, for example `app_store_connect_key`. Once connected, reference it in your workflow with the integrations: block — no API key environment variables are needed in the workflow. ```yaml integrations: app_store_connect: app_store_connect_key ``` This single reference covers both publishing to TestFlight/App Store and any Codemagic CLI tooling that needs to communicate with Apple's APIs (such as automatic build number incrementing). --- ## Step 3 — create codemagic.yaml ### Option: Android The following workflow installs Rock, checks for a cached native artifact in S3, runs a full build only on a cache miss, and produces a signed AAB ready for Google Play. ```yaml workflows: rock-android-release: name: Rock — Android Release max_build_duration: 60 instance_type: linux_x2 environment: groups: - rock_s3_cache # ROCK_S3_BUCKET, ROCK_S3_REGION, # ROCK_S3_ACCESS_KEY_ID, ROCK_S3_SECRET_ACCESS_KEY android_signing: - rock_release_keystore # reference name set in Codemagic UI # injects: CM_KEYSTORE_PATH, CM_KEYSTORE_PASSWORD, # CM_KEY_ALIAS, CM_KEY_PASSWORD vars: APP_MODULE: app BUILD_FLAVOR: "" # leave empty if your project has no product flavors node: latest java: 17 cache: cache_paths: - $HOME/.gradle/caches - $CM_BUILD_DIR/node_modules scripts: - name: Install Node dependencies script: npm ci - name: Install Rock CLI script: npm install -g @rock-js/cli # Rock checks the S3 cache before building. A cache hit skips Gradle # compilation entirely; a miss builds from source and uploads the artifact. # CM_KEYSTORE_PATH and related variables are injected automatically by # Codemagic from the android_signing block above. - name: Build Android (with remote cache) script: | rock remote-cache download --platform android --variant release || true if rock remote-cache is-cached --platform android --variant release; then echo "Cache hit — skipping native build" else echo "No cache hit — building from source" rock build:android \ --variant release \ --aab \ -P ROCK_UPLOAD_STORE_FILE="$CM_KEYSTORE_PATH" \ -P ROCK_UPLOAD_STORE_PASSWORD="$CM_KEYSTORE_PASSWORD" \ -P ROCK_UPLOAD_KEY_ALIAS="$CM_KEY_ALIAS" \ -P ROCK_UPLOAD_KEY_PASSWORD="$CM_KEY_PASSWORD" rock remote-cache upload --platform android --variant release fi artifacts: - android/app/build/outputs/**/*.aab - android/app/build/outputs/**/*.apk publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal email: recipients: - mobile@yourcompany.com notify: success: true failure: true ``` ### Option: iOS iOS builds must run on a macOS instance. The workflow below uses Codemagic's built-in signing management: the certificate is installed into a temporary keychain automatically and the paths to the certificate and provisioning profile are injected as environment variables — no manual `security import` or keychain setup required. ```yaml workflows: rock-ios-release: name: Rock — iOS Release max_build_duration: 90 instance_type: mac_mini_m2 integrations: app_store_connect: app_store_connect_key # name given when connecting in Team UI environment: groups: - rock_s3_cache # ROCK_S3_BUCKET, ROCK_S3_REGION, # ROCK_S3_ACCESS_KEY_ID, ROCK_S3_SECRET_ACCESS_KEY ios_signing: provisioning_profiles: - profile: distribution_profile # reference name set in Codemagic UI environment_variable: PROVISIONING_PROFILE_PATH certificates: - certificate: distribution_cert # reference name set in Codemagic UI environment_variable: CERTIFICATE_PATH vars: XCODE_WORKSPACE: YourApp.xcworkspace XCODE_SCHEME: YourApp BUNDLE_ID: com.example.yourapp node: latest xcode: latest cocoapods: default cache: cache_paths: - $HOME/Library/Caches/CocoaPods - $CM_BUILD_DIR/node_modules scripts: - name: Install Node dependencies script: npm ci - name: Install Rock CLI script: npm install -g @rock-js/cli - name: Install CocoaPods dependencies script: cd ios && pod install # Rock checks the S3 cache before building. A cache hit skips Xcode # compilation entirely; a miss builds from source and uploads the artifact. # CERTIFICATE_PATH and PROVISIONING_PROFILE_PATH are injected automatically # by Codemagic from the ios_signing block above. - name: Build iOS (with remote cache) script: | rock remote-cache download \ --platform ios \ --destination device \ --configuration Release || true if rock remote-cache is-cached \ --platform ios \ --destination device \ --configuration Release; then echo "Cache hit — skipping native build" else echo "No cache hit — building from source" rock build:ios \ --destination device \ --configuration Release \ --extra-params "CODE_SIGN_IDENTITY='iPhone Distribution' \ PROVISIONING_PROFILE_SPECIFIER='$BUNDLE_ID'" rock remote-cache upload \ --platform ios \ --destination device \ --configuration Release fi artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM publishing: app_store_connect: # Use referenced App Store Connect API key to authenticate binary upload auth: integration submit_to_testflight: true email: recipients: - mobile@yourcompany.com notify: success: true failure: true ``` --- ## Caching Behaviour and Cache Management Rock stores each artifact under a key derived from the native fingerprint, platform, variant/configuration, and destination. The `.rock/` directory in your project root holds locally downloaded cache entries; you do not need to include this in Codemagic's `cache_paths` since remote artifacts are fetched fresh on every run. Cache entries in S3 accumulate over time. If bucket size becomes a concern, apply an S3 lifecycle policy to expire objects older than 30–60 days. Because fingerprints are deterministic, expiring old entries only means the next CI run on that native state pays the full build cost once before re-populating the cache. --- ## Monorepo Layout If your React Native app lives inside a monorepo sub-directory (e.g. `packages/mobile`), run all Rock commands from that directory: ```yaml scripts: - name: Install dependencies script: cd packages/mobile && npm ci - name: Build Android script: | cd packages/mobile rock remote-cache download --platform android --variant release || true rock build:android --variant release --aab rock remote-cache upload --platform android --variant release ``` The `rock.config.mjs` file must live in the sub-package root alongside `package.json`, not at the repository root. --- ## Optional: Re.Pack and Super App Builds Rock supports [Re.Pack](https://re.pack.dev/) as an alternative bundler, enabling Module Federation–based Super App and microfrontend architectures. To switch from Metro to Re.Pack: ```bash npm install @rock-js/plugin-repack ``` ```js // rock.config.mjs import { pluginRepack } from '@rock-js/plugin-repack'; export default { // ... bundler: pluginRepack(), }; ``` No changes to the `codemagic.yaml` build scripts are required — `rock build:android` and `rock build:ios` invoke Re.Pack automatically once the bundler plugin is configured. --- ## Optional: Brownfield — Packaging React Native as a Native Library Rock can package your React Native app as a native library (`.xcframework` for iOS, `.aar` for Android) for embedding into an existing native host application, using the `@rock-js/plugin-brownfield-ios` and `@rock-js/plugin-brownfield-android` plugins. Add the plugins to your config: ```js import { pluginBrownfieldIos } from '@rock-js/plugin-brownfield-ios'; import { pluginBrownfieldAndroid } from '@rock-js/plugin-brownfield-android'; export default { plugins: [ pluginBrownfieldIos(), pluginBrownfieldAndroid(), ], // ... }; ``` Then add packaging steps to your Codemagic build: ```yaml scripts: - name: Package React Native as iOS framework script: rock package:ios --configuration Release - name: Package React Native as Android AAR script: rock package:android --variant release ``` Outputs are placed under `.rock/cache/ios/package/` (`.xcframework`) and `.rock/cache/android/package/` (`.aar`) respectively. Include these paths in your `artifacts:` block to make them available as Codemagic build artifacts. --- ## Environment Variable Reference | **Variable** | **Set in** | **Required for** | **Description** | |---|---|---|---| | `ROCK_S3_BUCKET` | env group | Remote cache | S3 or R2 bucket name | | `ROCK_S3_REGION` | env group | Remote cache | AWS region (`auto` for R2) | | `ROCK_S3_ACCESS_KEY_ID` | env group | Remote cache | S3/R2 access key ID | | `ROCK_S3_SECRET_ACCESS_KEY` | env group | Remote cache | S3/R2 secret key | | `CF_ACCOUNT_ID` | env group | Remote cache (R2) | Cloudflare account ID | | `CM_KEYSTORE_PATH` | auto (android_signing) | Android release | Path to keystore on build machine | | `CM_KEYSTORE_PASSWORD` | auto (android_signing) | Android release | Keystore store password | | `CM_KEY_ALIAS` | auto (android_signing) | Android release | Key alias | | `CM_KEY_PASSWORD` | auto (android_signing) | Android release | Key password | | `CERTIFICATE_PATH` | auto (ios_signing) | iOS release | Path to `.p12` on build machine | | `PROVISIONING_PROFILE_PATH` | auto (ios_signing) | iOS release | Path to `.mobileprovision` | | `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS` | env group | Android publishing | Google Play service account JSON | --- ## Further Reading - [Rock documentation](https://www.rockjs.dev/docs/introduction) - [Rock configuration reference](https://www.rockjs.dev/docs/configuration) - [S3 / R2 remote cache setup](https://www.rockjs.dev/docs/configuration#s3-provider) - [Callstack blog: Caching React Native builds on S3 and R2 with Rock](https://www.callstack.com/blog/caching-react-native-builds-on-s3-and-r2) - [Codemagic — Android code signing](https://docs.codemagic.io/yaml-code-signing/signing-android/) - [Codemagic — iOS code signing](https://docs.codemagic.io/yaml-code-signing/signing-ios/) - [Codemagic — Environment variable groups](https://docs.codemagic.io/yaml-basic-configuration/configuring-environment-variables/) - [Codemagic — Publishing to Google Play](https://docs.codemagic.io/yaml-publishing/google-play/) - [Codemagic — Publishing to App Store Connect](https://docs.codemagic.io/yaml-publishing/app-store-connect/) ================================================================================ source: https://docs.codemagic.io/integrations/sentry-crashlytics-dsym-uploading/ title: Uploading dSYM to Sentry description: How to upload dsym artifacts to Sentry last_modified: 2026-06-26 ================================================================================ # Uploading dSYM to Sentry > How to upload dsym artifacts to Sentry [**Sentry**](https://sentry.io/from/crashlytics/) is a crash reporting platform that provides you with real-time insight into production deployments with info to reproduce and fix crashes. **dSYM** is used to symbolicate your crash reports. The purpose of **dSYM** is to replace symbols in the crash logs with the specific methods so it will be readable and helpful for debugging the crash. A sample project showing how to upload **dSYM** files to Sentry can be found in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/sentry_integration_demo_project). ## Configure access to Sentry In order to configure them correctly, a Sentry access token (`SENTRY_ACCESS_TOKEN`) is required which can be found in your Sentry account after signing up. After getting the necessary token along with your organization name (`SENTRY_ORGANIZATION_NAME`) and project name (`SENTRY_PROJECT_NAME`), add them as environment variables in Codemagic. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `SENTRY_ACCESS_TOKEN`. 3. Copy and paste the API token string as **_Variable value_**. 4. Enter the variable group name, e.g. **_sentry_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to also add `SENTRY_ORGANIZATION_NAME` and `SENTRY_PROJECT_NAME` variables. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - sentry_credentials ``` ## Install Sentry dependency To generate debug symbols with **Sentry**, a platform-specific dependency needs to be installed. **Sentry** provides different ways of installing the Sentry dependency according to which platform your app is built with. More information can be found in the **Sentry** documentation [here](https://docs.sentry.io/). The following example installs the dependency for React Native apps: ```yaml scripts: - name: Install Sentry dependency script: | npm install --save @sentry/react-native ``` ## Specify artifacts path As soon as your build finishes successfully, debug symbols are generated. However, if you want them to be displayed in the Codemagic UI build page, the following path needs to be configured in **codemagic.yaml** under the artifacts section: ```yaml artifacts: - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM ``` ## Publish to Sentry In order to upload the dSYM files to Sentry, add the following script to your **codemagic.yaml** configuration file or to your post-publish script in the Flutter workflow editor: ```yaml scripts: - name: Install Sentry dependency script: | echo "Find build artifacts" dsymPath=$(find $CM_BUILD_DIR/build/ios/xcarchive/*.xcarchive -name "*.dSYM" | head -1) if [[ -z ${dsymPath} ]] then echo "No debug symbols were found, skip publishing to Sentry" else echo "Publishing debug symbols from $dsymPath to Sentry" sentry-cli --auth-token $SENTRY_ACCESS_TOKEN upload-dif \ --org $SENTRY_ORGANIZATION_NAME \ --project $SENTRY_PROJECT_NAME $dsymPath fi ``` The above-mentioned **dsymPath** is React Native and Native iOS specific and it could change depending on what platform the app is built on. For example, Flutter apps should use: ```yaml dsymPath=$(find $CM_BUILD_DIR/build/ios/archive/Runner.xcarchive -name "*.dSYM" | head -1) ``` If necessary, you can use remote access to the build machine to find the correct path. More information can be found [here](https://docs.codemagic.io/troubleshooting/accessing-builder-machine-via-ssh/). ================================================================================ source: https://docs.codemagic.io/integrations/sofy-integration/ title: Sofy integration description: How to integrate your workflows with Sofy using codemagic.yaml last_modified: 2026-02-16 ================================================================================ # Sofy integration > How to integrate your workflows with Sofy using codemagic.yaml **Sofy** is a testing automation platform that uses testing capabilities to enable tests without writing a single line of code. It is possible to publish binaries generated by **Codemagic** and schedule automation tests with **Sofy** via `codemagic.yaml`. A sample project that shows how to configure Sofy integration is available in our [Sample projects repository](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/sofy_integration_demo_project). ## Configuring Sofy access You will need to sign up with [Sofy](https://sofy.ai/) so you can obtain an **API Key** which is required for deploying your apps via **Codemagic**. In addition, you will also need the **Sofy subscription key** and the **Schedule ID**, both obtainable from your Sofy account settings. 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `SOFY_API_KEY`. 3. Copy and paste the API key string as **_Variable value_**. 4. Enter the variable group name, e.g. **_sofy_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the steps to also add `SOFY_SUBSCRIPTION_KEY`, `SOFY_SCHEDULE_ID`, and `$SOFY_SCHEDULE_GUID` variables. 8. Add the variable group to your `codemagic.yaml` file ```yaml environment: groups: - sofy_credentials ``` ## Real Time and App Automation The following examples show how to use **cURL** commands in your `codemagic.yaml` to deploy and test your app with Sofy. #### Uploading apps ```yaml scripts: - name: Publish APK / AAB / IPA to Sofy script: | curl --location "https://public.sofy.ai/parser-microservice/build-upload" \ --header "x-sofy-auth-key: $SOFY_SUBSCRIPTION_KEY" \ --form "applicationFile=@/build/app/outputs/flutter-apk/app-release.apk" \ ``` #### Uploading apps with Certificate Name (if any) for iOS builds ```yaml scripts: - name: Publishing IPA with a Certificate name script: | curl --location "https://public.sofy.ai/parser-microservice/build-upload" \ --header "x-sofy-auth-key: $SOFY_SUBSCRIPTION_KEY" \ --form "applicationFile=@build/ios/ipa/native_ios_app.ipa" \ --form 'CertificateName=""' ``` #### Uploading apps with Application Guid (linking application) ```yaml scripts: - name: Publishing APK with Application Guid script: | curl --location "https://public.sofy.ai/parser-microservice/build-upload" \ --header "x-sofy-auth-key: SOFY_SUBSCRIPTION_KEY" \ --form "applicationFile=@/build/app/outputs/flutter-apk/app-release.apk" \ --form 'ApplicationGUID=""' ``` #### Scheduling automation tests ```yaml scripts: - name: Schedule an automation test with Sofy script: | curl --location --request POST "https://public.sofy.ai/scheduler-microservice/scheduled-runs/:scheduledRunGuid/execute" \ --header "x-sofy-auth-key: SOFY_SUBSCRIPTION_KEY" ``` #### Scheduling automation tests on a particular build using application hash ```yaml scripts: - name: Schedule an automation test (on a specific build) with Sofy script: | curl --location --request POST "https://public.sofy.ai/scheduler-microservice/scheduled-runs/:scheduledRunGuid/execute?appHash=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \ --header "x-sofy-auth-key: SOFY_SUBSCRIPTION_KEY" ``` > > Note: **:scheduledRunGuid** will be replaced by the **SOFY_SCHEDULE_GUID** variable which can be found in your Sofy account, **appHash** will be fetched from the app upload API response mentioned above. > #### Fetching test run group IDs ```yaml scripts: - name: Fetch test run group IDs with Sofy script: | curl --location "https://public.sofy.ai/scheduler-microservice/scheduled-runs/$SOFY_SCHEDULE_GUID/test-run-groups" \ --header "x-sofy-auth-key: SOFY_SUBSCRIPTION_KEY" ``` #### Checking the status of scheduled tests ```yaml scripts: - name: Checking the status of scheduled tests script: | curl --location "https://public.sofy.ai/scheduler-microservice/scheduled-runs/$SOFY_SCHEDULE_GUID/status/:testRunGroupId" \ --header "x-sofy-auth-key: SOFY_SUBSCRIPTION_KEY" ``` > > `:testRunGroupId` will be replaced by test run group ID fetched from the response of the `Fetching test run group IDs` step above. > As soon as your **.ipa** and **.apk** are successfully built, they will appear in the **Sofy UI** and any preferred devices can be selected for testing with **Real Time**. If devices need to be pre-chosen, then some capabilities provided by **Sofy** device settings must be injected into your project's test scripts first. ================================================================================ source: https://docs.codemagic.io/rn-codepush/ionic-capacitor-codepush/ title: OTA updates for Ionic Capacitor apps description: Step-by-step guide to enabling CodePush OTA updates in an Ionic Capacitor app, including migration from Ionic Appflow Live Updates last_modified: 2026-06-26 ================================================================================ # OTA updates for Ionic Capacitor apps > Step-by-step guide to enabling CodePush OTA updates in an Ionic Capacitor app, including migration from Ionic Appflow Live Updates This guide walks you through integrating Codemagic CodePush into an Ionic Capacitor app to deliver JavaScript and web asset updates instantly, without waiting for an App Store or Google Play review. --- ## Prerequisites - Ionic Capacitor project (Capacitor 4 or later) - Node.js 18+ - A Codemagic account with CodePush access - The Codemagic CodePush CLI: ```bash npm install -g @codemagic/code-push-cli ``` - Java 21 for the Android build toolchain --- ## Migrating from Ionic Appflow Live Updates ### How CodePush differs from Appflow If you are migrating from Ionic Appflow, the mental model is similar but the implementation differs in a few important ways. Appflow handles update checks through its own SDK with minimal code changes on your side; with CodePush, you call `codePush.sync()` explicitly, which gives you more control over when and how updates are presented. Deployment channels in Appflow map directly to deployments in CodePush — Staging and Production work the same way. | | **Appflow Live Updates** | **Codemagic CodePush** | |---|---|---| | **Update check** | Appflow SDK, configurable | `codePush.sync()` called in your code | | **SDK package**| Appflow SDK | `cap-codepush` | | **Deployment channels** | Channels | Deployments (Staging / Production) | | **CLI** | `ionic deploy` | `code-push release` | | **Rollback** | Dashboard | Automatic on crash; `code-push rollback` | ### Migrating from Appflow — what to remove Before adding CodePush, remove all Appflow Live Updates references from your project. Leaving them in place will cause conflicts, since both SDKs attempt to manage and replace the same web assets. The steps below cover the most common Appflow setup — your project may use a subset of these depending on which Appflow features you had enabled. Remove the Appflow SDK package: ```bash npm uninstall @ionic/portals @ionic-enterprise/live-updates # remove whichever Appflow OTA package your project uses ``` Remove the Appflow plugin block from `capacitor.config.ts`: ```typescript // Remove this: plugins: { LiveUpdates: { appId: 'your-appflow-app-id', channel: 'Production', autoUpdateMethod: 'background', maxVersions: 2 } } ``` Remove any Appflow SDK initialisation calls from your app code — typically `Deploy.configure(...)` or `IonicLiveUpdates` calls in `app.component.ts` or `main.ts`. ## Configuring your Capacitor app ### Where this guide diverges from the React Native CodePush docs If you have used Codemagic CodePush with React Native, you will notice that several things are different for Capacitor: **No `strings.xml` or `Info.plist` entries required.** The React Native plugin reads configuration from native resource files directly because React Native has no equivalent of the Capacitor config layer. In Capacitor, the `plugins` block in `capacitor.config.ts` is read by the native plugin at runtime via Capacitor's configuration bridge. You do not need to touch `strings.xml` or `Info.plist`. **No root component wrapping.** React Native integrates CodePush by wrapping the root component: `export default codePush(App)`. Capacitor has no equivalent — you call `codePush.sync()` directly in your app's lifecycle, as shown in Step 4. **No `code-push release-react`.** React Native uses `code-push release-react` which builds the JS bundle internally. For Capacitor, you build with `ionic build` yourself and release the output folder with `code-push release`. ### Step 1 — Authenticate the CLI and register your apps Log in using the access token provided by Codemagic: ```bash code-push login --access-key YOUR_ACCESS_TOKEN ``` Create a separate CodePush app registration for each platform: ```bash code-push app add MyApp-iOS code-push app add MyApp-Android ``` Each app is provisioned with two deployment environments automatically: **Staging** and **Production**. List the deployment keys — you will need them in the next step: ```bash code-push deployment ls MyApp-iOS -k code-push deployment ls MyApp-Android -k ``` --- ### Step 2 — Install the plugin Install the `cap-codepush` plugin. The package is versioned to match your Capacitor major version: ```bash npm install cap-codepush@8 ``` Match the `cap-codepush` version to your Capacitor major version: `@8` for Capacitor 8, `@7` for Capacitor 7, `@3` for Capacitor 6, `@2` for Capacitor 5, `@1` for Capacitor 4. Also install the required Capacitor peer dependencies: ```bash npm install @capacitor/device @capacitor/dialog @capacitor/filesystem ``` Sync the native projects: ```bash npx cap sync ``` --- ### Step 3 — Configure the plugin All CodePush configuration goes in `capacitor.config.json` (or `capacitor.config.ts`). No changes to `Info.plist` or `strings.xml` are required. Add a `CodePush` block under `plugins` with your deployment keys and the Codemagic server URL: ```json { "appId": "com.example.myapp", "appName": "MyApp", "webDir": "www", "plugins": { "CodePush": { "IOS_DEPLOY_KEY": "YOUR_IOS_STAGING_DEPLOYMENT_KEY", "ANDROID_DEPLOY_KEY": "YOUR_ANDROID_STAGING_DEPLOYMENT_KEY", "SERVER_URL": "https://codepush.pro/" } } } ``` Run `npx cap sync` after any change to `capacitor.config.ts` to propagate the values into the native projects. > > For production builds, replace the Staging keys with your Production deployment keys. A common CI pattern is to generate the config file at build time and inject the appropriate key from an environment variable. > --- ### Step 4 — Add CodePush sync to your app Open `src/app/app.component.ts` (or your app entry point) and add an update check on startup. #### Silent background update (recommended for iOS) Silent updates download in the background and apply on the next app launch. This is fully compliant with App Store guidelines and is the recommended approach for iOS: ```typescript import { Component } from '@angular/core'; import { codePush } from 'cap-codepush'; import { Capacitor } from '@capacitor/core'; @Component({ selector: 'app-root', templateUrl: 'app.component.html', }) export class AppComponent { constructor() { this.checkForUpdates(); } async checkForUpdates() { if (!Capacitor.isNativePlatform()) { return; // skip in browser } try { await codePush.sync(); } catch (err) { console.error('CodePush sync failed:', err); } } } ``` #### Interactive update prompt (Android / internal distribution only) > > **Important:** Apple's App Store guidelines do not permit showing users an update prompt. Only use `updateDialog` for Android builds or internal/enterprise distribution. > ```typescript import { codePush, InstallMode } from 'cap-codepush'; async checkForUpdatesInteractive() { if (!Capacitor.isNativePlatform()) return; await codePush.sync( { updateDialog: { updateTitle: 'Update Available', optionalUpdateMessage: 'A new version is available. Install now?', optionalInstallButtonLabel: 'Install', optionalIgnoreButtonLabel: 'Later', mandatoryUpdateMessage: 'A required update is available.', mandatoryContinueButtonLabel: 'Continue', }, installMode: InstallMode.IMMEDIATE, }, (progress) => { console.log(`Downloaded ${progress.receivedBytes} of ${progress.totalBytes}`); } ); } ``` #### Check for updates on app resume (optional) To catch updates when the app comes back to the foreground: ```typescript import { App } from '@capacitor/app'; // In constructor or ngOnInit App.addListener('appStateChange', ({ isActive }) => { if (isActive) { this.checkForUpdates(); } }); ``` --- ### Step 5 — Build the native binary and install on device CodePush delivers updates on top of an already-installed native binary. Users must have installed the app from the App Store, Google Play, or a direct install before they can receive OTA updates. Build and install the initial binary as you normally would: ```bash ionic build npx cap sync ``` Then build and run via Xcode (iOS) or Android Studio (Android), or use the `codemagic.yaml` workflows at the end of this guide to build through Codemagic CI/CD. --- ### Step 6 — Release an OTA update Once the base binary is on devices, any subsequent change to your web code can be shipped as a CodePush update. #### Build and sync web assets ```bash ionic build npx cap copy ``` Running `npx cap copy` copies the compiled web assets from `www/` into the native project directories without updating native plugin dependencies. This is intentional — a CodePush release only delivers web assets, so native dependencies must stay in sync with the installed binary. Running `npx cap sync` instead risks updating native plugin code that will not be delivered to users and could cause crashes if your web code references the newer native APIs. #### Release to Staging ```bash # iOS code-push release MyApp-iOS ios/App/App/public/ "1.0.0" \ --deploymentName Staging \ --description "Your release description" # Android code-push release MyApp-Android android/app/src/main/assets/public/ "1.0.0" \ --deploymentName Staging \ --description "Your release description" ``` The version string (`"1.0.0"`) must match the `version` field in your `package.json`. This ensures the update is only delivered to users running a compatible native binary. To target all installed binary versions during development: ```bash code-push release MyApp-iOS ios/App/App/public/ "*" --deploymentName Staging ``` #### Verify the release ```bash code-push deployment history MyApp-iOS Staging code-push deployment history MyApp-Android Staging ``` #### Promote to Production Once validated in Staging, promote the release to Production without re-uploading: ```bash code-push promote MyApp-iOS Staging Production code-push promote MyApp-Android Staging Production ``` #### Rollback if needed ```bash code-push rollback MyApp-iOS Production code-push rollback MyApp-Android Production ``` --- ## Automate with Codemagic CI/CD Add a `codemagic.yaml` to your repository to automate both OTA releases and full native builds. The example below defines three workflows: - **`ota-update`** — builds web assets, syncs them to the native folders, and releases an OTA update to Staging. Runs automatically on every push to `main`. No code signing needed. - **`android-release`** — full signed Android build, published to Google Play. - **`ios-release`** — full signed iOS build, published to TestFlight/App Store. Store your CodePush access token as a secret environment variable in your team settings (**Team Settings → Environment variable groups**) in a group called `codepush_credentials`. ```yaml workflows: # ───────────────────────────────────────────────────────────────── # OTA UPDATE — runs on every merge to main, no native build needed # ───────────────────────────────────────────────────────────────── ota-update: name: CodePush OTA Release max_build_duration: 30 instance_type: linux_x2 triggering: events: - push branch_patterns: - pattern: main environment: node: latest groups: - codepush_credentials # contains CODEPUSH_ACCESS_TOKEN vars: CODEPUSH_APP_IOS: "MyApp-iOS" CODEPUSH_APP_ANDROID: "MyApp-Android" CODEPUSH_DEPLOYMENT: "Staging" scripts: - name: Install dependencies script: npm ci - name: Build web assets script: ionic build --prod - name: Sync web assets to native directories script: npx cap copy - name: Install CodePush CLI script: npm install -g @codemagic/code-push-cli - name: Authenticate with CodePush script: code-push login --access-key $CODEPUSH_ACCESS_TOKEN - name: Release iOS OTA update script: | APP_VERSION=$(node -p "require('./package.json').version") COMMIT_MESSAGE=$(git log --format=%B -n 1 $CM_COMMIT) code-push release \ $CODEPUSH_APP_IOS \ ios/App/App/public/ \ "$APP_VERSION" \ --deploymentName "$CODEPUSH_DEPLOYMENT" \ --description "$COMMIT_MESSAGE" - name: Release Android OTA update script: | APP_VERSION=$(node -p "require('./package.json').version") COMMIT_MESSAGE=$(git log --format=%B -n 1 $CM_COMMIT) code-push release \ $CODEPUSH_APP_ANDROID \ android/app/src/main/assets/public/ \ "$APP_VERSION" \ --deploymentName "$CODEPUSH_DEPLOYMENT" \ --description "$COMMIT_MESSAGE" publishing: email: recipients: - your-team@example.com notify: success: true failure: true # ───────────────────────────────────────────────────────────────── # ANDROID NATIVE RELEASE — full build + Google Play publish # Run this when native code, plugins, or the app version changes # ───────────────────────────────────────────────────────────────── android-release: name: Android Release Build max_build_duration: 120 instance_type: linux_x2 environment: android_signing: - keystore_reference groups: - google_play vars: PACKAGE_NAME: "com.example.myapp" GOOGLE_PLAY_TRACK: "internal" node: latest scripts: - name: Set up local.properties script: | echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/android/local.properties" - name: Install npm dependencies script: npm ci - name: Build web assets script: ionic build --prod - name: Sync web assets to native project script: npx cap copy android - name: Build Android release bundle script: | LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number \ --package-name "$PACKAGE_NAME") if [ -z "$LATEST_GOOGLE_PLAY_BUILD_NUMBER" ]; then UPDATED_BUILD_NUMBER=$BUILD_NUMBER else UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1)) fi cd android ./gradlew bundleRelease \ -PversionCode=$UPDATED_BUILD_NUMBER \ -PversionName=$(node -p "require('../package.json').version") artifacts: - android/app/build/outputs/**/*.aab - android/app/build/outputs/**/*.apk publishing: email: recipients: - your-team@example.com notify: success: true failure: true google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: $GOOGLE_PLAY_TRACK submit_as_draft: true # ───────────────────────────────────────────────────────────────── # iOS NATIVE RELEASE — full build + TestFlight / App Store publish # Run this when native code, plugins, or the app version changes # ───────────────────────────────────────────────────────────────── ios-release: name: iOS Release Build max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: codemagic environment: ios_signing: distribution_type: app_store bundle_identifier: com.example.myapp vars: APP_STORE_APPLE_ID: "1555555551" XCODE_WORKSPACE: "ios/App/App.xcworkspace" XCODE_SCHEME: "App" node: latest scripts: - name: Install npm dependencies script: npm ci - name: Install CocoaPods dependencies script: cd ios/App && pod install - name: Build web assets script: ionic build --prod - name: Sync web assets to native project script: npx cap copy ios - name: Set up code signing script: xcode-project use-profiles - name: Increment build number script: | cd $CM_BUILD_DIR/ios/App LATEST_BUILD_NUMBER=$(app-store-connect get-latest-app-store-build-number \ "$APP_STORE_APPLE_ID") agvtool new-version -all $(($LATEST_BUILD_NUMBER + 1)) - name: Build IPA script: | cd $CM_BUILD_DIR/ios/App xcode-project build-ipa \ --workspace "$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" artifacts: - ios/App/build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.dSYM publishing: email: recipients: - your-team@example.com notify: success: true failure: true app_store_connect: auth: integration submit_to_testflight: true beta_groups: - Internal Testers ``` > > **When to run which workflow:** Use `ota-update` for everyday changes that only touch JavaScript, TypeScript, or web assets. Use `android-release` or `ios-release` when you add or update native plugins, change Capacitor configuration, update native platform code, or bump the app's store version. After each native release, update the version string in `package.json` so future CodePush releases correctly target the new binary. > --- ## Troubleshooting **Update is not received by the app** - Confirm `SERVER_URL` in `capacitor.config.json` is exactly `https://codepush.pro/` — the trailing slash matters. - Confirm the deployment key in your config matches the output of `code-push deployment ls MyApp-iOS -k`. - The version string in `code-push release` must match the `version` in `package.json`, unless you used `"*"` to target all versions. - Configuration changes are baked into the native binary at build time — rebuild and reinstall the app after any changes to `capacitor.config.json`. **CSP error blocking network requests** Confirm that `https://codepush.pro` appears in the `default-src` directive of your Content Security Policy `` tag in `src/index.html`. **Plugin not found or `codePush` is undefined** The plugin registers after the native platform is ready. In Angular, make sure your sync call runs after `Platform.ready()` resolves, or place it in `ngOnInit` rather than the constructor. --- ## Next steps - [CodePush overview and pricing](https://codemagic.io/codepush/) - [Building Ionic Capacitor apps with Codemagic](../yaml-quick-start/building-an-ionic-app/) - [Environment variables and secrets](../yaml-basic-configuration/environment-variables/) - [Build versioning](../configuration/build-versioning/) ================================================================================ source: https://docs.codemagic.io/integrations/sonarcloud-integration/ title: SonarCloud integration description: How to integrate your workflows with SonarCloud using codemagic.yaml last_modified: 2026-06-18 ================================================================================ # SonarCloud integration > How to integrate your workflows with SonarCloud using codemagic.yaml **SonarCloud** is SonarQube's cloud-based code quality and code security service for projects hosted in cloud-based Git repositories such as GitHub, Bitbucket, GitLab and Azure DevOps. It can be used as part of your CI/CD workflow to analyse your code each time you commit new code. Sample projects that show how to configure SonarQube / SonarCloud integration are available in our sample projects repository for [Android](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/sonarqube_integration_demo_project/Android) and [iOS](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/integrations/sonarqube_integration_demo_project/Sonar). ## Create a SonarCloud account You will need access to a SonarCloud account and can [sign up](https://sonarcloud.io/) for free. This will allow you to work with public repositories. ## Add your app to SonarCloud 1. Log into SonarCloud [here](https://sonarcloud.io/sessions/new) 2. Enter an organization key and click on **Continue**. 3. Choose the Free plan and click on **Create Organization**. 4. Click on **My Account**. 5. Under the Security tab, generate a token by entering a name and clicking on **Generate**. 6. Copy the token so you can use it as an environment variable in your Codemagic workflow. 7. Click on the “+” button in the top-right corner, and select **Analyze a new project** to add a new project. 8. Select the project and click on **Set Up**. 9. Wait for the initial analysis to complete, then modify the **Last analysis method**. 10. **Turn off** the SonarCloud Automatic Analysis. You can now upload code analysis reports to SonarCloud from your CI/CD pipeline. ## Configuring access to SonarCloud in Codemagic There are three **environment variables** that need to be added to your workflow for the SonarCloud integration: `SONAR_TOKEN`, `SONAR_PROJECT_KEY`, and `SONAR_ORG_KEY`. - `SONAR_TOKEN` is the token you created when setting up your account - `SONAR_PROJECT_KEY` can be obtained from your project settings once it has been added to SonarCloud - `SONAR_ORG_KEY` is also obtained from your SonarCloud project settings 1. Open your Codemagic app settings, and go to the **Environment variables** tab. 2. Enter the desired **_Variable name_**, e.g. `SONAR_TOKEN`. 3. Enter the required value as **_Variable value_**. 4. Enter the variable group name, e.g. **_sonarcloud_credentials_**. Click the button to create the group. 5. Make sure the **Secret** option is selected. 6. Click the **Add** button to add the variable. 7. Repeat the process to add all of the required variables. 8. Add the **sonarcloud_credentials** group in your `codemagic.yaml` file ```yaml environment: groups: - sonarcloud_credentials ``` ## Platform specific configuration ### Option: Android To use SonarCloud with Android projects, you need to add the **sonarqube plugin** to the `app/build.gradle` file: ```Groovy plugins { ... id "org.sonarqube" version "3.3" ... } ``` You also need to set Sonarcloud properties in the same `app/build.gradle` file ```Groovy sonarqube { properties { property "sonar.host.url", "https://sonarcloud.io" property "sonar.branch", System.getenv("CM_BRANCH") property "sonar.projectKey", System.getenv("SONAR_PROJECT_KEY") property "sonar.organization", System.getenv("SONAR_ORG_KEY") property "sonar.branch.name", System.getenv("CM_BRANCH") property "sonar.branch.target", System.getenv("CM_PULL_REQUEST_DEST") property "sonar.login", System.getenv("SONAR_TOKEN") } } ``` Finally, add the scripts to build the debug version and generate the analysis report to your `codemagic.yaml` file ```yaml scripts: - name: Generate debug build script: | ./gradlew assembleDebug - name: Generate and upload code analysis report script: | ./gradlew sonarqube ``` An Android sample project that shows how to configure SonarCloud integration is available [here](https://github.com/codemagic-ci-cd/android-sonarcloud-sample-project) ### Option: iOS To use SonarCloud with iOS projects, you need to: 1. install the [Sonar Scanner](https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/) 2. generate a debug build of your project 3. convert the coverage report to Sonarqube format 4. generate and upload code analysis report To convert the coverage report to Sonarqube format, create a bash script in your project's root folder named `xccov-to-sonarqube-generic.sh` with the following content: ```bash #!/usr/bin/env bash set -euo pipefail function convert_file { local xccovarchive_file="$1" local file_name="$2" local xccov_options="$3" echo " " xcrun xccov view $xccov_options --file "$file_name" "$xccovarchive_file" | \ sed -n ' s/^ *\([0-9][0-9]*\): 0.*$/ /p; s/^ *\([0-9][0-9]*\): [1-9].*$/ /p ' echo ' ' } function xccov_to_generic { echo '' for xccovarchive_file in "$@"; do if [[ ! -d $xccovarchive_file ]] then echo "Coverage FILE NOT FOUND AT PATH: $xccovarchive_file" 1>&2; exit 1 fi local xccov_options="" if [[ $xccovarchive_file == *".xcresult"* ]]; then xccov_options="--archive" fi xcrun xccov view $xccov_options --file-list "$xccovarchive_file" | while read -r file_name; do convert_file "$xccovarchive_file" "$file_name" "$xccov_options" done done echo '' } xccov_to_generic "$@" ``` All of the other steps will be performed using scripts in your `codemagic.yaml` file: ```yaml scripts: - name: Install Sonar Scanner script: | brew install sonar-scanner - name: Generate debug build script: | xcodebuild \ -project "$XCODE_PROJECT" \ -scheme "$XCODE_SCHEME" \ -sdk iphonesimulator \ -destination 'platform=iOS Simulator,name=iPhone 16 Pro' \ -derivedDataPath Build/ \ -enableCodeCoverage YES \ clean build test CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO - name: Convert coverage report to Sonarqube format script: | bash xccov-to-sonarqube-generic.sh Build/Logs/Test/*.xcresult/ > sonarqube-generic-coverage.xml - name: Generate and upload code analysis report script: | export PATH=$PATH:$CM_BUILD_DIR/sonar-scanner/bin sonar-scanner \ -Dsonar.projectKey=$SONAR_PROJECT_KEY \ -Dsonar.organization=$SONAR_ORG_KEY \ -Dsonar.host.url=https://sonarcloud.io \ -Dsonar.login=$SONAR_TOKEN \ -Dsonar.projectVersion=1.0.0 \ -Dsonar.sources=. \ -Dsonar.cfamily.build-wrapper-output.bypass=true \ -Dsonar.coverageReportPaths=sonarqube-generic-coverage.xml \ -Dsonar.c.file.suffixes=- \ -Dsonar.cpp.file.suffixes=- \ -Dsonar.objc.file.suffixes=- ``` An iOS sample project that shows how to configure SonarCloud integration is available [here](https://github.com/codemagic-ci-cd/ios-sonarcloud-sample-project) ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-27-0/ title: Xcode 27.0.x (edge) last_modified: 2026-08-26 ================================================================================ # Xcode 27.0.x (edge) Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 26.6.2 (25G83)` - Kernel version `Darwin 25.6.0` - Disk `294GB (Free Space: 146GB)` ## Xcode versions - 27.0 (27A5252f) `/Applications/Xcode-27.0.app`, also selected when specifying `edge` in Xcode version settings ### Runtimes and Devices {{< collapsible title="iOS 26.5" >}} - iPad (A16) - iPad Air 11-inch (M4) - iPad Air 13-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone 17e - iPhone Air {{< /collapsible >}} {{< collapsible title="iOS 27.0" >}} - iPad (A16) - iPad Air 11-inch (M4) - iPad Air 13-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone 17e - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 27.0" >}} - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 27.0" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 27.0" >}} - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2026.1` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 build-tools;36.1.0 | 36.1.0 | Android SDK Build-Tools 36.1 | build-tools/36.1.0 build-tools;37.0.0 | 37.0.0 | Android SDK Build-Tools 37 | build-tools/37.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.31.6 | 3.31.6 | CMake 3.31.6 | cmake/3.31.6 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.1.2 | 4.1.2 | CMake 4.1.2 | cmake/4.1.2 cmdline-tools;22.0 | 22.0 | Android SDK Command-line Tools | cmdline-tools/22.0 emulator | 37.1.11 | Android Emulator | emulator extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK (Deprecated) | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;28.2.13676358 | 28.2.13676358 | NDK (Side by side) 28.2.13676358 | ndk/28.2.13676358 ndk;29.0.14206865 | 29.0.14206865 | NDK (Side by side) 29.0.14206865 | ndk/29.0.14206865 ndk;30.0.16138531 | 30.0.16138531 rc3 | NDK (Side by side) 30.0.16138531 | ndk/30.0.16138531 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 37.0.1 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36.1 | 1 | Android SDK Platform 36.1 | platforms/android-36.1 platforms;android-37.0 | 2 | Android SDK Platform 37.0 | platforms/android-37.0 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36.1 | 1 | Sources for Android 36.1 | sources/android-36.1 sources;android-37.0 | 2 | Sources for Android 37.0 | sources/android-37.0 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 28.2.13676358 | `/usr/local/share/android-sdk/ndk/28.2.13676358` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | | 30.0.16138531 | `/usr/local/share/android-sdk/ndk/30.0.16138531` | | 29.0.14206865 | `/usr/local/share/android-sdk/ndk/29.0.14206865` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 26.0.2.1 | `/Library/Java/JavaVirtualMachines/zulu-26.jdk/Contents/Home` | | 21.0.12.1 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.20.1** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.32.1 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_504 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.36.30` - azure-cli `2.89.1` - carthage `0.40.0` - cocoapods `1.17.0` - cordova `12.0.0` - curl `8.7.1` - ew-cli `1.4.2` - fastlane `2.238.0` - firebase `15.28.1` - gem `4.0.19` - gh `2.98.0` - git `2.55.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `6.0.19` - ionic `7.2.1` - jq `1.8.2` - ktlint `1.8.0` - node `24.19.0` - npm `11.17.0` - python `3.12.7` - python3 `3.12.7` - ruby `4.0.6` - ssh `10.3p1` - sudo `1.9.17p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - xcbeautify `3.2.1` - yarn `4.9.2` - yq `4.53.6` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-26-6/ title: Xcode 26.6.x (default) last_modified: 2026-09-06 ================================================================================ # Xcode 26.6.x (default) Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 26.5.1 (25F80)` - Kernel version `Darwin 25.5.0` - Disk `294GB (Free Space: 156GB)` ## Xcode versions - 26.6 (17F113) `/Applications/Xcode-26.6.app` ### Runtimes and Devices {{< collapsible title="iOS 26.5" >}} - iPad (A16) - iPad Air 11-inch (M4) - iPad Air 13-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone 17e - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 26.5" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 26.5" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 26.5" >}} - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2025.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 build-tools;36.1.0 | 36.1.0 | Android SDK Build-Tools 36.1 | build-tools/36.1.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.31.6 | 3.31.6 | CMake 3.31.6 | cmake/3.31.6 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.1.2 | 4.1.2 | CMake 4.1.2 | cmake/4.1.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 20.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;28.2.13676358 | 28.2.13676358 | NDK (Side by side) 28.2.13676358 | ndk/28.2.13676358 ndk;29.0.14206865 | 29.0.14206865 | NDK (Side by side) 29.0.14206865 | ndk/29.0.14206865 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 37.0.0 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36.1 | 1 | Android SDK Platform 36.1 | platforms/android-36.1 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36.1 | 1 | Sources for Android 36.1 | sources/android-36.1 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 28.2.13676358 | `/usr/local/share/android-sdk/ndk/28.2.13676358` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | | 29.0.14206865 | `/usr/local/share/android-sdk/ndk/29.0.14206865` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 26.0.1 | `/Library/Java/JavaVirtualMachines/zulu-26.jdk/Contents/Home` | | 21.0.11 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.19** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.31 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_492 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.35.8` - azure-cli `2.87.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `1.3.4` - fastlane `2.236.1` - firebase `15.22.0` - gem `4.0.14` - gh `2.95.0` - git `2.54.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `6.0.2` - ionic `7.2.1` - jq `1.8.1` - ktlint `1.8.0` - node `24.17.0` - npm `11.13.0` - python `3.12.7` - python3 `3.12.7` - ruby `4.0.5` - ssh `10.2p1` - sudo `1.9.17p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - xcbeautify `3.2.1` - yarn `4.9.2` - yq `4.53.3` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-26-5/ title: Xcode 26.5.x last_modified: 2026-08-13 ================================================================================ # Xcode 26.5.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 26.5 (25F71)` - Kernel version `Darwin 25.5.0` - Disk `294GB (Free Space: 144GB)` ## Xcode versions - 26.5 (17F42) `/Applications/Xcode-26.5.app` ### Runtimes and Devices {{< collapsible title="iOS 26.4" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 11-inch (M4) - iPad Air 13-inch (M3) - iPad Air 13-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone 17e - iPhone Air {{< /collapsible >}} {{< collapsible title="iOS 26.5" >}} - iPad (A16) - iPad Air 11-inch (M4) - iPad Air 13-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone 17e - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 26.5" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 26.5" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 26.5" >}} - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2025.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 build-tools;36.1.0 | 36.1.0 | Android SDK Build-Tools 36.1 | build-tools/36.1.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.31.6 | 3.31.6 | CMake 3.31.6 | cmake/3.31.6 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.1.2 | 4.1.2 | CMake 4.1.2 | cmake/4.1.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 20.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;28.2.13676358 | 28.2.13676358 | NDK (Side by side) 28.2.13676358 | ndk/28.2.13676358 ndk;29.0.14206865 | 29.0.14206865 | NDK (Side by side) 29.0.14206865 | ndk/29.0.14206865 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 37.0.0 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36.1 | 1 | Android SDK Platform 36.1 | platforms/android-36.1 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36.1 | 1 | Sources for Android 36.1 | sources/android-36.1 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 28.2.13676358 | `/usr/local/share/android-sdk/ndk/28.2.13676358` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | | 29.0.14206865 | `/usr/local/share/android-sdk/ndk/29.0.14206865` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 26.0.1 | `/Library/Java/JavaVirtualMachines/zulu-26.jdk/Contents/Home` | | 21.0.11 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.19** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.31 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_492 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.34.45` - azure-cli `2.86.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `1.3.1` - fastlane `2.234.0` - firebase `15.17.0` - gem `4.0.11` - gh `2.92.0` - git `2.54.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `5.1.11` - ionic `7.2.1` - jq `1.8.1` - ktlint `1.8.0` - node `24.15.0` - npm `11.12.1` - python `3.12.7` - python3 `3.12.7` - ruby `4.0.4` - ssh `10.2p1` - sudo `1.9.17p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - xcbeautify `3.2.1` - yarn `4.9.2` - yq `4.53.2` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-26-4/ title: Xcode 26.4.x last_modified: 2026-09-06 ================================================================================ # Xcode 26.4.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 26.4.1 (25E253)` - Kernel version `Darwin 25.4.0` - Disk `294GB (Free Space: 142GB)` ## Xcode versions - 26.4.1 (17E202) `/Applications/Xcode-26.4.app`, also selected when specifying `26.4` or `latest` in Xcode version settings ### Runtimes and Devices {{< collapsible title="iOS 26.3" >}} - iPad (A16) - iPad Air 11-inch (M4) - iPad Air 13-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone 17e - iPhone Air {{< /collapsible >}} {{< collapsible title="iOS 26.4" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 11-inch (M4) - iPad Air 13-inch (M3) - iPad Air 13-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone 17e - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 26.4" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 26.4" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 26.4" >}} - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2025.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 build-tools;36.1.0 | 36.1.0 | Android SDK Build-Tools 36.1 | build-tools/36.1.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.31.6 | 3.31.6 | CMake 3.31.6 | cmake/3.31.6 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.1.2 | 4.1.2 | CMake 4.1.2 | cmake/4.1.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 20.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;28.2.13676358 | 28.2.13676358 | NDK (Side by side) 28.2.13676358 | ndk/28.2.13676358 ndk;29.0.14206865 | 29.0.14206865 | NDK (Side by side) 29.0.14206865 | ndk/29.0.14206865 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 37.0.0 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36.1 | 1 | Android SDK Platform 36.1 | platforms/android-36.1 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36.1 | 1 | Sources for Android 36.1 | sources/android-36.1 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 28.2.13676358 | `/usr/local/share/android-sdk/ndk/28.2.13676358` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | | 29.0.14206865 | `/usr/local/share/android-sdk/ndk/29.0.14206865` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 26 | `/Library/Java/JavaVirtualMachines/zulu-26.jdk/Contents/Home` | | 21.0.10 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.18** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.30 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_482 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.34.32` - azure-cli `2.85.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `1.2.2` - fastlane `2.233.0` - firebase `15.15.0` - gem `4.0.10` - gh `2.90.0` - git `2.53.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `5.1.7` - ionic `7.2.1` - jq `1.8.1` - ktlint `1.8.0` - node `24.15.0` - npm `11.12.1` - python `3.12.7` - python3 `3.12.7` - ruby `4.0.2` - ssh `10.2p1` - sudo `1.9.17p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - xcbeautify `3.2.1` - yarn `4.9.2` - yq `4.53.2` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-26-3/ title: Xcode 26.3.x last_modified: 2026-08-13 ================================================================================ # Xcode 26.3.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 26.3 (25D125)` - Kernel version `Darwin 25.3.0` - Disk `294GB (Free Space: 143GB)` ## Xcode versions - 26.3 (17C529) `/Applications/Xcode-26.3.app` ### Runtimes and Devices {{< collapsible title="iOS 26.1" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M4) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone Air {{< /collapsible >}} {{< collapsible title="iOS 26.2" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 26.2" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 26.2" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 26.2" >}} - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2025.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 build-tools;36.1.0 | 36.1.0 | Android SDK Build-Tools 36.1 | build-tools/36.1.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.31.6 | 3.31.6 | CMake 3.31.6 | cmake/3.31.6 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.1.2 | 4.1.2 | CMake 4.1.2 | cmake/4.1.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 20.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;28.2.13676358 | 28.2.13676358 | NDK (Side by side) 28.2.13676358 | ndk/28.2.13676358 ndk;29.0.14206865 | 29.0.14206865 | NDK (Side by side) 29.0.14206865 | ndk/29.0.14206865 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 36.0.2 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36.1 | 1 | Android SDK Platform 36.1 | platforms/android-36.1 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36.1 | 1 | Sources for Android 36.1 | sources/android-36.1 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 28.2.13676358 | `/usr/local/share/android-sdk/ndk/28.2.13676358` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | | 29.0.14206865 | `/usr/local/share/android-sdk/ndk/29.0.14206865` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 25.0.2 | `/Library/Java/JavaVirtualMachines/zulu-25.jdk/Contents/Home` | | 21.0.10 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.18** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.30 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_482 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.33.30` - azure-cli `2.83.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `1.2.0` - fastlane `2.232.1` - firebase `15.8.0` - gem `4.0.6` - gh `2.87.3` - git `2.53.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `5.0.15` - ionic `7.2.1` - jq `1.8.1` - ktlint `1.8.0` - node `24.13.1` - npm `11.8.0` - python `3.12.7` - python3 `3.12.7` - ruby `4.0.1` - ssh `10.2p1` - sudo `1.9.17p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - xcbeautify `3.1.4` - yarn `4.9.2` - yq `4.52.4` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-26-2/ title: Xcode 26.2.x last_modified: 2026-04-26 ================================================================================ # Xcode 26.2.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 26.2 (25C56)` - Kernel version `Darwin 25.2.0` - Disk `294GB (Free Space: 147GB)` ## Xcode versions - 26.2 (17C52) `/Applications/Xcode-26.2.app` ### Runtimes and Devices {{< collapsible title="iOS 26.1" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M4) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone Air {{< /collapsible >}} {{< collapsible title="iOS 26.2" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 26.2" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 26.2" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 26.2" >}} - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2025.2` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 build-tools;36.1.0 | 36.1.0 | Android SDK Build-Tools 36.1 | build-tools/36.1.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.31.6 | 3.31.6 | CMake 3.31.6 | cmake/3.31.6 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.1.2 | 4.1.2 | CMake 4.1.2 | cmake/4.1.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 19.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;28.2.13676358 | 28.2.13676358 | NDK (Side by side) 28.2.13676358 | ndk/28.2.13676358 ndk;29.0.14206865 | 29.0.14206865 | NDK (Side by side) 29.0.14206865 | ndk/29.0.14206865 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 36.0.0 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36.1 | 1 | Android SDK Platform 36.1 | platforms/android-36.1 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36.1 | 1 | Sources for Android 36.1 | sources/android-36.1 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 28.2.13676358 | `/usr/local/share/android-sdk/ndk/28.2.13676358` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | | 29.0.14206865 | `/usr/local/share/android-sdk/ndk/29.0.14206865` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 25.0.1 | `/Library/Java/JavaVirtualMachines/zulu-25.jdk/Contents/Home` | | 21.0.9 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.17** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.29 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_472 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.32.16` - azure-cli `2.81.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `1.0.4` - fastlane `2.229.1` - firebase `15.0.0` - gem `4.0.1` - gh `2.83.2` - git `2.52.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `5.0.5` - ionic `7.2.1` - jq `1.8.1` - ktlint `1.8.0` - node `24.12.0` - npm `11.6.2` - python `3.12.7` - python3 `3.12.7` - ruby `3.4.7` - ssh `10.0p2` - sudo `1.9.17p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - yarn `4.9.2` - yq `4.50.1` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-26-1/ title: Xcode 26.1.x last_modified: 2026-04-08 ================================================================================ # Xcode 26.1.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 26.1 (25B78)` - Kernel version `Darwin 25.1.0` - Disk `294GB (Free Space: 150GB)` ## Xcode versions - 26.1.1 (17B100) `/Applications/Xcode-26.1.app`, also selected when specifying `26.1` in Xcode version settings ### Runtimes and Devices {{< collapsible title="iOS 26.0" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M4) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone Air {{< /collapsible >}} {{< collapsible title="iOS 26.1" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 11-inch (M5) - iPad Pro 13-inch (M4) - iPad Pro 13-inch (M5) - iPad mini (A17 Pro) - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 26.1" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 26.1" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 26.1" >}} - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2024.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.0.2 | 4.0.2 | CMake 4.0.2 | cmake/4.0.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 19.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest emulator | 35.5.10 | Android Emulator | emulator extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;29.0.13113456 | 29.0.13113456 rc1 | NDK (Side by side) 29.0.13113456 | ndk/29.0.13113456 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 35.0.2 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36 | 2 | Android SDK Platform 36 | platforms/android-36 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36 | 1 | Sources for Android 36 | sources/android-36 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 29.0.13113456 | `/usr/local/share/android-sdk/ndk/29.0.13113456` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 25.0.1 | `/Library/Java/JavaVirtualMachines/zulu-25.jdk/Contents/Home` | | 21.0.9 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.17** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.29 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_472 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.32.1` - azure-cli `2.80.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `1.0.1` - fastlane `2.228.0` - firebase `14.12.1` - gem `3.7.2` - gh `2.83.1` - git `2.52.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `5.0.2` - ionic `7.2.1` - jq `1.8.1` - ktlint `1.8.0` - node `24.11.0` - npm `11.6.1` - python `3.12.7` - python3 `3.12.7` - ruby `3.4.5` - ssh `10.0p2` - sudo `1.9.17p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - yarn `4.9.2` - yq `4.48.2` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-26-0/ title: Xcode 26.0.x last_modified: 2026-04-08 ================================================================================ # Xcode 26.0.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 15.7 (24G222)` - Kernel version `Darwin 24.6.0` - Disk `294GB (Free Space: 153GB)` ## Xcode versions - 26.0.1 (17A400) `/Applications/Xcode-26.0.app`, also selected when specifying `26` or `26.0` in Xcode version settings ### Runtimes and Devices {{< collapsible title="iOS 18.5" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 13-inch (M4) - iPad mini (A17 Pro) - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone 16e {{< /collapsible >}} {{< collapsible title="iOS 26.0" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 13-inch (M4) - iPad mini (A17 Pro) - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone 16e - iPhone 17 - iPhone 17 Pro - iPhone 17 Pro Max - iPhone Air {{< /collapsible >}} {{< collapsible title="tvOS 26.0" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 26.0" >}} - Apple Vision Pro 4K {{< /collapsible >}} {{< collapsible title="watchOS 26.0" >}} - Apple Watch SE (40mm) (2nd generation) - Apple Watch SE (44mm) (2nd generation) - Apple Watch SE 3 (40mm) - Apple Watch SE 3 (44mm) - Apple Watch Series 10 (42mm) - Apple Watch Series 10 (46mm) - Apple Watch Series 11 (42mm) - Apple Watch Series 11 (46mm) - Apple Watch Ultra 2 (49mm) - Apple Watch Ultra 3 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2024.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.0.2 | 4.0.2 | CMake 4.0.2 | cmake/4.0.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 19.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest emulator | 35.5.10 | Android Emulator | emulator extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;27.3.13750724 | 27.3.13750724 | NDK (Side by side) 27.3.13750724 | ndk/27.3.13750724 ndk;29.0.13113456 | 29.0.13113456 rc1 | NDK (Side by side) 29.0.13113456 | ndk/29.0.13113456 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 35.0.2 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36 | 2 | Android SDK Platform 36 | platforms/android-36 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36 | 1 | Sources for Android 36 | sources/android-36 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 29.0.13113456 | `/usr/local/share/android-sdk/ndk/29.0.13113456` | | 27.3.13750724 | `/usr/local/share/android-sdk/ndk/27.3.13750724` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 25 | `/Library/Java/JavaVirtualMachines/zulu-25.jdk/Contents/Home` | | 21.0.8 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.16** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.28 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_462 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.31.3` - azure-cli `2.77.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `0.12.5` - fastlane `2.228.0` - firebase `14.12.1` - gem `3.7.2` - gh `2.80.0` - git `2.51.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `4.6.14` - ionic `7.2.1` - jq `1.8.1` - ktlint `1.7.1` - node `24.7.0` - npm `11.5.1` - python `3.12.7` - python3 `3.12.7` - ruby `3.4.5` - ssh `9.9p2` - sudo `1.9.13p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - yarn `4.9.2` - yq `4.47.2` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-16-4/ title: Xcode 16.4.x last_modified: 2026-04-08 ================================================================================ # Xcode 16.4.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 15.5 (24F74)` - Kernel version `Darwin 24.5.0` - Disk `294GB (Free Space: 156GB)` ## Xcode versions - 16.4 (16F6) `/Applications/Xcode-16.4.app` ### Runtimes and Devices {{< collapsible title="iOS 17.5" >}} - iPad (10th generation) - iPad Air (5th generation) - iPad Pro (11-inch) (4th generation) - iPad Pro (12.9-inch) (6th generation) - iPad mini (6th generation) - iPhone 14 - iPhone 14 Plus - iPhone 14 Pro - iPhone 14 Pro Max - iPhone 15 - iPhone 15 Plus - iPhone 15 Pro - iPhone 15 Pro Max - iPhone SE (3rd generation) {{< /collapsible >}} {{< collapsible title="iOS 18.5" >}} - iPad (A16) - iPad Air 11-inch (M3) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 13-inch (M4) - iPad mini (A17 Pro) - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone 16e {{< /collapsible >}} {{< collapsible title="tvOS 18.5" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 2.5" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 11.5" >}} - Apple Watch SE (40mm) (2nd generation) - Apple Watch SE (44mm) (2nd generation) - Apple Watch Series 10 (42mm) - Apple Watch Series 10 (46mm) - Apple Watch Ultra 2 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2024.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 build-tools;36.0.0 | 36.0.0 | Android SDK Build-Tools 36 | build-tools/36.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmake;4.0.2 | 4.0.2 | CMake 4.0.2 | cmake/4.0.2 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 19.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest emulator | 35.5.10 | Android Emulator | emulator extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 ndk;29.0.13113456 | 29.0.13113456 rc1 | NDK (Side by side) 29.0.13113456 | ndk/29.0.13113456 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 35.0.2 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-34 | 3 | Android SDK Platform 34 | platforms/android-34 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-36 | 2 | Android SDK Platform 36 | platforms/android-36 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-34 | 2 | Sources for Android 34 | sources/android-34 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 sources;android-36 | 1 | Sources for Android 36 | sources/android-36 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 29.0.13113456 | `/usr/local/share/android-sdk/ndk/29.0.13113456` | | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 24.0.1 | `/Library/Java/JavaVirtualMachines/zulu-24.jdk/Contents/Home` | | 21.0.7 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.15** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.27 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_452 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.14.1 | `/Users/builder/programs/gradle-8.14.1` | ## Other pre-installed tools - appium `2.19.0` - aws `2.27.37` - azure-cli `2.74.0` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `0.12.4` - fastlane `2.228.0` - firebase `11.21.0` - gem `3.6.9` - gh `2.74.1` - git `2.50.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `4.5.7` - ionic `7.2.1` - jq `1.8.0` - ktlint `1.6.0` - node `22.16.0` - npm `10.9.2` - python `3.12.7` - python3 `3.12.7` - ruby `3.3.6` - ssh `9.9p2` - sudo `1.9.13p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - yarn `4.9.2` - yq `4.45.4` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-16-3/ title: Xcode 16.3.x last_modified: 2026-04-08 ================================================================================ # Xcode 16.3.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 15.4 (24E248)` - Kernel version `Darwin 24.4.0` - Disk `294GB (Free Space: 156GB)` ## Xcode versions - 16.3 (16E140) `/Applications/Xcode-16.3.app` ### Runtimes and Devices {{< collapsible title="iOS 18.4" >}} - iPad (10th generation) - iPad (A16) - iPad Air 11-inch (M2) - iPad Air 11-inch (M3) - iPad Air 13-inch (M2) - iPad Air 13-inch (M3) - iPad Pro 11-inch (M4) - iPad Pro 13-inch (M4) - iPad mini (A17 Pro) - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone 16e {{< /collapsible >}} {{< collapsible title="tvOS 18.4" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 2.4" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 11.4" >}} - Apple Watch SE (40mm) (2nd generation) - Apple Watch SE (44mm) (2nd generation) - Apple Watch Series 10 (42mm) - Apple Watch Series 10 (46mm) - Apple Watch Ultra 2 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2024.2` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 build-tools;35.0.1 | 35.0.1 | Android SDK Build-Tools 35.0.1 | build-tools/35.0.1 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 19.0.0 rc1 | Android SDK Command-line Tools (latest) | cmdline-tools/latest emulator | 35.3.12 | Android Emulator | emulator extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 35.0.2 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 3 | Android SDK Platform 33 | platforms/android-33 platforms;android-35 | 2 | Android SDK Platform 35 | platforms/android-35 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 sources;android-35 | 1 | Sources for Android 35 | sources/android-35 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 24 | `/Library/Java/JavaVirtualMachines/zulu-24.jdk/Contents/Home` | | 21.0.6 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.14** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.26 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_442 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.1.1 | `/Users/builder/programs/gradle-8.1.1` | | 7.6 | `/Users/builder/programs/gradle-7.6` | | 7.3.1 | `/Users/builder/programs/gradle-7.3.1` | ## Other pre-installed tools - appium `2.5.0` - aws `2.25.8` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `0.12.3` - fastlane `2.227.0` - firebase `11.21.0` - gem `3.6.6` - gh `2.69.0` - git `2.49.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `4.4.27` - ionic `7.2.0` - jq `1.7.1` - ktlint `1.5.0` - node `22.9.0` - npm `10.8.3` - python `3.12.7` - python3 `3.12.7` - ruby `3.3.6` - ssh `9.9p1` - sudo `1.9.13p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.25.0` - yarn `1.22.22` - yq `4.45.1` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-16-2/ title: Xcode 16.2.x last_modified: 2026-04-08 ================================================================================ # Xcode 16.2.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` - Mac mini M4 `10-Core CPU / 16GB` > > Mac Studio M4 Max available on request. > ## System - System version `macOS 15.2 (24C101)` - Kernel version `Darwin 24.2.0` - Disk `294GB (Free Space: 151GB)` - Disk `294GB (Free Space: 150GB)` ## Xcode versions - 16.2 (16C5032a) `/Applications/Xcode-16.2.app` ### Runtimes and Devices {{< collapsible title="iOS 18.2" >}} - iPad (10th generation) - iPad Air 11-inch (M2) - iPad Air 13-inch (M2) - iPad Pro 11-inch (M4) - iPad Pro 13-inch (M4) - iPad mini (A17 Pro) - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone SE (3rd generation) {{< /collapsible >}} {{< collapsible title="tvOS 18.2" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 2.2" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 11.2" >}} - Apple Watch SE (40mm) (2nd generation) - Apple Watch SE (44mm) (2nd generation) - Apple Watch Series 10 (42mm) - Apple Watch Series 10 (46mm) - Apple Watch Ultra 2 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2021.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 8.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 33.0.3 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 2 | Android SDK Platform 33 | platforms/android-33 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 23.0.1 | `/Library/Java/JavaVirtualMachines/zulu-23.jdk/Contents/Home` | | 21.0.5 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.13** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.25 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_432 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.1.1 | `/Users/builder/programs/gradle-8.1.1` | | 7.6 | `/Users/builder/programs/gradle-7.6` | | 7.3.1 | `/Users/builder/programs/gradle-7.3.1` | ## Other pre-installed tools - appium `2.5.0` - aws `2.22.15` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `0.12.3` - fastlane `2.225.0` - firebase `11.21.0` - gem `3.5.23` - gh `2.60.1` - git `2.47.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `4.4.11` - ionic `7.2.0` - jq `1.7.1` - ktlint `1.5.0` - node `22.9.0` - npm `10.8.3` - python `3.12.7` - python3 `3.12.7` - ruby `3.3.6` - ssh `9.8p1` - sudo `1.9.13p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.24.5` - yarn `1.22.22` - yq `4.44.3` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-16-1/ title: Xcode 16.1.x last_modified: 2026-04-08 ================================================================================ # Xcode 16.1.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` > > Mac mini M4 and Mac Studio M4 Max available on request. > ## System - System version `macOS 15.1.1 (24B91)` - Kernel version `Darwin 24.1.0` - Disk `294GB (Free Space: 151GB)` ## Xcode versions - 16.1 (16B40) `/Applications/Xcode-16.1.app` ### Runtimes and Devices {{< collapsible title="iOS 18.1" >}} - iPad (10th generation) - iPad Air 11-inch (M2) - iPad Air 13-inch (M2) - iPad Pro 11-inch (M4) - iPad Pro 13-inch (M4) - iPad mini (6th generation) - iPad mini (A17 Pro) - iPhone 15 - iPhone 15 Plus - iPhone 15 Pro - iPhone 15 Pro Max - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone SE (3rd generation) {{< /collapsible >}} {{< collapsible title="tvOS 18.1" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 2.1" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 11.1" >}} - Apple Watch SE (40mm) (2nd generation) - Apple Watch SE (44mm) (2nd generation) - Apple Watch Series 10 (42mm) - Apple Watch Series 10 (46mm) - Apple Watch Ultra 2 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2021.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Loading package information... Loading local repository... [========= ] 25% Loading local repository... [========= ] 25% Fetch remote repository... [=======================================] 100% Fetch remote repository... Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 8.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 33.0.3 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 2 | Android SDK Platform 33 | platforms/android-33 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 23 | `/Library/Java/JavaVirtualMachines/zulu-23.jdk/Contents/Home` | | 21.0.4 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.12** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.24 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_422 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.1.1 | `/Users/builder/programs/gradle-8.1.1` | | 7.6 | `/Users/builder/programs/gradle-7.6` | | 7.3.1 | `/Users/builder/programs/gradle-7.3.1` | ## Other pre-installed tools - appium `2.5.0` - aws `2.18.1` - carthage `0.40.0` - cocoapods `1.16.2` - cordova `12.0.0` - curl `8.7.1` - ew-cli `0.12.3` - fastlane `2.225.0` - firebase `11.21.0` - gem `3.5.22` - gh `2.58.0` - git `2.47.0` - Google Cloud SDK `502.0.0` - gsutil `5.31` - homebrew `4.4.6` - ionic `7.2.0` - jq `1.7.1` - ktlint `1.3.1` - node `22.9.0` - npm `10.8.3` - python `3.12.7` - python3 `3.12.7` - ruby `3.3.6` - ssh `9.8p1` - sudo `1.9.13p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.24.5` - yarn `1.22.22` - yq `4.44.3` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/specs-macos/xcode-16-0/ title: Xcode 16.0.x last_modified: 2026-04-08 ================================================================================ # Xcode 16.0.x Codemagic offers multiple build machines with different specifications and pre-installed tools. You can choose between them by specifying the required Xcode version. ## Hardware - Mac mini M2 `8-Core CPU / 12GB` > > Mac mini M4 and Mac Studio M4 Max available on request. > ## System - System version `macOS 14.7 (23H124)` - Kernel version `Darwin 23.6.0` - Disk `294GB (Free Space: 141GB)` ## Xcode versions - 16.0 (16A242d) `/Applications/Xcode-16.0.app`, also selected when specifying `16` in Xcode version settings ### Runtimes and Devices {{< collapsible title="iOS 18.0" >}} - iPad (10th generation) - iPad Air 11-inch (M2) - iPad Air 13-inch (M2) - iPad Pro 11-inch (M4) - iPad Pro 13-inch (M4) - iPad mini (6th generation) - iPhone 15 - iPhone 15 Plus - iPhone 15 Pro - iPhone 15 Pro Max - iPhone 16 - iPhone 16 Plus - iPhone 16 Pro - iPhone 16 Pro Max - iPhone SE (3rd generation) {{< /collapsible >}} {{< collapsible title="tvOS 18.0" >}} - Apple TV - Apple TV 4K (3rd generation) - Apple TV 4K (3rd generation) (at 1080p) {{< /collapsible >}} {{< collapsible title="visionOS 2.0" >}} - Apple Vision Pro {{< /collapsible >}} {{< collapsible title="watchOS 11.0" >}} - Apple Watch SE (40mm) (2nd generation) - Apple Watch SE (44mm) (2nd generation) - Apple Watch Series 10 (42mm) - Apple Watch Series 10 (46mm) - Apple Watch Series 9 (41mm) - Apple Watch Series 9 (45mm) - Apple Watch Ultra 2 (49mm) {{< /collapsible >}} ## Android Studio > Android Studio `2021.3` installed at `~/programs/android-studio` ## Android SDK > SDK Manager at `/usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager` {{< collapsible title="Installed SDK packages" >}} ``` $ /usr/local/share/android-sdk/cmdline-tools/latest/bin/sdkmanager --list_installed ``` Installed packages: Path | Version | Description | Location ------- | ------- | ------- | ------- add-ons;addon-google_apis-google-19 | 20 | Google APIs | add-ons/addon-google_apis-google-19 add-ons;addon-google_apis-google-21 | 1 | Google APIs | add-ons/addon-google_apis-google-21 add-ons;addon-google_apis-google-22 | 1 | Google APIs | add-ons/addon-google_apis-google-22 add-ons;addon-google_apis-google-23 | 1 | Google APIs | add-ons/addon-google_apis-google-23 add-ons;addon-google_apis-google-24 | 1 | Google APIs | add-ons/addon-google_apis-google-24 build-tools;19.1.0 | 19.1.0 | Android SDK Build-Tools 19.1 | build-tools/19.1.0 build-tools;20.0.0 | 20.0.0 | Android SDK Build-Tools 20 | build-tools/20.0.0 build-tools;21.1.2 | 21.1.2 | Android SDK Build-Tools 21.1.2 | build-tools/21.1.2 build-tools;22.0.1 | 22.0.1 | Android SDK Build-Tools 22.0.1 | build-tools/22.0.1 build-tools;23.0.1 | 23.0.1 | Android SDK Build-Tools 23.0.1 | build-tools/23.0.1 build-tools;23.0.2 | 23.0.2 | Android SDK Build-Tools 23.0.2 | build-tools/23.0.2 build-tools;23.0.3 | 23.0.3 | Android SDK Build-Tools 23.0.3 | build-tools/23.0.3 build-tools;24.0.0 | 24.0.0 | Android SDK Build-Tools 24 | build-tools/24.0.0 build-tools;24.0.1 | 24.0.1 | Android SDK Build-Tools 24.0.1 | build-tools/24.0.1 build-tools;24.0.2 | 24.0.2 | Android SDK Build-Tools 24.0.2 | build-tools/24.0.2 build-tools;24.0.3 | 24.0.3 | Android SDK Build-Tools 24.0.3 | build-tools/24.0.3 build-tools;25.0.0 | 25.0.0 | Android SDK Build-Tools 25 | build-tools/25.0.0 build-tools;25.0.1 | 25.0.1 | Android SDK Build-Tools 25.0.1 | build-tools/25.0.1 build-tools;25.0.2 | 25.0.2 | Android SDK Build-Tools 25.0.2 | build-tools/25.0.2 build-tools;25.0.3 | 25.0.3 | Android SDK Build-Tools 25.0.3 | build-tools/25.0.3 build-tools;26.0.0 | 26.0.0 | Android SDK Build-Tools 26 | build-tools/26.0.0 build-tools;26.0.1 | 26.0.1 | Android SDK Build-Tools 26.0.1 | build-tools/26.0.1 build-tools;26.0.2 | 26.0.2 | Android SDK Build-Tools 26.0.2 | build-tools/26.0.2 build-tools;26.0.3 | 26.0.3 | Android SDK Build-Tools 26.0.3 | build-tools/26.0.3 build-tools;27.0.0 | 27.0.0 | Android SDK Build-Tools 27 | build-tools/27.0.0 build-tools;27.0.1 | 27.0.1 | Android SDK Build-Tools 27.0.1 | build-tools/27.0.1 build-tools;27.0.2 | 27.0.2 | Android SDK Build-Tools 27.0.2 | build-tools/27.0.2 build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools/27.0.3 build-tools;28.0.0 | 28.0.0 | Android SDK Build-Tools 28 | build-tools/28.0.0 build-tools;28.0.1 | 28.0.1 | Android SDK Build-Tools 28.0.1 | build-tools/28.0.1 build-tools;28.0.2 | 28.0.2 | Android SDK Build-Tools 28.0.2 | build-tools/28.0.2 build-tools;28.0.3 | 28.0.3 | Android SDK Build-Tools 28.0.3 | build-tools/28.0.3 build-tools;29.0.0 | 29.0.0 | Android SDK Build-Tools 29 | build-tools/29.0.0 build-tools;29.0.1 | 29.0.1 | Android SDK Build-Tools 29.0.1 | build-tools/29.0.1 build-tools;29.0.2 | 29.0.2 | Android SDK Build-Tools 29.0.2 | build-tools/29.0.2 build-tools;29.0.3 | 29.0.3 | Android SDK Build-Tools 29.0.3 | build-tools/29.0.3 build-tools;30.0.0 | 30.0.0 | Android SDK Build-Tools 30 | build-tools/30.0.0 build-tools;30.0.1 | 30.0.1 | Android SDK Build-Tools 30.0.1 | build-tools/30.0.1 build-tools;30.0.2 | 30.0.2 | Android SDK Build-Tools 30.0.2 | build-tools/30.0.2 build-tools;30.0.3 | 30.0.3 | Android SDK Build-Tools 30.0.3 | build-tools/30.0.3 build-tools;31.0.0 | 31.0.0 | Android SDK Build-Tools 31 | build-tools/31.0.0 build-tools;32.0.0 | 32.0.0 | Android SDK Build-Tools 32 | build-tools/32.0.0 build-tools;32.1.0-rc1 | 32.1.0 rc1 | Android SDK Build-Tools 32.1-rc1 | build-tools/32.1.0-rc1 build-tools;33.0.0 | 33.0.0 | Android SDK Build-Tools 33 | build-tools/33.0.0 cmake;3.10.2.4988404 | 3.10.2 | CMake 3.10.2.4988404 | cmake/3.10.2.4988404 cmake;3.18.1 | 3.18.1 | CMake 3.18.1 | cmake/3.18.1 cmake;3.22.1 | 3.22.1 | CMake 3.22.1 | cmake/3.22.1 cmake;3.6.4111459 | 3.6.4111459 | CMake 3.6.4111459 | cmake/3.6.4111459 cmdline-tools;1.0 | 1.0 | Android SDK Command-line Tools | cmdline-tools/1.0 cmdline-tools;2.1 | 2.1 | Android SDK Command-line Tools | cmdline-tools/2.1 cmdline-tools;3.0 | 3.0 | Android SDK Command-line Tools | cmdline-tools/3.0 cmdline-tools;4.0 | 4.0 | Android SDK Command-line Tools | cmdline-tools/4.0 cmdline-tools;5.0 | 5.0 | Android SDK Command-line Tools | cmdline-tools/5.0 cmdline-tools;6.0 | 6.0 | Android SDK Command-line Tools | cmdline-tools/6.0 cmdline-tools;7.0 | 7.0 | Android SDK Command-line Tools | cmdline-tools/7.0 cmdline-tools;latest | 8.0 | Android SDK Command-line Tools (latest) | cmdline-tools/latest extras;google;google_play_services | 49 | Google Play services | extras/google/google_play_services extras;google;instantapps | 1.9.0 | Google Play Instant Development SDK | extras/google/instantapps extras;google;market_apk_expansion | 1 | Google Play APK Expansion library | extras/google/market_apk_expansion extras;google;market_licensing | 1 | Google Play Licensing Library | extras/google/market_licensing extras;google;webdriver | 2 | Google Web Driver | extras/google/webdriver ndk;25.1.8937393 | 25.1.8937393 | NDK (Side by side) 25.1.8937393 | ndk/25.1.8937393 patcher;v4 | 1 | SDK Patch Applier v4 | patcher/v4 platform-tools | 33.0.3 | Android SDK Platform-Tools | platform-tools platforms;android-19 | 4 | Android SDK Platform 19 | platforms/android-19 platforms;android-20 | 2 | Android SDK Platform 20 | platforms/android-20 platforms;android-21 | 2 | Android SDK Platform 21 | platforms/android-21 platforms;android-22 | 2 | Android SDK Platform 22 | platforms/android-22 platforms;android-23 | 3 | Android SDK Platform 23 | platforms/android-23 platforms;android-24 | 2 | Android SDK Platform 24 | platforms/android-24 platforms;android-25 | 3 | Android SDK Platform 25 | platforms/android-25 platforms;android-26 | 2 | Android SDK Platform 26 | platforms/android-26 platforms;android-27 | 3 | Android SDK Platform 27 | platforms/android-27 platforms;android-28 | 6 | Android SDK Platform 28 | platforms/android-28 platforms;android-29 | 5 | Android SDK Platform 29 | platforms/android-29 platforms;android-30 | 3 | Android SDK Platform 30 | platforms/android-30 platforms;android-31 | 1 | Android SDK Platform 31 | platforms/android-31 platforms;android-32 | 1 | Android SDK Platform 32 | platforms/android-32 platforms;android-33 | 2 | Android SDK Platform 33 | platforms/android-33 platforms;android-TiramisuPrivacySandbox | 8 | Android SDK Platform TiramisuPrivacySandbox | platforms/android-TiramisuPrivacySandbox sources;android-19 | 2 | Sources for Android 19 | sources/android-19 sources;android-20 | 1 | Sources for Android 20 | sources/android-20 sources;android-21 | 1 | Sources for Android 21 | sources/android-21 sources;android-22 | 1 | Sources for Android 22 | sources/android-22 sources;android-23 | 1 | Sources for Android 23 | sources/android-23 sources;android-24 | 1 | Sources for Android 24 | sources/android-24 sources;android-25 | 1 | Sources for Android 25 | sources/android-25 sources;android-26 | 1 | Sources for Android 26 | sources/android-26 sources;android-27 | 1 | Sources for Android 27 | sources/android-27 sources;android-28 | 1 | Sources for Android 28 | sources/android-28 sources;android-29 | 1 | Sources for Android 29 | sources/android-29 sources;android-30 | 1 | Sources for Android 30 | sources/android-30 sources;android-31 | 1 | Sources for Android 31 | sources/android-31 sources;android-32 | 1 | Sources for Android 32 | sources/android-32 {{< /collapsible >}} ## Android NDK | **Version** | **Path** | |---------|------| | 25.1.8937393 | `/usr/local/share/android-sdk/ndk/25.1.8937393` | ## Android emulators Android emulators are unavailable on Apple silicon machines due to the Apple Virtualization Framework not supporting nested virtualization. Please use a Linux instance. ## Java versions | **Version** | **Path** | |-------------|----------| | 22.0.1 | `/Library/Java/JavaVirtualMachines/zulu-22.jdk/Contents/Home` | | 21.0.3 | `/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home` | | **17.0.11** (default) | `/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home` | | 11.0.23 | `/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home` | | 1.8.0_412 | `/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home` | | 1.7.0_352 | `/Library/Java/JavaVirtualMachines/zulu-7.jdk/Contents/Home` | ## Gradle versions | **Version** | **Path** | |---------|------| | 8.1.1 | `/Users/builder/programs/gradle-8.1.1` | | 7.6 | `/Users/builder/programs/gradle-7.6` | | 7.3.1 | `/Users/builder/programs/gradle-7.3.1` | ## Other pre-installed tools - appium `2.5.0` - aws `2.15.38` - carthage `0.39.1` - cocoapods `1.16.1` - cordova `12.0.0` - curl `8.7.1` - ew-cli `0.12.3` - fastlane `2.225.0` - firebase `11.21.0` - gem `3.5.22` - gh `2.48.0` - git `2.44.0` - Google Cloud SDK `404.0.0` - gsutil `5.14` - homebrew `4.2.18` - ionic `7.2.0` - jq `1.7.1` - ktlint `1.2.1` - node `20.12.2` - npm `10.5.0` - python `3.8.13` - python3 `3.8.13` - ruby `3.0.4p208` - ssh `9.7p1` - sudo `1.9.13p2` - swiftgen `6.6.3` - tar `3.5.3` - ucd `0.11.10` - unzip `6.00` - wget `1.24.5` - yarn `1.22.22` - yq `4.43.1` - zip `3.0` ================================================================================ source: https://docs.codemagic.io/yaml-quick-start/first-signed-build/ title: First Release Pipeline description: Build, sign, and distribute a mobile app with Codemagic—internal testing through App Store and Play store release last_modified: 2026-04-01 ================================================================================ # First Release Pipeline > Build, sign, and distribute a mobile app with Codemagic—internal testing through App Store and Play store release Codemagic is a cloud-based CI/CD service for building, signing, and distributing mobile apps. This quick start uses **tabs** so you can follow **Flutter**, **React Native**, **native iOS**, or **native Android**. The flow is the same in five steps: 1. **[Unsigned build](#step-1-a-basic-unsigned-build)** — Run a workflow without signing to confirm the project compiles in CI. 2. **[Signing credentials](#step-2-preparing-for-signing)** — Create or gather Apple and Android signing inputs, then upload them in Codemagic. 3. **[Signed build](#step-3-sign-your-build)** — Add signing to YAML and produce signed **`.ipa`**, **`.aab`**, or **`.apk`** files. 4. **[Internal distribution](#step-4-distribute-to-internal-testers)** — Publish to **TestFlight** (internal testers) and Google Play **internal** testing. 5. **[Store release](#step-5-publish-to-the-stores)** — Use **separate workflows** to submit to the **App Store** and **Google Play** production. You do not need to modify your Xcode or Gradle project to run unsigned builds. Signing requires adding credentials, but does not require restructuring your project. [Step 4](#step-4-distribute-to-internal-testers) and [Step 5](#step-5-publish-to-the-stores) are optional publishing paths. After that, [Next steps: from signed build to full CI/CD](#next-steps-from-signed-build-to-full-cicd) lists what most teams add next; [Further capabilities](#further-capabilities-and-next-steps) links stack guides and reference. ## Connect your repo or use a sample repository To connect your repo, authorize the relevant connection then choose the repo you want to use. To try Codemagic without wiring your own app first, clone one of these sample projects: - **Flutter** — [flutter-android-and-ios-yaml-demo-project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/flutter/flutter-android-and-ios-yaml-demo-project) - **React Native** — [react-native-demo-project](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/react-native/react-native-demo-project) - **Native iOS** — [ios-native-quick-start](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/ios/ios-native-quick-start) - **Native Android** — [android-native-quick-start](https://github.com/codemagic-ci-cd/codemagic-sample-projects/tree/main/android/android-native-quick-start) More samples are listed on [Codemagic sample projects](codemagic-sample-projects). ## Step 1: A basic unsigned build Put **`codemagic.yaml` at the repository root**, commit it, open **your stack’s tab**, copy the **unsigned** workflow, and replace **placeholders** (workspace, scheme, package name, and so on) for your app. Each workflow lives under the top-level **`workflows:`** key. The examples below start with **`environment`**, **`scripts`**, and **`artifacts`**; add **`publishing:`** in **Steps 4–5** when you distribute builds (**Step 5** normally uses **extra** workflow entries—see there). ```yaml workflows: my-workflow: name: My workflow name instance_type: mac_mini_m2 max_build_duration: 60 environment: # variables, groups, tool versions, signing references triggering: # branches, PRs, tags, webhooks scripts: # build and test steps artifacts: # files to keep from the build publishing: # distribution and notifications cache: # dependency caches ``` These iOS examples use **`xcode: latest`**, and [the corresponding environment](../specs-macos/xcode-26-2) . Pin a specific **major.minor** version only if your project requires it. ### Option: Flutter Two workflows: **debug iOS** without code signing (`--no-codesign`), and **debug Android APK**. ```yaml workflows: flutter-ios-unsigned: name: Flutter iOS (unsigned debug) max_build_duration: 120 instance_type: mac_mini_m2 environment: flutter: stable xcode: latest cocoapods: default scripts: - name: Get Flutter packages script: flutter pub get - name: Install CocoaPods dependencies script: find . -name "Podfile" -execdir pod install \; - name: Build iOS debug without code signing script: flutter build ios --debug --no-codesign artifacts: - build/ios/iphoneos/**/*.app - /tmp/xcodebuild_logs/*.log flutter-android-debug: name: Flutter Android (debug APK) max_build_duration: 120 instance_type: mac_mini_m2 environment: flutter: stable scripts: - name: Set up local.properties script: echo "flutter.sdk=$HOME/programs/flutter" > "$CM_BUILD_DIR/android/local.properties" - name: Get Flutter packages script: flutter pub get - name: Build Android debug APK script: flutter build apk --debug artifacts: - build/app/outputs/flutter-apk/*.apk ``` ### Option: React Native Two workflows: **Android `assembleDebug`** and **unsigned iOS** via `xcodebuild` with `CODE_SIGNING_ALLOWED=NO`. Adjust `XCODE_WORKSPACE`, `XCODE_SCHEME`, and Node version to match your project. ```yaml workflows: rn-android-debug: name: React Native Android (debug) max_build_duration: 120 instance_type: mac_mini_m2 environment: node: v22.11.0 scripts: - name: Install npm dependencies script: npm ci - name: Set Android SDK location script: echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/android/local.properties" - name: Build Android debug script: | cd android ./gradlew assembleDebug artifacts: - android/app/build/outputs/**/*.apk rn-ios-unsigned: name: React Native iOS (unsigned debug) max_build_duration: 120 instance_type: mac_mini_m2 environment: node: v22.11.0 xcode: latest cocoapods: default vars: XCODE_WORKSPACE: "YourApp.xcworkspace" XCODE_SCHEME: "YourApp" scripts: - name: Install npm dependencies script: npm ci - name: Install CocoaPods dependencies script: | cd ios && pod install - name: Build iOS without code signing script: | xcodebuild \ -workspace "$CM_BUILD_DIR/ios/$XCODE_WORKSPACE" \ -scheme "$XCODE_SCHEME" \ -configuration Debug \ -destination 'generic/platform=iOS' \ CODE_SIGNING_ALLOWED=NO \ build artifacts: - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - /tmp/xcodebuild_logs/*.log ``` {{< collapsible title="Using Expo without prebuild ### Option: iOS (native) Assumes the **Xcode workspace** lives at the **repository root** (as in [iOS native apps](building-a-native-ios-app)). If your workspace is only under `ios/`, use `cd ios && pod install` and point `-workspace` to `$CM_BUILD_DIR/ios/YourApp.xcworkspace`. ```yaml workflows: ios-native-unsigned: name: Native iOS (unsigned debug) max_build_duration: 120 instance_type: mac_mini_m2 environment: xcode: latest cocoapods: default vars: XCODE_WORKSPACE: "YourApp.xcworkspace" XCODE_SCHEME: "YourApp" scripts: - name: Install CocoaPods dependencies script: pod install - name: Build iOS without code signing script: | xcodebuild \ -workspace "$CM_BUILD_DIR/$XCODE_WORKSPACE" \ -scheme "$XCODE_SCHEME" \ -configuration Debug \ -destination 'generic/platform=iOS' \ CODE_SIGNING_ALLOWED=NO \ build artifacts: - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app - /tmp/xcodebuild_logs/*.log ``` > > If you use a **.xcodeproj** only, swap `-workspace` for `-project YourApp.xcodeproj` in the `xcodebuild` command (same pattern as [iOS native apps](building-a-native-ios-app)). > ### Option: Android (native) Assumes the **Gradle project** is at the **repository root** (as in [Android native apps](building-a-native-android-app)). If the project is in a subfolder, run Gradle from that directory and adjust `local.properties` paths. ```yaml workflows: android-native-debug: name: Native Android (debug) max_build_duration: 120 instance_type: mac_mini_m2 scripts: - name: Set Android SDK location script: echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/local.properties" - name: Build Android debug script: ./gradlew assembleDebug artifacts: - app/build/outputs/**/*.apk ``` Commit `codemagic.yaml` to your repository and push. In [Codemagic](https://codemagic.io/apps), click on `Start new build` to run it. If an unsigned workflow finishes successfully, your Codemagic setup is working and you can move on to **signing**. If a build fails, typical causes are YAML at the wrong path, **`local.properties`** next to the wrong **`build.gradle`**, or iOS **workspace/scheme/paths**—see [Common issues](../troubleshooting/common-issues), [Common iOS issues](../troubleshooting/common-ios-issues), and [Common Android issues](../troubleshooting/common-android-issues). ## Step 2: Preparing for signing Add the credentials for App Store or Google Play. The **iOS** and **Android** tabs below describe what to upload; Flutter and React Native use the **same** Apple and Android files as native apps when your bundle ID and application ID match. Details and troubleshooting: [Signing iOS apps](../yaml-code-signing/signing-ios), [Signing Android apps](../yaml-code-signing/signing-android); walkthroughs: [iOS native](building-a-native-ios-app#code-signing), [Android native](building-a-native-android-app#code-signing). Set this up **once per platform** (iOS and/or Android). You will reference the same uploaded files from **your** signed workflow in the next section, regardless of framework. ### Option: iOS **Requirements:** Active [Apple Developer Program](https://developer.apple.com/programs/enroll/) membership. 1. **App Store Connect API key** — Create in [App Store Connect](https://appstoreconnect.apple.com/access/integrations/api) under **Users and Access → Integrations → App Store Connect API**; download the **`.p8`** (once). Note **Issuer ID** and **Key ID**. Upload in Codemagic under **Team integrations → Developer Portal → Manage keys**. 2. **Signing files for your bundle ID** — **Apple Distribution** certificate (e.g. `.p12`) and an **App Store** provisioning profile (`.mobileprovision`). Add them under **Team settings → codemagic.yaml settings → Code signing identities** (**iOS certificates** / **iOS provisioning profiles**), or use **Fetch** after the API key is saved. **Minimal signing block in `codemagic.yaml`** (use your key name and bundle ID). Run **`xcode-project use-profiles`** in `scripts` **before** the IPA build step (see **your** stack’s signed YAML in **Step 3** below). ```yaml integrations: app_store_connect: YOUR_API_KEY_NAME environment: ios_signing: distribution_type: app_store bundle_identifier: com.example.app ``` **Expected artifact:** signed **`.ipa`** (artifact paths match **your** tab’s signed example below). **More:** [Signing iOS apps](../yaml-code-signing/signing-ios). ### Option: Android 1. **Release keystore** — Generate locally with **Java keytool**, or use an existing upload key: ```Shell keytool -genkey -v -keystore codemagic.keystore -storetype JKS \ -keyalg RSA -keysize 2048 -validity 10000 -alias codemagic ``` 2. **Upload** the keystore under **Team settings → codemagic.yaml settings → Code signing identities → Android keystores**. Set keystore password, key alias, key password, and a **reference name** you will use in YAML. 3. **`android_signing` in `codemagic.yaml`** — Codemagic injects the keystore on the build machine and sets **`CM_KEYSTORE_PATH`**, **`CM_KEYSTORE_PASSWORD`**, **`CM_KEY_ALIAS`**, and **`CM_KEY_PASSWORD`**: ```yaml environment: android_signing: - your_keystore_reference_name ``` 4. **Gradle release signing (required)** — Uploading the keystore and listing `android_signing` is not enough: **`release` must use those variables** or you still get **unsigned** release outputs. Add a `signingConfigs.release` block in **`android/app/build.gradle`** (Groovy) that reads the `CM_*` env vars when Codemagic sets **`CI=true`**, and point **`buildTypes.release`** at it: ```Groovy android { // ... signingConfigs { release { if (System.getenv()["CI"]) { 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"] } } } buildTypes { release { signingConfig signingConfigs.release } } } ``` For a complete **`android { }`** example with an **`else`** branch (so local **`./gradlew assembleRelease`** still works via `key.properties`), see [Signing Android apps using Gradle](../yaml-code-signing/signing-android#signing-android-apps-using-gradle). Kotlin DSL (**`.kts`**) projects need the same wiring in **`build.gradle.kts`** — see [Signing Android apps](../yaml-code-signing/signing-android). **Expected artifact:** **`.aab`** or **`.apk`** from `./gradlew bundleRelease` / `assembleRelease` (see **your** tab’s signed example below). **More:** [Signing Android apps](../yaml-code-signing/signing-android). ## Step 3: Sign your build Use the workflow in **your stack’s tab** after the identities above exist in **Team settings** → **Code signing identities** (and your **App Store Connect** integration key is saved under **Team integrations** when you build iOS). Replace placeholders such as ``, `keystore_reference`, `PACKAGE_NAME`, `bundle_identifier`, workspace, and scheme names. ### Option: Flutter Two workflows: **Android** (signed **AAB**) and **iOS** (signed **IPA**). Each needs the matching credentials from **Step 2** above. For more Flutter options, see [Flutter apps](building-a-flutter-app). ```yaml workflows: flutter-android-signed: name: Flutter Android (signed release) max_build_duration: 120 instance_type: mac_mini_m2 environment: android_signing: - keystore_reference vars: PACKAGE_NAME: "com.example.yourapp" flutter: stable scripts: - name: Set up local.properties script: echo "flutter.sdk=$HOME/programs/flutter" > "$CM_BUILD_DIR/android/local.properties" - name: Get Flutter packages script: flutter pub get - name: Build Android App Bundle script: flutter build appbundle --release artifacts: - build/**/outputs/**/*.aab flutter-ios-signed: name: Flutter iOS (signed release) max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: environment: ios_signing: distribution_type: app_store bundle_identifier: com.example.yourapp flutter: stable xcode: latest cocoapods: default scripts: - name: Set up code signing settings on Xcode project script: xcode-project use-profiles - name: Get Flutter packages script: flutter pub get - name: Install CocoaPods dependencies script: find . -name "Podfile" -execdir pod install \; - name: Flutter build ipa script: | flutter build ipa --release \ --build-name=1.0.0 \ --build-number=1 \ --export-options-plist=/Users/builder/export_options.plist artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log ``` ### Option: React Native Two workflows: **Android** (**AAB**) and **iOS** (**IPA**), using the same `android_signing` / `ios_signing` settings as in **Step 2** above. Adjust paths if your `android/` or `ios/` layout differs. ```yaml workflows: rn-android-signed: name: React Native Android (signed release) max_build_duration: 120 instance_type: mac_mini_m2 environment: android_signing: - keystore_reference vars: PACKAGE_NAME: "com.example.yourapp" node: v22.11.0 scripts: - name: Install npm dependencies script: npm ci - name: Set Android SDK location script: echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/android/local.properties" - name: Build Android release bundle script: | cd android ./gradlew bundleRelease artifacts: - android/app/build/outputs/**/*.aab rn-ios-signed: name: React Native iOS (signed release) max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: environment: ios_signing: distribution_type: app_store bundle_identifier: com.example.yourapp vars: XCODE_WORKSPACE: "YourApp.xcworkspace" XCODE_SCHEME: "YourApp" APP_STORE_APPLE_ID: 1234567890 node: v22.11.0 xcode: latest cocoapods: default scripts: - name: Install npm dependencies script: npm ci - name: Install CocoaPods dependencies script: | cd ios && pod install - name: Set up code signing settings on Xcode project script: xcode-project use-profiles - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "$CM_BUILD_DIR/ios/$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log ``` ### Option: iOS (native) Matches the pattern in [iOS native apps](building-a-native-ios-app): `ios_signing`, `xcode-project use-profiles`, and `xcode-project build-ipa`. ```yaml workflows: ios-native-signed: name: Native iOS (signed release) max_build_duration: 120 instance_type: mac_mini_m2 integrations: app_store_connect: environment: ios_signing: distribution_type: app_store bundle_identifier: com.example.yourapp vars: XCODE_WORKSPACE: "YourApp.xcworkspace" XCODE_SCHEME: "YourApp" xcode: latest cocoapods: default scripts: - name: Install CocoaPods dependencies script: pod install - name: Set up code signing settings on Xcode project script: xcode-project use-profiles - name: Build ipa for distribution script: | xcode-project build-ipa \ --workspace "$CM_BUILD_DIR/$XCODE_WORKSPACE" \ --scheme "$XCODE_SCHEME" artifacts: - build/ios/ipa/*.ipa - /tmp/xcodebuild_logs/*.log ``` ### Option: Android (native) Matches [Android native apps](building-a-native-android-app): `android_signing` and `bundleRelease`. ```yaml workflows: android-native-signed: name: Native Android (signed release) max_build_duration: 120 instance_type: mac_mini_m2 environment: android_signing: - keystore_reference vars: PACKAGE_NAME: "com.example.yourapp" scripts: - name: Set Android SDK location script: echo "sdk.dir=$ANDROID_SDK_ROOT" > "$CM_BUILD_DIR/local.properties" - name: Build Android release bundle script: ./gradlew bundleRelease artifacts: - app/build/outputs/**/*.aab ``` > > **Common issues (signed builds)** > > - **iOS:** Run **`xcode-project use-profiles`** before **`xcode-project build-ipa`** or **`flutter build ipa`**. Check **`distribution_type`** and **bundle ID** match your provisioning profile; Flutter often needs **`--export-options-plist=/Users/builder/export_options.plist`**. More detail: [Common iOS issues](../troubleshooting/common-ios-issues). > - **Android:** The **`keystore_reference`** name in YAML must match **Code signing identities**; **`release`** builds need **`signingConfigs`** wired to **`CM_KEYSTORE_*`** / **`CM_KEY_*`** when `CI=true` (see the Gradle section above). See [Common Android issues](../troubleshooting/common-android-issues). > - **Google Play:** Upload and signing problems are covered in [Common Google Play errors](../troubleshooting/common-google-play-errors). > > If the failure is unclear, open the failing step in the build log and search these guides for the error text. > ## Step 4: Distribute to internal testers Optional: once **Step 3** produces signed artifacts, add **`publishing:`** to each workflow. To run distribution workflows when you push code, set up [Webhooks](../yaml-running-builds/webhooks) from your Git host and define **`triggering:`** in `codemagic.yaml` as in [Starting builds automatically](../yaml-running-builds/starting-builds-automatically). You can still start any workflow manually with Codemagic UI. ```yaml workflows: ios-testflight-internal: name: iOS TestFlight (internal) # ... publishing: app_store_connect: auth: integration submit_to_testflight: true beta_groups: - Internal testers android-play-internal: name: Android Play internal testing # ... publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal ``` The tabs below spell out each **`publishing`** block and link to the full guides. ### Option: iOS (TestFlight) Reuse the **`app_store_connect`** integration from signing. **`auth: integration`** uploads the **`.ipa`** from **`artifacts`**. **`submit_to_testflight`** and **`beta_groups`** run in **post-processing** after the main workflow finishes. Replace group names with your **Internal testing** groups in App Store Connect. Full options (release scheduling, phased release, and so on): [App Store Connect publishing](../yaml-publishing/app-store-connect). ```yaml publishing: app_store_connect: auth: integration submit_to_testflight: true beta_groups: - Internal testers ``` ### Option: Android (Play internal) Store the Play **service account** JSON as a [secret environment variable](../yaml-basic-configuration/environment-variables) (for example **`GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`**) and attach the variable group to the workflow **`environment`** if you use groups. **`track: internal`** targets [internal testing](https://support.google.com/googleplay/android-developer/answer/9845334). For a **new** listing, upload the first **`.aab`** **once** in Play Console; later uploads need a **higher version code**—see [Automatic build versioning](../knowledge-codemagic/build-versioning). Details and optional fields: [Google Play publishing](../yaml-publishing/google-play). ```yaml publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: internal ``` For **Firebase App Distribution**, **GitHub Releases**, and other targets, see [Publishing](../yaml-publishing/). ## Step 5: Publish to the stores **Create separate workflows** in the same `codemagic.yaml` for publishing to the App Store or Play store. Set when each workflow runs with `triggering:`. Store submission has **review**, **metadata**, and **rollout** rules that internal testing does not; use the full guides for **`phased_release`**, **staged rollouts**, and Magic Actions timing. Two **sibling** workflows under **`workflows:`** (production **`.ipa`** / **`.aab`**—reuse your Step 3 build configuration in place of **`# …`**): ```yaml workflows: ios-app-store-release: name: iOS App Store release # ... publishing: app_store_connect: auth: integration submit_to_app_store: true android-play-production: name: Android Play production # ... publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: production ``` ### Option: iOS (App Store) **`submit_to_app_store: true`** requests App Store review in **post-processing** after the **`.ipa`** upload (same pattern as TestFlight actions in Step 4). You still need a valid app record, screenshots, privacy details, and so on in App Store Connect. Details: [App Store Connect publishing](../yaml-publishing/app-store-connect). ```yaml publishing: app_store_connect: auth: integration submit_to_app_store: true ``` ### Option: Android (Play production) **`track: production`** sends the **`.aab`** to the production track. Optional **`rollout_fraction`** and promotion between tracks are in [Google Play publishing](../yaml-publishing/google-play). Each upload must use a **higher version code** than the last one on that track—see [Automatic build versioning](../knowledge-codemagic/build-versioning). ```yaml publishing: google_play: credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS track: production ``` ## Next steps: from signed build to full CI/CD After optional **Steps 4–5**—or if you skip them—most teams go on to: - **Tests** — Run [unit and integration tests](../yaml-testing/testing) in CI, or [Firebase Test Lab](../yaml-testing/firebase-test-lab) for Android device testing. - **Caching** — Speed up repeat builds with [dependency and Xcode caching](../knowledge-codemagic/caching) (Gradle, CocoaPods, Pub / Flutter, and related paths). - **Workflows** — Trigger builds from [webhooks](../yaml-running-builds/webhooks), [branches, pull requests, or tags](../yaml-running-builds/starting-builds-automatically), and use [scheduling](../yaml-running-builds/scheduling) where it helps. - **More distribution** — Extra tracks, Firebase App Distribution, GitHub Releases, and the rest of [Publishing](../yaml-publishing/). ## Further capabilities and next steps - **Build versioning** — [Automatic build versioning](../knowledge-codemagic/build-versioning) (for example App Store or TestFlight build numbers). - **Desktop** — [Flutter code signing](building-a-flutter-app#code-signing) (macOS / Windows), [Signing macOS apps](../yaml-code-signing/signing-macos). - **[codemagic.yaml reference](../yaml/yaml-getting-started)** — full configuration reference. **Deeper guide for your stack:** [Flutter](building-a-flutter-app), [React Native](building-a-react-native-app), [iOS native](building-a-native-ios-app), or [Android native](building-a-native-android-app). For notifications, environment groups, and other topics, use the sidebar or search the docs.