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.

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.
  3. Select the repository from the list of available repositories. Select the appropriate project type.
  4. Click Finish: Add apllication

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.

Tip You can find codemagic.yaml examples in Codemagic Sample Projects repository.

If you prefer to write your codemagic.yaml file from scratch, you can start with this minimal configuration.

workflows:
    android-workflow-id:
        name: Android Sample Workflow
        max_build_duration: 120
        instance_type: mac_mini_m1
workflows:
    ios-workflow-id:
        name: iOS Sample Workflow
        max_build_duration: 120
        instance_type: mac_mini_m1

Tip You can have more than one workflow in the same codemagic.yaml file. If you are building for both the Android and iOS, simply enter both workflows as:
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.

Note: This guide is written specifically for users with Team accounts. If you are a Personal account user, please check the Code signing for Personal accounts guide.

Generating a keystore

You can create a keystore for signing your release builds with the Java Keytool utility by running the following command:

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.

Add the following code to the environment section of your codemagic.yaml file:

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 as follows:

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

Setting up the Android package name

Configure Android package name by adding the corresponding variable in the codemagic.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.

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:
  - android/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.

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.

The prerequisite is a valid Google Cloud Service Account. Plese follow these steps:

  1. Go to this guide 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 GCLOUD_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 Secure option is checked.

  1. Add the google_play variable group to the codemagic.yaml
    workflows:
      android-workflow-id:
        # ....
        environment:
          groups:
            - keystore_credentials
            - google_play
  2. Modify the build script to calculate the build number and use it as gradlew arguments.
    scripts:
        # ....
      - 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
            # 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
  3. Modify the android/app/build.gradle file to get the build number values and apply them:
    // 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 and the Google Play Store 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.

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

react-native-android:
  # ... 
  publishing:
    # ...
    google_play:
      credentials: $GCLOUD_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 Codemagic UI and start the build to see it in action.

Your final codemagic.yaml file should look something like this:

workflows:
  native-android:
    name: Native Android
    max_build_duration: 120
    instance_type: mac_mini_m1
    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/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
          ./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: $GCLOUD_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 to get you started with testing, as well as additional guides such as the one on running tests on Firebase Test Lab or Registering iOS test devices.

Documentation on using codemagic.yaml teaches you to configure additional options such as changing the instance type on which to build, speeding up builds by configuring Caching options, or configuring builds to be automatically triggered on repository events.