Basic implementation of CI & CD in Android development
Tags: mobile
Published: 2022-11-09 08:20:39

---
title: Basic implementation of CI & CD in Android development
published: true
date: 2022-11-08 08:53:38 UTC
tags: Mobile
canonical_url: https://apiumhub.com/tech-blog-barcelona/basic-implementation-of-ci-cd-in-android-development/
---

CI & CD is a software development practice most mobile developers in team projects use daily, however, most times the Version Control practices (or _git branching strategy_) as well as the automated testing/deployment is already established and will only require small changes if anything. On the other hand, when working on individual or personal projects setting up our own CI & CD pipelines can seem overkill if not with a learning motive or client requirement.

As a result, many mobile developers might feel like CI & CD falls outside their fields of expertise, and perhaps without the use of a mobile DevOps platform this might be the case, but mobile CI & CD automation has never been easier through the use of these platforms.

This article will not focus on CI & CD as a concept but on an overview of the implementation of CI & CD through a mobile DevOps platform, making use of its simplicity but multiple configurable features.

## **CI (Continuous Integration)**

When we talk about CI we refer to regularly integrating or pushing code into a shared code repository, and automatically running tests against the changes to detect any issues before being merged into the team’s shared repository. 

## **CD (Continuous Delivery/Deployment)**

As for CD in a mobile app development context, we refer to automatically building our apps and delivering them to groups of interest such as QA, clients, testers… etc, or deployed to an app store, when a particular CI action is triggered.

## **DevOps platforms**

There are very popular Source Control platforms such as GitHub and Gitlab, and they both provide their own CI/CD pipeline integrations. These are definitely viable solutions, especially when your project is already being hosted there, but due to their multi-purpose and multi-platform nature, they are harder to understand when it comes to the sole aspect of mobile continuous integration & development.

The end product of a CI/CD configuration file is an YML file with the instructions to be carried out by an external machine. Mobile DevOps platforms allow us to use their interfaces and a wide variety of features to customize our pipeline, in a safe way, as it generates said YML file without us having to edit any line of code in the file. Likewise, modifying manually the YML will also update the UI steps we see in the workflows. It also provides build reports and information more clearly to the user, as the platform solely focuses on CI/CD integration.

Within CI/CD and more specifically the DevOps platforms there are some common concepts that should be explained:

**Workflows –** The core tool we will use to customize the automation. Workflows are a set of steps the platform performs for us to implement a CI/CD pipeline. These may include building, testing, or deploying an app. 

**Steps** – Steps are the different actions our platform can run inside a workflow, these may include git repository actions, running builds, deploying an apk, modifying a Gradle file, or simply a script… etc. There are several possibilities.

**Triggers** – These are the conditions that will _trigger_ a workflow. These will most likely be related to pushes and merge requests from one branch to another.

**Environment variables** – Just like your standard environment variables, these variables can be stored in the project’s space so they are widely available within workflows. Examples could include apk directories, package names, app modules, or variants.

**Secrets** – Similar to environment variables, these might be required in some steps in the workflow, but secrets contain secure sensitive information, for example, a token to access Play Store APIs.

**Code signing** – This will include any files necessary when releasing, such as Keystore files, their alias, and passwords. Bitrise will store and safely handle these for you.

**YML file –** This is the configuration file you have set up through the platform’s interface. It is always accessible for you to read and edit. It will act as an instruction guide for the machine running the pipeline. This file should be stored in the app repository (Bitrise can manage this for you). This is useful in case you ever run into CI configuration problems as you can easily revert to a previous version and update the YML file in Bitrise.

## **Introducing Bitrise**

