How did I set up multiple flavors for an Android App under 5 minutes
Posted on July 18, 2017 in Development
Let's start with understanding few key terms.
Understanding differences between "Build Types", "Flavor" and "Build Variant"
***Build Types: Build Type refers to build and packaging settings like signing configuration for a project.
***Flavor: A flavor is used to specify custom features, minimum and target API levels, device and API requirements like layout, drawable and custom code (for example, if production code is slightly different than development code).
***Build Variant: The combination of Build Type and Flavor is known as Build Variant.
And, now time to dig deeper !
Android Apps: Flavors
Motivation
The motivation behind Android Flavors is code reuse and code maintainability. Time to time, we might want to publish different versions of the same app with slight changes in assets or functionality. For example, in free version of the app, you may want to show ads while in paid version, you may decide not to show ads and integrate in-app purchase or upfront price rather. That's where Android Flavors help us to achieve this flexibility.
Setting up Flavors in build.gradle
android {
flavorDimensions "version"
productFlavors {
freeVersion {
dimension "version"
}
paidVersion {
dimension "version"
}
}
}
These newly created flavors appears in "Build Variants" tab of Android Studio:
Note 1: You'll have to choose the configuration from "Build Variants" drop down menu before runnind the app on device/emulator.
Note 2: Starting Android Studion 3.0,
flavorDimension
attribute needs to be added.
Application Id
Each flavor can have its own application Id. An 'applicationId' makes a app in Play Store unique.
In this example, the free version will be published on Play Store with packageId/applicationId as com.pcc.flavors.free
and paid one will have com.pcc.flavors.paid
.
Note: I'll be showing build.gradle
with all the configuration until this point.
android {
flavorDimensions "version"
productFlavors {
freeVersion {
dimension "version"
applicationId "com.pcc.flavors.free"
}
paidVersion {
dimension "version"
applicationId "com.pcc.flavors.paid"
}
}
}
Configuring App's name
Each flavor can have its own name as well. For example, free version has app name shown to users
in Play Store as "Free Great App" and paid version has its name displayed in Play Store as "Paid Great App".
Let's see how this can be configured in build.gradle
.
android {
flavorDimensions "version"
productFlavors {
freeVersion {
//select the dimension of flavor
dimension "version"
//configure applicationId for app published to Play store
applicationId "com.pcc.flavors.free"
//Configure this flavor specific app name published in Play Store
resValue "string", "flavored_app_name", "Free Great App"
}
paidVersion {
dimension "version"
applicationId "com.pcc.flavors.paid"
resValue "string", "flavored_app_name", "Paid Great App"
}
}
}
Don't forget to use flavored_app_name
string resource from AndroidManifest.xml
to defined app's name:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.pcc.flavors">
<application
android:label="@string/flavored_app_name"
</application>
</manifest>
Flavor specific Icons for apps
Each differently named/flavored app may want to have its own icon. Lets see how would we achieve this.
First we have to create a flavor specific directory at the same level of main
. Basically, we need to mimic
the main
directory for each flavor to support fully functional flavors (when there's code changes are involved).
These directories must be named same as its flavor definition names. In our example, these two additional
directories are : freeVersion
and paidVersion
.
Make sure that you've the icon's name same as referenced from AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.pcc.flavors">
<application
android:icon="@mipmap/ic_launcher"
</application>
</manifest>
Finally, flavor some code !
It's very similar to flavoring icons for specific app. Remember that you've the same directory/package
structure across all the flavors. That's how the changes are overridden.
For demonstration purposes, I'll update TextView
widget text differently for each app. Free version's
TextView
will read "Hello Free Great App !", and Paid version will read : "Hello Paid App !".
It involves two steps:
1. Make sure that you've the same code directory structure.
2. Write your custom code !
Note: There's one gotcha though. You can't have the same class defined in src/main/java
and src/<flavorNmae>/java
directories. Gradle will throw Duplicate class error while building. Either you can have one class in src/main/java
or in other flavors. I've MainActivity2
in src/freeVersion/java
and src/paidVersion/java
, but not in src/main/java
. AndroidManifest.xml
has reference to MainActivity2
, so it picks MainActivity2
for a selected build variant's flavor.
Project structure would look like this:
Checkout the demo app in Github
Checkout this article on my blog