Android signing config with Gradle

Updated in Android Gradle

Android Gradle plugin can handle the whole app build process from source code compilation to apk signing. In order to produce a signed apk, you need to setup Gradle with signing config with a keystore containing the signing certificate.

Keystore containing the signing certificate can be created with Android Studio, but adding the information to Gradle without adding any secrets to version control is a little bit trickier thing to achieve.

I’ve been using the following setup in my app module build.gradle file:

android {
    ...
    // Load keystore properties if file exists
    def keystore_properties = file('../keystore.properties')
    if (keystore_properties.exists()) {
        Properties props = new Properties()
        props.load(new FileInputStream(keystore_properties))
        props.each { prop ->
            project.ext.set(prop.key, prop.value)
        }
    }

    // Read passwords from Gradle properties and if not found, then from environment variables
    def keystore_password = project.hasProperty('KEYSTORE_PASSWORD') ? KEYSTORE_PASSWORD : System.getenv("KEYSTORE_PASSWORD")
    def key_alias = project.hasProperty('KEY_ALIAS') ? KEY_ALIAS : System.getenv("KEY_ALIAS")
    def key_password = project.hasProperty('KEY_PASSWORD') ? KEY_PASSWORD : System.getenv("KEY_PASSWORD")

    signingConfigs {
        release {
            storeFile file('../keystore.jks')
            storePassword keystore_password
            keyAlias key_alias
            keyPassword key_password
        }
    }
    ...
    buildTypes {
        ...
        release {
            ...
            // Set signing config if keystore variables are set
            if (keystore_password && key_alias && key_password) {
                signingConfig signingConfigs.release
            } else {
                logger.error("You need to define KEYSTORE_PASSWORD, KEY_ALIAS and KEY_PASSWORD to enable release signing.")
            }
            ...
        }
        ...
    }
    ...
}

First thing I do in the Android block is load the keystore variables from keystore.properties file located in the root of the Android project. The keystore properties file is very simple, it just contains the following lines:

KEYSTORE_PASSWORD=passwordForKeystore
KEY_ALIAS=release-key-alias
KEY_PASSWORD=passwordForKey

The second thing in the Android block is to setup the keystore variables. The variables are initialized so that you don’t have to use the properties file if you don’t want to. You can setup the same variables as in the properties file as environment variables. This is helpful for example with CI servers.

After the variable introduction the signing config for release build is set. The keystore location is set as keystore.jks in the parent directory. Keystore location needs to be set, since the build fails if the location is empty.

The release signing config is set in the buildTypes block for release. The config is only set when the variables are available. If there’s no check, then the build will fail due to missing keystore if the properties file (or environment variables) are not available.

This also allows defining other things when release apk is built. For example you can enable minifying only when release build is going to be done:

if (keystore_password && key_alias && key_password) {
    minifyEnabled true
    signingConfig signingConfigs.release
} else {
    logger.error("You need to define KEYSTORE_PASSWORD, KEY_ALIAS and KEY_PASSWORD to enable release signing.")
}

This will speed up your builds, since minifying can take a long time and there’s usually there’s no need to do it for every build.