Automate (and scale) your Android deployment with Bitbucket Pipelines

We’ve launched a new Android template in Bitbucket Pipelines. This template helps you automate building and testing an Android project in a Docker container, using Gradle as your build tool.

Access the template code here or go to the Pipelines tab of your repo and select the Android template.

This blog walks you through how this template is structured and has tips on how you can scale it.

Prerequisites

  • Android Project with an empty bitbucket-pipelines.yml file in the root folder of the repo.
  • Bitbucket Pipelines should be enabled in your repository. Simply navigate to your repository and click on Settings, and under Pipelines click on Settings again, and select the toggle to enable Pipelines.

If you’d prefer to quickly import a demo repository with a working pipeline to experiment with, have a look at our demo android repo.

Build an Android Project

Bitbucket Pipelines runs all your builds in Docker containers using an image that you specify at the beginning of your configuration file. In this guide, we are going to use Docker for Android SDK 30 with preinstalled build tools and emulator image from the Docker Hub.

Basic configuration

Once you have selected your Docker image, you can start adding a basic configuration to build an Android application:

image: androidsdk/android-30

pipelines:
  default:
      - step:
          name: Android Debug Application
          script:
            - ./gradlew assembleDebug

bitbucket-pipelines.yml

This configuration contains the pipeline definition for all branches with a single step that executes ./gradlew assembleDebug script command.

After you push the new bitbucket-pipelines.yml file you can view your Pipeline status, get detailed log information from its run, and a variety of other useful data.

From the Pipeline build tab, you can see that ./gradlew assembleDebug script command took 1m 16s to execute with a total build time of 1m 21s.

Add caching to speed up build time

Bitbucket Pipelines is able to cache external build dependencies and directories, such as Gradle libraries, between builds providing faster builds. To enable Gradle cache, simply add caches command.

image: androidsdk/android-30

pipelines:
  default:
      - step:
          name: Android Debug Application
          caches:
            - gradle
          script:
            - ./gradlew assembleDebug

bitbucket-pipelines.yml

After you you make the changes ./gradlew assembleDebug script command will take 21s to execute, reducing the total build time from 1m 21s to 35s.

Note: when caching is enabled, the first Pipeline execution will take more time, because the cache has to be uploaded.

Store Artifacts

Artifacts are files that are produced by a step. The assembleDebug script command produces the Android .apk file in the app/build/outputs/ folder. To store artifacts, simply add artifacts command.

image: androidsdk/android-30

pipelines:
  default:
      - step:
          name: Android Debug Application
          caches:
            - gradle
          script:
            - ./gradlew assembleDebug
          artifacts:
            - app/build/outputs/**

bitbucket-pipelines.yml

You can download artifacts generated by a step by selecting the Artifact tab of the pipeline result view as shown in the above screenshot.

To learn more about Pipelines build configurations check out this this article.

Running Static Code Analysis Tools

To keep repository code healthy most of the Android projects nowadays use static code analysis tools like lint, detekt, ktlint. In this guide, we are going to use lint.

Simply add ./gradlew lint script command after the ./gradlew assembleDebug script command. Lint produces reports in the app/build/reports/ folder as an .xml and .html files. To store these files as artifacts, add another artifacts command as shown below.

image: androidsdk/android-30

pipelines:
  default:
      - step:
          name: Android Debug Application
          caches:
            - gradle
          script:
            - ./gradlew assembleDebug
            - ./gradlew lint
          artifacts:
            - app/build/outputs/**
            - app/build/reports/**

bitbucket-pipelines.yml

Linting adds 16s to the build time.

Running Unit Tests

Running tests on CI is another important aspect to assert that the new code is behaving as expected.

To run android unit tests add ./gradlew testDebugUnitTest script command.

Test reporting is automatically enabled in Pipelines, so we don't need to artifacts command.

image: androidsdk/android-30

pipelines:
  default:
      - step:
          name: Android Debug Application
          caches:
            - gradle
          script:
            - ./gradlew assembleDebug
            - ./gradlew lint
            - ./gradlew testDebugUnitTest
          artifacts:
            - app/build/outputs/**
            - app/build/reports/**

bitbucket-pipelines.yml

The number of tests that have been executed is displayed on the right of the Pipeline step as shown in the bottom left of the above screenshot.

20 tests passed

Build and Test Faster

Parallel Steps

Adding more scripts to a single Pipeline step greatly increase total project build time. Fortunately, Bitbucket Pipelines provides a way to run steps in parallel.

To run steps in parallel, instead of running all scripts in one step, you can distribute scripts to multiple steps.

image: androidsdk/android-30

pipelines:
  default:
      - parallel:
          - step:
              name: Android Debug Application
              caches:
                - gradle
              script:
                - ./gradlew assembleDebug
              artifacts:
                - app/build/outputs/**
          - step:
              name: Lint
              caches:
                - gradle
              script:
                - ./gradlew lint
              artifacts:
                - app/build/reports/**
          - step:
              name: Debug Unit Test
              caches:
                - gradle
              script:
                - ./gradlew testDebugUnitTestimage: androidsdk/android-30

bitbucket-pipelines.yml

Total build time decreased from 1m 59s to 1m 39s.

Scale CI as your project grows

When your project grows you will notice that some steps are going to take significantly more time than others.

In the case of Android projects, steps which execute tests take the most time. While Gradle can execute tasks in parallel by enabling org.gradle.parallel flag, you will still be limited to CI machine configuration (Memory, CPU cores).

Splitting the Android project into multiple modules can greatly increase project build speed. Let's add another Android module called feature and move 10 of our tests from the app module into feature module.

Now we can split the Debug Unit Test step into two and run tests independently:

  • App Unit Test
  • Feature Unit Test
image: androidsdk/android-30

pipelines:
  default:
      - parallel:
          - step:
              name: Android Debug Application
              caches:
                - gradle
              script:
                - ./gradlew assembleDebug
              artifacts:
                - app/build/outputs/**
          - step:
              name: Lint
              caches:
                - gradle
              script:
                - ./gradlew lint
              artifacts:
                - app/build/reports/**
          - step:
              name: App Unit Test
              caches:
                - gradle
              script:
                - ./gradlew :app:testDebugUnitTest
          - step:
              name: Feature Unit Test
              caches:
                - gradle
              script:
                - ./gradlew :feature:testDebugUnitTest

bitbucket-pipelines.yml

Total build time decreased from 1m 39s to 1m 09s.

Bitbucket Pipelines at Atlassian

Here is an example of how one of our Android teams benefits from using Bitbucket Pipelines. The Android project has more than:

  • 100 modules
  • 4000 Unit tests
  • 800 UI tests

With Bitbucket Pipelines running steps in parallel, the build time for this project is about 20 minutes.

Splitting the Android project into multiple modules can easily build and test your Android project at scale.

Get started with the Android template.