This post was written by Alexander Zhukov, a Senior Software Engineer at SoftServe.
Setting up CI/CD for your Android app lets you automate much of your development process, resulting in higher velocity development with less bugs and defects, and new features getting into the hands of your customers faster.
Bitbucket Pipelines can be used to automatically build and test your Android application, and this guide will show you how to do this through a workflow that includes internal, alpha, beta, and production processes, using a simple demo application (source code available here).
Before publishing your Android application using Pipelines, you need to do a couple of things:
Bitbucket Pipelines should also be enabled in your repository. Simply navigate to your repository and click on Settings, and under Pipelines click on Settings again, selecting the toggle to enable Pipelines.
Configuring your Pipeline
The pipeline configuration will consist of several steps:
- Setup of the build environment.
- Building the debug application (debug version) for testing.
- Building the application for production.
- Running tests.
- Publishing to the Internal track.
- Promoting Internal to Alpha.
- Promoting Alpha to Beta.
- Promoting Beta to Production.
The last three steps are triggered manually in order to provide more control over the release process.
During the pipeline execution we will use a couple of environment variables that you'll need to setup. Here is a list of variables:
|GOOGLE_API_KEY_JSON||The API key for your google service account with permissions to publish to Google Play.|
|SIGNING_JKS_FILE||Base64 encoded contents of the Java KeyStore file containing your code signing certificate.|
|SIGNING_KEYSTORE_PASSWORD||Password to your java key store with your signing key|
|SIGNING_KEY_ALIAS||The alias name of the key in your key store|
|SIGNING_KEY_PASSWORD||Password to the signing key|
You'll learn where to get the values for these variables later. You can configure your variables by navigating to Repository settings > Pipelines > Settings > Repository variables.
Building and testing the application
The workflow in this guide uses two parallel steps to build a debug and production an Android Application Package (APK). Add the following snippet to your
Tip: Use caching to speed up subsequent execution. In the example below we cache the gradle dependencies.
pipelines: branches: master: - parallel: - step: name: Build image: bitbucketpipelines/android-ci-image caches: - gradle script: - echo "$SIGNING_JKS_FILE" | base64 -d > android-signing-keystore.jks - ./gradlew assembleRelease artifacts: - app/build/outputs/** - step: name: Build Debug caches: - gradle image: bitbucketpipelines/android-ci-image script: - echo "$SIGNING_JKS_FILE" | base64 -d > android-signing-keystore.jks - ./gradlew assembleDebug artifacts: - app/build/outputs/**
Note that we're using a
SIGNING_JKS_FILE variable. The value is a base64 encoded content of your Java KeyStore file containing your code signing certificate. You can learn more about Android app signing here.
Tip: Use secured variables for sensitive data like passwords and tokens.
To encode your file you can run the following command and copy the output:
base64 -w 0 keystore-file.jks. To generate a self signed code signing certificate, you can use the java keytool:
keytool -genkey -v -keystore keystore-file.jks -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
Notice that in the yaml snippet above we specify which artifacts we would like to create during the step execution. In our case we want to keep our APK files for future testing and publishing in subsequent steps.
Running our unit tests
To run your unit tests using gradle add another step to your
- step: name: Test image: bitbucketpipelines/android-ci-image script: - ./gradlew test
Note: You should upload the first version of the APK manually via Google Play dashboard. This will connect your Google Play application with the package ID from your build.gradle configuration
Now we’ll publish our release APK to the internal testing track. This is the last step that is triggered automatically, and all other steps will need to be triggered manually to promote the package to the rest of the tracks. Tracks are a way to organize and manage your test and production releases in Google Play. You can read about open, closed and internal tests here.
Tip: Deployments in Bitbucket allow you to view and track deployment results. In the example below, we use the "Internal" deployment environment. Read more about Deployments in our official docs.
- step: name: Publish Internal image: bitbucketpipelines/android-ci-image deployment: Internal script: - echo $GOOGLE_API_KEY_JSON > google_play_api_key.json - echo "$SIGNING_JKS_FILE" | base64 -d > android-signing-keystore.jks - ./gradlew publishReleaseApk
publishReleaseApk task is available when you enable the Gradle Play Publisher plugin.
You'll need to configure the
GOOGLE_API_KEY_JSON variable to use for this and remaining steps. The value of this variable should be the content of the Google API Key json file for the service account that has permissions to publish and promote APKs. Below is a simple instruction how to create a service account and generate an API key json file:
- Open the Google Play Console
- Click the Settings menu entry, followed by API access
- Click the CREATE SERVICE ACCOUNT button
- Follow the Google Developers Console link in the dialog, which opens a new tab/window:
- Click the CREATE SERVICE ACCOUNT button at the top of the Google Developers Console
- Provide a Service account name
- Click Select a role and choose Service Accounts > Service Account User
- Check the Furnish a new private key checkbox
- Make sure JSON is selected as the Key type
- Click SAVE to close the dialog
- Make a note of the file name of the JSON file downloaded to your computer
- Back on the Google Play Console, click DONE to close the dialog
- Click on Grant Access for the newly added service account
- Choose Release Manager (or alternatively Project Lead) from the Role dropdown. (Note that choosing Release Manager grants access to the production track and all other tracks. Choosing Project Lead grants access to update all tracks except the production track.)
- Click ADD USER to close the dialog
Promoting using Deployments
The last three steps are manually triggered steps to promote to the rest of the Google Play tracks, including Alpha, Beta and Production. You can also configure multiple options, such as rollout fractions.
- step: name: Promote Internal to Alpha image: bitbucketpipelines/android-ci-image deployment: Alpha trigger: manual script: - echo $GOOGLE_API_KEY_JSON > google_play_api_key.json - ./gradlew promoteArtifact --track alpha - step: name: Promote Alpha to Beta trigger: manual image: bitbucketpipelines/android-ci-image deployment: Beta script: - echo $GOOGLE_API_KEY_JSON > google_play_api_key.json - ./gradlew promoteArtifact --track beta - step: name: Promote Beta to Production trigger: manual image: bitbucketpipelines/android-ci-image deployment: Production script: - echo $GOOGLE_API_KEY_JSON > google_play_api_key.json - ./gradlew promoteArtifact --track production
And with that you now have an easy workflow that lets you build, test, and deploy your Android app to the Google Play Store using Bitbucket Pipelines and Deployments!