Product Flavors in Android

Droid By Me
4 min readOct 28, 2023

Imagine you are an ice cream vendor with a signature recipe. To delight your customers, you experiment with different flavors, creating a variety of new and exciting products. This concept is similar to how Android developers use product flavors to create different versions of their apps, each tailored to a specific audience, scenario, or requirement. Let’s delve into the intricacies of Product Flavors and their applications in this article.

The Significance of Product Flavors

When developing apps, there are times when customization and flexibility are essential. Product Flavors are a key tool for addressing these situations.

Consider the following examples:

  • White labeling: You are delivering a product to multiple clients, each with their own branding requirements, such as logos, colors, and styles. Product Flavors allow you to accommodate each client’s preferences using a single codebase.
  • Distinct endpoints: Your app communicates with various backend services through different API endpoints. Product Flavors make it easy to switch between endpoints, depending on the needs of different clients or environments.
  • Free and paid versions: Your app has both free and paid versions, each with its own set of features. Product Flavors let you efficiently manage the differences between these versions, ensuring a seamless user experience.

Unveiling Product Flavors

As per the official definition from developer.android.com, Product Flavors encompass different versions of a project that are designed to coexist on a single device, the Google Play store, or a repository. They facilitate the creation of app variants that share common source code and resources, while allowing differentiation in terms of features, resources, and configurations.

Configuring Product Flavors

Imagine you are developing an app with both free and paid versions. The build.gradle file is essential for configuring these variants. Using the productFlavors block, you can define unique properties for each flavor:

android {
namespace = "com.example.flavors"
compileSdk = 33

defaultConfig {
applicationId = "com.example.flavors"
minSdk = 27
targetSdk = 33
versionCode = 1
versionName = "1.0"
}
}

As per above config, your build-variants (build types) looks like this:

So, Product flavors let you output different versions of your project by simply changing the components and settings that are different between them. This lets you maintain a single codebase while tailoring the app for different use cases. For example, the free and paid flavors can have different application IDs, version codes, version names, and more.

Customizing Product Flavors

Beyond the basic configurations, Product Flavors offer the flexibility to fine-tune each variant.

Now based on the above ‘free’ and ‘paid’ specifications, you will create another version of the same app. So your build.gradle file will look like this:

android {
namespace = "com.example.flavors"
compileSdk = 33

defaultConfig {
applicationId = "com.example.flavors"
minSdk = 27
targetSdk = 33
versionCode = 1
versionName = "1.0"
}

productFlavors {
create("free") {
applicationId = "com.example.flavors.free"
// or applicationIdSuffix = ".free"
}
create("paid") {
applicationId = "com.example.flavors.paid"
// or applicationIdSuffix = ".paid"
}
}
}

As a result, your build-variants will look like this:

You can define more properties that enable you to cater to specific client needs while maintaining code consistency such as:

create("free") {
applicationId = "com.example.flavors.free"
versionCode = 2
versionName = "1.1"
minSdk = 28
targetSdk = 33
buildConfigField("String", "HOST_URL", "\"www.flavors.com/free\"")
manifestPlaceholders["enable_crashlytics"] = true
}

Diverse Build Variants

Build variants are essential in Android app development. By default, the primary build types are debug and release. Debug is used when running the app from the IDE directly onto a device. Release is used when creating a signed APK/AAB for publishing on the Play Store.

However, there are times when you need additional build variants, such as for QA testing or client previews. These build variants, combined with product flavors, provide a wide range of options for meeting different requirements. Whether you need to create personalized versions for clients, manage different API endpoints, or offer distinct app versions, product flavors streamline the development process. This can be achieved through the buildTypes block:

buildTypes {
// default
getByName("release") {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}

// default
getByName("debug") {
isMinifyEnabled = false
isDebuggable = true
applicationIdSuffix = ".debug"
android.buildFeatures.buildConfig = true
buildConfigField("String", "HOST_URL", "\"www.dev-flavors.com\"")
}

// created staging build-type
create("staging") {
initWith(getByName("debug"))
applicationIdSuffix = ".debugStaging"
buildConfigField("String", "HOST_URL", "\"www.staging-flavors.com\"")
}


// created qa build-type
create("qa") {
applicationIdSuffix = ".qa"
buildConfigField("String", "HOST_URL", "\"www.qa-flavors.com\"")
}
}

Now your build-variants look like this:

This is how you can create different versions of your app for different purposes, using a single code-base and different configuration.

--

--