Scaling Android Deployment With Bitbucket Pipelines and Fastlane

DZone 's Guide to

Scaling Android Deployment With Bitbucket Pipelines and Fastlane

Put your Android application in the Fastlane (see what we did there?) with automated scaling using Bitbucket pipelines.

· DevOps Zone ·
Free Resource

Image title

For all the ways your application can grow and go

Traveler.today makes local travel guides for tourists and self-explorers. We create a different app for each location because each of our apps is made for a different partner/customer.

As our business started to grow, we needed to create multiple new apps per week and it started to take too much time away from the whole team. It interrupted our development work as we would spend most of our time supporting releases. For each new app, it took several hours to configure the server, build and deploy a new application, update the database, fill metadata, etc.

You may also enjoy:  Automating AWS Lambda Deployments Using Bitbucket

The purpose of this post is to share our experience in automating deployment of dozens of Android applications based on the same codebase. This process resulted in reducing our deployment time per app from several hours to several minutes.

What We Did

We decided to automate the most time-consuming parts of the process:

  • Building and deploying servers
  • Refreshing the application database
  • Uploading application metadata (screens, description, changelog)
  • Building and deploying applications

Here’s how we did it using Bitbucket, Git, and Fastlane.

Git Tags and Our Server Deploy Process

We use the Git-flow methodology. We have several test and production environments for each customer. To reduce manual work, we decided to deploy applications using tags with versions. The below image shows you some sample branch names.

Here are some sample branch names

Then we configured a Bitbucket route for each tag version to its environment. For each tag, we build a server instance, copy it, send it to DigitalOcean and then notify our Slack channel about success or failure.

For the test instance, we have a continuous integration process with fast deploy and start. For production, we build and manually deploy. We provide a commit ID, version, and application name into the build script to understand what version was deployed. We use the variables BITBUCKET_TAG   and BITBUCKET_COMMIT to understand which version was deployed for each instance.

Here is some detail on the process.

First, define access variables on the account variable page:

The Bitbucket account variable page

Next, build the CI process using Bitbucket Pipelines. Here is our Pipelines code in the test environment.

 - step:
     name: Build and deploy
       - maven
       - mvn clean install -DskipTests=true -Ptest -Dapp.name=test -Dapp.version=$BITBUCKET_TAG -Dapp.commit=$BITBUCKET_COMMIT
       - scp -v -P $SSH_PORT city-webapp/target/test.war $SSH_LOGIN@$SSH_IP:$DEPLOY_FOLDER
       - scp -v -P $SSH_PORT deploy/deploy_test.sh $SSH_LOGIN@$SSH_IP:$DEPLOY_FOLDER
              - ssh -p $SSH_PORT $SSH_LOGIN@$SSH_IP 'sh $DEPLOY_FOLDER/deploy_test.sh'

Finally, for notifications, we use Slack and Bitbucket WebHooks on our #devops channel. Here’s how you do it. Go to your repo settings page and click on webhooks.

Webhooks push Bitbucket even further

Add a new webhook for each "Push" and "Build status updated" events.

Alerts you want, none you don't

Here is how notifications look.

Green, green everywhere

With this new process, building and deploying microservices for each application only takes a few minutes, including caching and copying files.

Microservices hard at work

Using Fastlane to Build and Deploy Mobile Apps

You can read about how to set up Fastlane in this blog.

In this section, I will describe our build and deploy process. We need to build and deploy several apps for the same code base, but with a different database and metadata like images, descriptions, titles, and changelogs.

Here’s the command to build the app name with the current profile.

fastlane build app:test

Then we start the process of updating the database, building and deploying the application. Step by step.

platform :android do
  desc "Build apps: 'sudo fastlane build app:altay' for instance"
  lane :build do |options|
    update_data(app: options[:app])    #1. update database
    build_android(app: options[:app])  #2. build from src
   deploy(app: options[:app])              #3. deploy app

Step 1: Update Database

We would often forget to update the database or to synchronize API versions. Now, we just run this script to get access to the API:

sudo fastlane update_data app:altay

We have an external API on the server with fresh data in JSON format. Because all new users must have offline access to the data (travelers often don’t have internet), we will provide it for each new release. Then save the downloaded file to the mobile app directory before the build starts. The build script in the next step will fetch this data from the file and save it into the database.

desc "Update database"
lane :update_data do |options|
    objects = download(url: $API_URL + options[:app])
    objectFile = "../mobile/src/" + options[:app] + "/assets/json/database.json"
    File.open(objectFile, 'w') { |file| file.write(database.to_json) }

Step 2: Build

To start build, provide key variables into the script:  $PATH_TO_KEY ,  $STORE_PASSWORD,  $KEY_ALIAS ,  $KEY_PASSWORD.

platform :android do
  desc "Build android app from src”
  lane :build_android do |options|
      task: "assemble",
      flavor: options[:app],
      build_type: "Release",
      print_command: false,
      properties: {
        "android.injected.signing.store.file" => $PATH_TO_KEY,
        "android.injected.signing.store.password" => $STORE_PASSWORD,
        "android.injected.signing.key.alias" => $KEY_ALIAS,
        "android.injected.signing.key.password" => $KEY_PASSWORD,

In the result, we have new APK file, and now we are ready to deploy.

Step 3: Deploy

Manually deploying an application in the App Store and Google Play is a challenge when we want to optimize screenshots, video, or keywords. To deploy the APK, set up the folder with metadata from the source and start the supply Fastlane task. You can also put all these variables into Bitbucket.

desc "Deploy a new version to the Google Play.
  lane :deploy do |options|
      track: options[:track],
      package_name: "today.traveler." + options[:app],
      metadata_path: "$APP_PATH/fastlane/" + options[:app] + "_metadata",
      apk: "mobile/build/outputs/apk/" + options[:app] + "/release/guide-" + options[:app] + ".apk"

The next step for us is to add CI for iOS applications and build a separate server architecture for more micro-services to improve deployment flexibility.


Now the entire application and server deploy process only takes half an hour with all tests and checks. Before automation, it had taken about 1 hour for each app or each server deploy. For 10 apps we’ve saved an entire day in time. For 50 apps, we save an entire week!

Here’s how our new process helped us:

  • No more manually uploading data, database updates and deploys.
  • No more human errors in the workflow.
  • Reduced onboarding time for new team members.
  • And now we always know the version of the product and when it was delivered without a lot of documentation.

We can add any number of new applications to our deployment process and it won’t decrease our speed. That means that we can allocate resources to improve our core product.

As your startup grows, it’s important to think about scaling your development process. I hope this post helped you think about your processes and gave you ideas on you can scale.

Further Reading

Bitbucket vs. Github

Android Clean Code: Part 2

android ,application scaling ,bitbucket pipelines ,fastlane ,mobile

Published at DZone with permission of Ivan Rigovsky . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}