There are multiple DevOps platforms, but Bitrise is a mobile-first provider and arguably one of the most simple but capable platforms to get set up. Also, you get a few free credits to set up your pipeline and run a few builds. You can find Bitrise at the top of many [mobile DevOps Platforms lists](https://geekflare.com/mobile-devops-platforms/#geekflare-toc-bitrise).

For almost every Android CI/CD action you might want to run, [Bitrise docs](https://devcenter.bitrise.io/en/steps-and-workflows/workflow-recipes-for-android-apps.html) have a template for that workflow, explaining what steps you should add and why. Some steps could be considered boilerplate as they might be required in the workflow regardless of the platform or goal such as: connecting to our VCS, cloning the project repository, pulling/pushing caches from bitrise to speed up build times, or deploying build results back to bitrise. Most other steps, however, will be defined by the goal and platform.

## **CI & CD in practice**

To integrate pipelines we first need to define a version control or _git branching_ strategy. Next, we will describe a common sample\* strategy that will help us define our workflows. 

This will consist of the following branches and their roles:

- **Development** – This is the base branch with a stable shared codebase for the devs in the team. Every time we want to add code we checkout this branch and push or pull request the changes back into _development_, triggering unit tests as well as UI tests which when passed, will allow the MR or push to succeed.

- **Staging** – When we want our code to pass a QA check we will merge _development_ into _staging_, QAs should only use this branch to pass their tests. This stage might generate an unsigned apk build to be deployed to a platform such as a firebase for testers and/or clients to test. No testing is required in this workflow as we would be repeating the same tests against the same codebase from the **development** workflow.

- **Release** – When our app is ready to be deployed we can merge _staging_ into _release_. This can trigger a release to the Play Store, but even though some might prefer to manually update the app and skip this trigger, you can also use it to release it to an alpha or beta channel, not necessarily production.

_\*This strategy is just an example and not the best practice, it provides a good base and understanding for CI/CD to be implemented through a mobile DevOps platform. The best or most optimal strategy can depend on many factors and will vary from project to project._ 

## **Our workflows**

Next, we will look at how 3 different workflows in the _development_–_staging_–_release_ VC strategy we described above would look like, and how they are triggered.

### **Development workflow:**

Role → Merging into this branch means adding changes to the code that require tests to pass before merging, to ensure new code doesn’t break anything.

Trigger → Pushing or making a merge request from a _development/feature\_branch_ (or any other) to the _development_ branch.

Specific steps →  This workflow will run all the Android steps needed to run Unit Tests and UI Tests if we have any. For this we can read Bitrise docs and figure out what steps we need and configure them accordingly. For example, when testing for UI tests we might need an _AVD Manager_ step, and if we are using an Emulator we need a _Wait for Android emulator_ step.

![Ql V81aBa3Ls71og4t NS8Gp0ckDYkArtpKUoiznfMeDKYDqB XYI6BRfOFGfO8CFY0OyLkAIDeL w1Z sGE rEsbLb3vvKwbh3Po1TaTaLCay8bAlF](https://lh5.googleusercontent.com/Ql-V81aBa3Ls71og4t-NS8Gp0ckDYkArtpKUoiznfMeDKYDqB-XYI6BRfOFGfO8CFY0OyLkAIDeL_w1Z-sGE-rEsbLb3vvKwbh3Po1TaTaLCay8bAlF-FuTCFfe7xD51cpUSVFheOve_OkniJbmrJTqdREaqGl8DE18idtLCLKVItnu_1kR_5RCOIagCug "Basic implementation of CI & CD in Android development 6")

### **Staging workflow:**

Role → Merging into this branch could mean an APK should be made available to a group of interest, such as QA, or a client.

Trigger → Pushing to the _staging_ branch

Specific steps →  This workflow doesn’t include any testing steps, as there have been no changes in the code from the codebase in _development_. This workflow is characterized by having an Android Build step that generates an unsigned APK and another step that distributes it to Firebase.

To showcase some interesting features we also added steps to automatically modify the versionCode and the versionName of our app. To do so we need to run a script that will modify the Gradle file dynamically, however, it requires the branch name to contain the desired version name, and the versionCode can only be updated to the Bitrise build number so it does have obvious limitations.

![AX6xNFtBeaS6ur VMZVkIpsMEqEyZPGIg5YIq PapshEalsU0SCfB 3WzEKouTsl3q6zBW3Fnooa4cqif Hg9ZWyFxo S1r Z5YoKb39DVdzg2GHiPkBS oFL9k2T1GZhTPAYyPchptp9B1R89gg1epCIlXyoEPZMyEAMAbVIJ1JbbrbgVGUGPCLiNQ g](https://lh5.googleusercontent.com/AX6xNFtBeaS6ur_VMZVkIpsMEqEyZPGIg5YIq-PapshEalsU0SCfB-3WzEKouTsl3q6zBW3Fnooa4cqif-Hg9ZWyFxo__S1r-Z5YoKb39DVdzg2GHiPkBS_oFL9k2T1GZhTPAYyPchptp9B1R89gg1epCIlXyoEPZMyEAMAbVIJ1JbbrbgVGUGPCLiNQ-g "Basic implementation of CI & CD in Android development 7")

### **Release workflow:**

Role → Merging into this branch means an APK should be deployed to the playstore, to a channel(s).

Trigger → Pushing to the _release_ branch

Specific steps →  This workflow is characterized by adding an Android Sign step to the build (will require App Signing information such as Keystore JKS file and alias key and password) and another step to distribute to the play store (requires a play store console service account set up, as well as a file with the release notes if desired, and other specifications such as channel, apk or bundle… etc)

![t3dNi44Gp3oKUnXfJAdeoDTVDsicUFk7ZaSp7Eq2DOgLPrn G24sWCCZSLSvT tE5dWy1U5heKV1IZK7tN9keAQIF3MiSxiT uPayYgrXJspV7jzB2VnITi1 cGyjc0mJEe7IryAmCXywT 8AIxqqV2kQ6Uoybk3YkHbMeunGwYjlYmCVHFhDs KqNultA](https://lh6.googleusercontent.com/t3dNi44Gp3oKUnXfJAdeoDTVDsicUFk7ZaSp7Eq2DOgLPrn-G24sWCCZSLSvT_tE5dWy1U5heKV1IZK7tN9keAQIF3MiSxiT_uPayYgrXJspV7jzB2VnITi1_cGyjc0mJEe7IryAmCXywT_8AIxqqV2kQ6Uoybk3YkHbMeunGwYjlYmCVHFhDs-KqNultA "Basic implementation of CI & CD in Android development 8")

## **Setting up the triggers**

Now that we have defined our workflows, we can configure the triggers, which means specifying what actions will trigger each workflow. Bitrise has a tab for us to specify these actions easily.

For the **development** workflow, we set a trigger for pull requests (or pushes), in which we state that any branch making a PR into _development_ will start up the **development** (called _development\_tests_ in the screenshot) workflow:

Next time we make a PR our VC website will pop up a message indicating a Bitrise pipeline is running. Depending on the build’s success it will show a green check or an error. 

![9LDZBxWNt22cQDi66j5iXtbWsSng ql0qPMA3bgPhWQqlHGoMJn28aqhptVo JuO RffiyZzS uMYs4RP0N3SKOFqP kKpoatpOPXOtSbRUd8J2d5WrluLl Om0R60okNWk2eaVP1d3p8AwOg4J13APM72ofkj3SrMu5CnbFolTgCVjT5WlXO7gM3zlPCQ](https://lh4.googleusercontent.com/9LDZBxWNt22cQDi66j5iXtbWsSng-ql0qPMA3bgPhWQqlHGoMJn28aqhptVo-JuO-RffiyZzS_uMYs4RP0N3SKOFqP-kKpoatpOPXOtSbRUd8J2d5WrluLl_Om0R60okNWk2eaVP1d3p8AwOg4J13APM72ofkj3SrMu5CnbFolTgCVjT5WlXO7gM3zlPCQ "Basic implementation of CI & CD in Android development 9")

For the **staging** (called _staging\_deploy\_firebase\_apk_ in the screenshot) and **release** (called _release\_deploy_ in the screenshot) workflows, we have similar triggers. Both will trigger when there is a push action to their respective branches:

![vAOshVWS2IRgbbsNUPshMkza5gM6z8fESVh1Q 1tkY5c0hk8TqalzySAhSV4zkG2i3KYnL7BXwbCt8n1U0Vb9MowZi5fWZfjphBeDU 7YlFBqZpLra5 l32wMMp7MMF35vEn3tAwJawNo2GBoihK UF8dgX3J0OCoehsw55LnsmrC6rKOao dpL Mp0Uiw](https://lh6.googleusercontent.com/vAOshVWS2IRgbbsNUPshMkza5gM6z8fESVh1Q-1tkY5c0hk8TqalzySAhSV4zkG2i3KYnL7BXwbCt8n1U0Vb9MowZi5fWZfjphBeDU_7YlFBqZpLra5-l32wMMp7MMF35vEn3tAwJawNo2GBoihK-UF8dgX3J0OCoehsw55LnsmrC6rKOao-dpL_Mp0Uiw "Basic implementation of CI & CD in Android development 10")

## **All set!**  

Once we have defined the workflows and the triggers, we have essentially built our pipelines, and all we should do is respect the branching strategy for the CI/CD to be correctly implemented.

We did not dive into the details for every step configuration and platform feature to keep it short and sweet but hopefully this article will provide some insight into how simple CI/CD in an Android project can look like and the capabilities of mobile DevOps platforms.