Gradle signing flavors with different keys on Android

AndroidGradleAndroid Gradle-PluginCode Signing

Android Problem Overview


I have many flavors of my Android app, and I want all but one to use the same key. There is one that needs to use a different key.

How do I override the signingConfig for just 1 flavor of the app (but within the same build type e.g. "release")?

  • I would like all builds by default to use the main release configuration.
  • I only want to override 1 flavor
  • I want to be able to run all release builds with a single gradlew assembleRelease command

This last point is important as I currently have over 120 different flavors and growing. In order to customise every single flavor individually is a lot of extra work.


Related posts I have tried:

Producing multiple builds signed with different keys from single build type

  • this requires configuration for each flavor
  • it doesn't seem to use my custom signingConfig anyway

Signing product flavors with gradle

  • accepted solution doesn't work (for me)
  • according to a comment this is possible by putting buildTypes inside the productFlavors but I do not understand how to do this.

Debug Signing Config on Gradle Product Flavors

Overall, each solution seems to still use the default release config, instead of my custom config.


Important parts of my build.gradle look like this:

signingConfigs {
    releaseConfig {
        storeFile file('key')
        storePassword "pass"
        keyAlias "alias"
        keyPassword "pass"
    }

    custom {
        storeFile file('custom_key')
        storePassword "pass"
        keyAlias "alias"
        keyPassword "pass"
    }
}

productFlavors {
    apple {
        applicationId "demo.apple"
    }
    banana {
        applicationId "demo.banana"
    }
    
    // def customConfig = signingConfigs.custom
    custom {
        applicationId "custom.signed.app"
        // signingConfig customConfig
    }
 }


buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
    release {
         signingConfig signingConfigs.releaseConfig
         // productFlavors.custom.signingConfig signingConfigs.custom
    }
}

Android Solutions


Solution 1 - Android

The Gradle Plugin User Guide says that you can:

> have each release package use their own SigningConfig by setting each > android.productFlavors.*.signingConfig objects separately.

This is demonstrated in this answer (Debug Signing Config on Gradle Product Flavors) and this blog post (Building Multiple Editions of an Android App with Gradle).

However, specifying a separate signingConfig line for each flavor does not scale well, and was out of scope of the question. Unfortunately none of the provided answers showed how to correctly override a signingConfig correctly.


The trick came from this answer (How to get the currently chose build variant in gradle?) which shows how to loop over build variants (and by extension, flavors).

My solution uses a loop to set the signingConfig on each flavor instead of having a separate line for that. This scales perfectly well. The "override" is done with a single line that specifies the custom config after the loop.

Place the following code inside the buildTypes.release block:

// loop over all flavors to set default signing config
productFlavors.all { flavor ->
    flavor.signingConfig signingConfigs.releaseConfig
}
// override default for single custom flavor
productFlavors.custom.signingConfig signingConfigs.custom

Solution 2 - Android

The below given code will use release1 as default signingConfig if signingConfig is not specified in the product flavor.

app/build.gradle

signingConfigs {
    debug {
        storeFile file("/home/.../debugkeystore.jks")
        storePassword "..."
        keyAlias "..."
        keyPassword "..."
    }
    release1 {
        storeFile file("/home/.../testkeystore1.jks")
        storePassword "..."
        keyAlias "..."
        keyPassword "..."
    }
    release2 {
        storeFile file("/home/.../testkeystore2.jks")
        storePassword "..."
        keyAlias "..."
        keyPassword "..."
    }
    release3 {
        storeFile file("/home/.../testkeystore3.jks")
        storePassword "..."
        keyAlias "..."
        keyPassword "..."
    }
}

defaultConfig {
    applicationId "com.example.signingproductflavors"
    minSdkVersion 15
    targetSdkVersion 24
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    signingConfig signingConfigs.release1
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug { 
        signingConfig signingConfigs.debug
    }
}

productFlavors {
    blocks {
        applicationId "com.example.blocks"
        resValue 'string', 'APP_NAME', "Blocks"
    }
    cloud {
        applicationId "com.example.cloud"
        resValue 'string', 'APP_NAME', "Cloud"
        signingConfig signingConfigs.release2
    }
    deck {
        applicationId "com.example.deck"
        resValue 'string', 'APP_NAME', "Deck"
        signingConfig signingConfigs.release3
    }
}

