CICD — Build, Test, Ship — Android Apps

By — Akshat Kukreti (Engineer, App Platform)

UC Blogger
Urban Company – Engineering
5 min readMay 27, 2020

--

This blog post comes to you from the mobile engineering team at Urban Company. We are a group of passionate engineers dedicated to creating the biggest services market place in the world. At the same time, we are also striving to solve challenges related to efficiency and developer productivity. This blog post describes how we solved for continuous integration and delivery of our Android apps.

Problems with the Manual Android Release Process

  1. Manual builds on development machines: APKs had to be built on individual development machines. This would lead to loss in developer productivity as important work had to be stopped in order to build the app.
  2. No tracking of builds: Since anyone could individually build the app, it was difficult to maintain production and ad-hoc releases.
  3. No testing phase: The lack of a centralised build system made it impossible to ensure testing before releases. Without testing, one could easily release a buggy app.
  4. Continuous testing: Continuous testing is the process in which we regularly test for breaking changes on merge. This becomes really important in an environment where multiple teams are working on different problem statements in parallel and releases consist of multiple features. In a manual release process, it was difficult to continuously test at regular intervals.
  5. No centralised code quality check: Since the builds were created on individual machines, it was difficult to ensure a code quality process and keep track of release metrics such as lint errors and warnings.

Android CI/CD Process

Our Android CI/CD setup has Jenkins running on a EC2 container. Android SDK and JDK are setup on the Jenkins instance

Triggering the build process –

The build process could be triggered in the following two ways:

  1. Automatically – GitLab webhooks with the following the events:
    a) Push event to a branch.
    b) Merge request on a branch.
    c) Comment on any merge request.
  2. Manually – Jenkins with the following build flavour options:
    a) Test
    b) Staging
    c) Production

Stages of the build process –

Based on the above configurations, the build process works in the following stages:

  1. A gradle task writes the above build information into an environment properties file.
  2. At the start of the build process, environment properties are read from the file built in step 1.
  3. Based on the combination of properties from the environment properties, different flavours of the app are built along with the following steps.
  4. Linting.
  5. Unit and UI testing.
  6. Lint results are published on Jenkins.
  7. The built APKs/Android bundles for release are uploaded to a dedicated Slack channel.
  8. Gitlab is updated with the build results in case the build was triggered via a Gitlab event.
  9. A code analysis script is run that publishes the following data to our internal dashboards
    a) Lint errors.
    b) Size of the APK.

How has This Helped Us?

  1. Improved developer productivity: By delegating the task of creating and releasing builds to a dedicated Jenkins server, we no longer need to stop doing important work to create and distribute ad-hoc, and release builds.
  2. Automated deployment: The Jenkins Gitlab plugin enables us to create a web-hook that triggers builds on git events such as push to development branch. The Gitlab plugin also enables us to trigger timely builds. For example, we create daily test builds to ensure that new features are continuously integrated with the current codebase.
  3. Ensure testing before release: The new system enables us to ensure testing as a part of our release process. First, a development environment build is created, and unit and UI tests are run. After the tests succeed, the actual release build is started. If the tests fail, the Gitlab plugin doesn’t allow the code to be merged. We will talk in detail about testing process in our next blog post.
  4. Continuous testing: We can now automatically trigger unit and UI tests when a change gets merged into our stable development branch. This is done with the help of Gitlab web-hooks. We have configured our Gitlab web-hooks to run tests nightly.
  5. Easy tracking and sharing of builds: The resultant build and test reports are uploaded to a dedicated Slack channel which ensures that the builds are getting tracked. The builds can be easily shared.
  6. Code level release metrics: As explained above, the CI/CD system publishes release metrics including lint results, APK size, and warnings as a post build step. This enables us to keep a track of our releases and easily detect anomalies introduced due to code.

By investing in a CI/CD process, we were able to eliminate several tedious manual tasks, and create an automated centralised build system that aids in building apps without busy waiting, ensuring quality through automated testing, tracking builds, and publishing release metrics that can be used to improve future releases.

Many thanks to Vivek Singh and Dilpreet Singh for their effort on this project.

About the author –

Akshat Kukreti is part of the app infrastructure team solving for developer happiness, efficient processes and tooling. A quiet person in office, he is quite the show stopper during offsites. He enjoys gaming in his spare time.

Sounds like fun?
If you enjoyed this blog post, please clap 👏(as many times as you like) and follow us (@UC Blogger) . Help us build a community by sharing on your favourite social networks (Twitter, LinkedIn, Facebook, etc).

You can read up more about us on our publications —
https://medium.com/uc-design
https://medium.com/uc-engineering
https://medium.com/uc-culture

https://www.urbancompany.com/blog/humans-of-urbanclap

If you are interested in finding out about opportunities, visit us at http://careers.urbancompany.com

--

--

UC Blogger
Urban Company – Engineering

The author of stories from inside Urban Company (owner of Engineering, Design & Culture blogs)