Adding ‘Flavor’ to your App
In the world of white labelled Apps, we come across situations where we need to build Apps with almost similar features but the branding differs. Also, you may wish to publish different versions of same App e.g. basic and pro. Here, maintaining multiple repositories of every App does not seem feasible as this may result in code maintenance as well as code duplication issue.
This problem of code maintenance and duplication for white labelled Apps or versioned Apps could be solved with ‘Product Flavors’.

Consider we have to publish the 2 Apps - ‘VanillaApp’ and ‘ChocoApp’. Each of the App has same features. But the branding and theming is different for each App.
Let’s start with flavor declaration. In build.gradle of the app module need to declare package name of each App.
productFlavors{
vanilla{
applicationId "com.factory.vanilla"
flavorDimensions "versionCode"
manifestPlaceholders = [FILE_PROVIDER_AUTHORITIES: "com.factory.vanilla.fileprovider"]
}
choco{
applicationId "com.factory.choco"
flavorDimensions "versionCode"
manifestPlaceholders = [FILE_PROVIDER_AUTHORITIES: "com.factory.choco.fileprovider"]
}
}Here, flavorDimension is useful to form combination of flavor and specified flavorDimension category.
manifestPlaceholders come handy when we need to explicitly provide flavor specific manifest arguments. FileProvider is one of the example.
Now, let’s modify the directory structure.
app
| — main/kotlin/com.factory.choco
| — main/res
| —vanilla/kotlin/com.factory.vanilla
| — vanilla/res/
| — choco/kotlin/com.factory.choco
| — choco/res
Respective sourceSets needs to be specified in build.gradle as below, so that respective class files for a flvaor will be picked from directory mentioned in sourceSets path.
sourceSets {
main.java.srcDirs = ['src/main/kotlin']
vanilla.java.srcDirs = ['src/vanilla/kotlin']
choco.java.srcDirs = ['src/choco/kotlin']
debug.java.srcDirs = ['src/debug/kotlin']
test.java.srcDirs = ['src/test/kotlin']
androidTest {
java.srcDirs = ['src/androidTest/kotlin']
res.srcDirs = ['src/androidTest/res']
}
}The resources files pertaining to a flavor should be added within it’s directory. These resources will be used when respective flavor build is generated.
e.g. <string name=”app_name”>Vanilla App</string> specified in resources of vanilla directory will be picked for vanilla flavor of the App and so on. Common resources needs to go inside main directory.
Similar rule needs to be followed for class files. Class files which are common to both flavors needs to be inside main directory. But, when there is a different implementation for each flavor either of below approaches can be followed.
1. Conditional programming using param from Build.config
2. Add separate classes in flavor specific directory with same name.
In first case, class file needs to be in main directory, but in second case specific class file needs to be removed from main directory and then added to respective flavor directories.
Note : Maintain similar path structure in both directories while adding classes separately to avoid import issues while building.
In case of white labelled Apps, we can sign each flavor separately with release, debug buildTypes in signingConfig block as below.
signingConfigs {
vanillarelease {
storeFile file("keys/release1.keystore")
storePassword "vanillapwd"
keyAlias "vanillaAlias"
keyPassword "pwd"
}
vanilladebug {
storeFile file("keys/debug1.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
} chocorelease {
storeFile file("keys/release2.keystore")
storePassword "chocopwd"
keyAlias "chocoAlias"
keyPassword "pwd"
}
chocodebug {
storeFile file("keys/debug2.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
}
After this set up is ready, Build the project. Set of BuildVariants will be generated as per flavors. Select required BuildVariant and click Run and you will have the required App running.
Hope this was useful!