Solution 3 - Android

You would have to define the signingconfigs in your buildTypes. Add custom signing config to your debug build type or create a custom build type

    buildTypes {
        debug {
            applicationIdSuffix ".debug"
             signingConfig signingConfigs.custom
        }
        custom {
            applicationIdSuffix ".custom"
             signingConfig signingConfigs.custom
        }
        release {
             signingConfig signingConfigs.releaseConfig
        }
}

Gradle would create flavor for each build type and depending on the buildType the flavor would use the respective signinconfig. With the above configuration of build type , lets consider "apple" flavor. Gradle would create the following build variants just for apple

  • appledebug --> custom signing config

  • applecustom --> custom signing config

  • applerelease --> release signing config

    You can select the respective build variant and run your application

Adding signing config to flavor

productFlavors {
    def customSigningConfig = signingConfigs.custom

    custom {
        ...
        signingConfig customSigningConfig
        ...
    }

You need to declare your signingConfigs before you declare your flavors.

https://code.google.com/p/android/issues/detail?id=64701

Solution 4 - Android

I am not 100% sure this will work, but I dont think you want to create a new build type. That would create a new build variant for every flavor. When really you just want one flavor to override a "default config" :)

This code isnt tested but you should be able to do something along the lines of this:

signingConfigs {
    normal {
        storeFile file('key')
        storePassword "pass"
        keyAlias "alias"
        keyPassword "pass"
    }

    custom {
        storeFile file('custom_key')
        storePassword "pass"
        keyAlias "alias"
        keyPassword "pass"
    }
}

    /**
     *  defaultConfig is of type 'ProductFlavor'.
     *
     *  If we need to use a different signing key than the default,
     *  override it in the specific product flavor.
     */

    defaultConfig {
        versionCode 123
        versionName '1.2.3'
        minSdkVersion 15

        def standardSigningConfig = signingConfigs.normal

        buildTypes{
            release {
               signingConfig standardSigningConfig 
               zipAlign true
               // ...
            }
            debug { 
               //not sure you need this node
            }  
        }
    }
        

productFlavors {

    def customConfig = signingConfigs.custom
    def standardSigningConfig = signingConfigs.normal

    apple {
        applicationId "demo.apple"
    }
    banana {
        applicationId "demo.banana"
    }
    custom {
        applicationId "custom.signed.app"
        signingConfig customConfig
    }
}

Reference:
http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Product-Flavor-Configuration

Solution 5 - Android

One idea could be to use project properties in order to determine if you should or not use your custom signinconfig.

if (project.hasProperty('custom')) {
    android.signingConfigs.release = customSigningConfig
} else {
    //should use the default
}

Then to build your custom flavor you run:

gradle assembleCustomRelease -Pcustom=true

Solution 6 - Android

tl;dr go through "gradle.startParameter.taskNames" to look for the flavor and modify the variable.

I do this for test variants for the Vine app and it works out very nicely. You can also use this to make different dependencies compile without adding more flavor dimensions.

It would look something like this in your case.

            //root of buil.gradle OR probably inside buildTypes.release
            def signType = signingConfigs.normal;
            //You can put this inside builTypes.release or any task that executes becore
            def taskNames = gradle.startParameter.taskNames;
                taskNames.each { String name ->
                    if (name.contains("customFlavor")) {
                        signType = signingConfigs.custom
                    }
                }
            buildTypes{
                release {                   
                    signingConfig signType
                }
            }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRichard Le MesurierView Question on Stackoverflow
Solution 1 - AndroidRichard Le MesurierView Answer on Stackoverflow
Solution 2 - AndroidAshwinView Answer on Stackoverflow
Solution 3 - Androidrahul.ramanujamView Answer on Stackoverflow
Solution 4 - AndroidpjcoView Answer on Stackoverflow
Solution 5 - AndroidArnaudView Answer on Stackoverflow
Solution 6 - AndroidEdisonView Answer on Stackoverflow