← Back to Blog

Build by types and sign Android app from Jenkins

Roman Kushnarenko
Dec 04, 2017
DevOps Jenkins Android

In this post I will explain how to update Gradle file, setup signing options and build by types from Jenkins. Keeping sensitive keystore credential hidden.

Previous blog post
Jenkins Android
Setup and build Android app from Jenkins

Step by step guide of how to setup Jenkins and Android SDK on VM and create a basic job that builds Android apps.


Steps

Update Gradle files

We are going to make our build.gradle file to support signing configurations for release build types.

The concept

We don’t want to hardcode the passwords and sensitive info inside our code / build.gradle files. So, we will put the placeholders (variables) in build.gradle file, but the actual values will be injected during the build on Jenkins.

We will use gradle.properties file for this.

Update shared gradle.properties

Add default values to gradle.properties file. This file is located under root of the project.

# Project-wide Gradle settings.
org.gradle.jvmargs=-Xmx1536m

# Undefined maps keys
KEYSTORE_FILE_PATH=undefined
KEYSTORE_PASSWORD=undefined
KEY_ALIAS=undefined
KEY_PASSWORD=undefined
Update module’s build.gradle

Update build.gradle of your app module. We will add signingConfigs and update buildTypes.

android {
    ...
    signingConfigs {
        release {
            storeFile file(KEYSTORE_FILE_PATH)
            storePassword KEYSTORE_PASSWORD
            keyAlias KEY_ALIAS
            keyPassword KEY_PASSWORD
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
        }
    }
}

As you can see, the values of signing config are taken from gradle.properties file variables.

Create signing keystore

We need to create the keystore file. We will use this file to sign the app.

1. Create

Open Android Studio -> Build -> Generate Signed APK. Fill the data and create the file. (Don’t forget the passwords)

2. Upload to Jenkins

Now we need to upload this file to Jenkins server. We’ll put the file in /var/lib/jenkins/keystores/ folder. You can use scp command to copy file from your local machine to remote server (Jenkins machine).

scp [LOCAL_PATH_TO_FILE] [USERNAME]@[REMOTE_SERVER]:[REMOTE_PATH]

It can look something like this:

scp -i ~/.ssh/google_compute_engine ~/Desktop/my.jks roman@35.192.51.10:/home/roman/

Then move the file to /var/lib/jenkins/keystores/

# create folder 
sudo mkdir /var/lib/jenkins/keystores

# move the file
sudo mv my.jks /var/lib/jenkins/keystores/

Update Jenkins job

We will add parameters to our job. These parameters are the ones we need for signing the app.

Execution script - build.sh

We are going to write a script that updates the gradle.properties with values from Jenkins parameters and executes the build.

First of all create new folder in your root project and call it scripts. Then add new file and call it build.sh

The script will do next steps:

  1. Update key store values in gradle.properties file.
  2. Build debug or release APK.
  3. Move ready apk to artifacts folder.

The Jenkins just need to execute this script.

Update Jenkins build step

Job -> Configure -> Build -> Execute shell

# make script executable
chmod +x scripts/build.sh

# run the script
./scripts/build.sh $branch $build_type $store_password $key_password $key_alias $keystore_path

The script build.sh

#!/usr/bin/env bash

branch=$1
buildType=$2
storePassword=$3
keyPassword=$4
keyAlias=$5
keystorePath=$6

echo "Running build script.."
echo "branch: $branch"
echo "buildType: $buildType"

# Update gradle.properties
sed -i "s|KEYSTORE_FILE_PATH=undefined|KEYSTORE_FILE_PATH=$keystorePath|g" gradle.properties
sed -i "s|KEYSTORE_PASSWORD=undefined|KEYSTORE_PASSWORD=$storePassword|g" gradle.properties
sed -i "s|KEY_ALIAS=undefined|KEY_ALIAS=$keyAlias|g" gradle.properties
sed -i "s|KEY_PASSWORD=undefined|KEY_PASSWORD=$keyPassword|g" gradle.properties

# Build
if [ $buildType = 'debug' ]; then
    ./gradlew clean assembleDebug
elif [ $buildType = 'release' ]; then
    ./gradlew clean assembleRelease
fi

# Revert gradle.properties (to prevent secret leaks)
git checkout gradle.properties

# Copy artifacts
mkdir artifacts
if [ $buildType = 'debug' ]; then
    mv app/build/outputs/apk/debug/*.apk artifacts/
elif [ $buildType = 'release' ]; then
    mv app/build/outputs/apk/release/*.apk artifacts/
fi
The final script - Check here.

🎉 That’s it. Try running your job!


Next blog post

Build Android Lint Tests
Run lint and unit tests of Android builds from Jenkins

In this post I will show how to run lint and junit tests part of the build process and present the results in Jenkins job.

Questions

If you have any comments, please open an issue at https://github.com/sromku/build-android-jenkins