================================================================================
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/).

3. Create a new service account from **CREATE CREDENTIALS** on the [Credentials menu page](https://console.cloud.google.com/apis/credentials).

4. In Step 1, enter the account name and description.

5. In Step 2, select the **Service Accounts > Service Account User** role.

6. Step 3 is unnecessary, so complete it by clicking **Done**.

7. Open the edit page from the **Actions** column of the created service account.

8. From the **KEYS** tab page, click on **ADD KEY > Create new key**.

9. Select **JSON** as the Key type and create a new key.

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.

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.

13. For the **Email address**, enter the one for the service account you just created.

14. From the **Add app**, select the target app.

15. Grant permissions for the **Releases** section (the rest of the settings can be left as default), and click **Apply**.

16. Invite the service account by clicking **Invite user**.

## 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**.

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.

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**.

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.

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.

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).

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.

## 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 
4. Create new release (or the track you want to start with).

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.

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/)).

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**.

### 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
[](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.

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**.

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.

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".

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):
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.

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**.

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.

#### 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:

## 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.

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.

**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**

Give it a name for e.g. **Codemagic CI/CD** and select the workspace of your choice to install the app.
Click create App.

Go to your **App settings > Basic Information > Display Information** and fill all the general details.

### 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.

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.

### 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**.

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.

2. Click **More options** (⋮) → **Connectors** → **Edit**.
3. Add an **Incoming Webhook**.

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.