Published in


Using TravisCI to securely build and deploy a signed version of your Android app.

In my team we’ve started using TravisCI for our projects — namely, for automatically building our app, Curated. We’re happy with the way it integrates with our Github repositories and its easy configurability. It’s also free to use for open source projects — a great quality for any tool.

Doing the initial setup — building the app by pulling the correct tools and then running unit tests when a PR is opened — was easy enough. Our next big hurdle was how to have Travis build a signed, release version of our APK? We wanted to be able to do this securely — without adding our Keystore file or any of its credential details in source control or having them visible anywhere else. I undertook this task and will share here how I managed to crack it.

“Every day thousands of APKs are securely delivered. We wanted to join the fun”

Lets first define what our goals are:

  • Create a Keystore file + credentials with which to sign the apk.
  • Use Travis to add an encrypted version of our Keystore file to our repository.
  • Store our keystore’s secure credentials in Travis.
  • When new code is pushed to our repository use Travis to build and deploy a signed, release version of the APK.

For this example we’ll use Github releases as our release provider.


In this article we’ll be working with our app build.gradle and our .travis.yml files. To start with, they don’t need to have anything more than the default setup. If you’re looking for examples, I provide a link to a project at the end of this article.

Let’s start — create the keystore

Our first step is to create our Keystore file. The easiest way is to follow the official Generate Key and Keystore guide. If you already have a Keystore and credentials, great — skip this part. The important thing to remember here is to not actually use the wizard to sign your app — once you’ve created the keystore and assigned credentials to it, you should click cancel. Remember the credentials you used as you’ll need them shortly.

This means you’ve created the keystore. You can cancel at this stage.

Store our keystore securely with Travis

We have our keystore, great. Now we have to add it to Travis. For this we’ll use the Travis File Encryption functionality. If you’ve not done so already, install the Travis command line tools by executing gem install travis in your terminal. Use the terminal to cd into your project location. Execute travis login to make sure you authenticate Travis with your Github account.

Now, copy the your keystore file to the place in your project repository you’d like it to live. I just put it in the root repo folder for this example. Now run the following command travis encrypt-file OurStore.keystore --add replacing OurStore.keystore with your own Keystore name. You’ll see something like the following output.

Before you do anything else, delete the original keystore file from the repository folder where you executed the command (as Travis handily informs you to). Now you’re left with something called OurStore.keystore.enc — this is the encrypted version of the file and can be safely commited to your repository. You’ll also notice the following command in the before_install step of your .travis.yml file:

before_install:- openssl aes-256-cbc -K $encrypted_839e38d787bc_key -iv $encrypted_839e38d787bc_iv -in OurStore.keystore.enc -out OurStore.keystore -d

I won’t go into how openssl works here, but simply put what has happened is that Travis has encrypted our file using the aes-256-cbc cipher, which is an industry standard encryption algorithm. The arguments it passes as -K and -iv are the key and initialisation vector, respectively (google that if you want to learn more about it). Travis generates those and, if you look in your Travis web console project settings page, you’ll see that those two parameters have been added to the Environment Variables list. Notice that even we can’t see those values. They’re secret and only available to the Travis Virtual Machine when it works on your app.

What you actually care about is that this command runs in the before_install step and it decrypts the .keystore.enc file to provide us with what we need — our .keystore file. Similar to the Environment Variables, our keystore will only be available on the Travis VM while it builds on our app. Since Travis will tear down the VM after it finishes, we can be sure it won’t be leaked anywhere else.

Great — so now when Travis builds our app we will have access to our Keystore. On with the next step.

Store our credentials securely with Travis

Getting access to our Keystore is only half the work — we still need our credentials for it in order to create a signed APK. Doing this is very simple — we’ll just use the Environment Variables — the place that Travis stored our Keystore decryption parameters — to also store our credentials.

The reason why we use Environment Variables is twofold — first, they are encrypted and second — they are available to our whole project, which is useful if you want to generate APKs from different branches.

Go to the Travis web console settings page and add your parameters. Remember, don’t enable the Display Value in build log option else they will be printed to build logs which is not safe. Name them something sensible — you can see how they are named in the example here:

Now, keystore_alias, keystore_alias_password and keystore_password will be available as system environment variables when the Travis VM builds the app. Now its time to jump into our gradle file to tie this all together.

Create and sign a release version of the apk

Time to edit the app’s build.gradle file. There we need to create a release signing config and populate it — but only when running on Travis, since we won’t have access to the data otherwise. You can see how to handle that below.

Modified file to setup a signing config when running on Travis

You can see the important bits are in the lower half of the file. We use the System.getenv function to get access to the environment variables Travis provides. "CI" is actually one of the default handy variables Travis sets for us. We use it here to determine whether Travis is building our app. If that is the case we populate our signing config with the store file, password, key alias and alias password. Pretty straightforward!

One final step — let’s deploy to Github Releases

Creating a signed APK is not much use unless we actually deploy it somewhere. You can find the guide on how to setup Github releases with Travis here. When setting up the example project used for this article the .travis.yml file ended up like this:

It’s a very simple implementation — it will deploy to Github releases when a commit is tagged in the repo. The deployment will contain the contents of the apk release folder.

And that’s it — we’re all done. I hope this guide has been helpful to you if you’re using Travis or planning on using it for your own Android projects.

You can find all the code used in this article in this example project on Github.




The (retired) Pub(lication) for Android & Tech, focused on Development

Recommended from Medium

▷ Mobile App Development in Barbados | Professional App Developers in Barbados — MDX

▷ Mobile App Development in Barbados | Professional App Developers in Barbados - MDX

YAKDT: Yet Another Kubernetes Development Toolkit

A Complete Guide to Deploying Elixir & Phoenix Applications on Kubernetes — Part 1: Setting up…

Substack Newsletter — OpenLampTech issue #32

Sunset for SAP HEC Or RISE with SAP?

Standardize display of checkboxes in APEX

Canopas Podcast 5— Imperative vs Declarative Programming paradigms

The Repository Pattern

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Valentin Hinov

Valentin Hinov

I'm passionate about building applications which are both well designed and intelligently architected. Find me at

More from Medium

How to send SMS programmatically from an Android application

Debugging API traffic on Android devices

How to Set Up Jenkins and Jenkins Pipeline with Android : Step-by-Step Guide (Part 1)

How to Intercepter HTTPS on Android With Requestly SDK