A Deep Dive into Android Product Flavors and Build Variants for Enhanced App Development

Table of Contents

In Android development, product flavors allow you to create different versions of your app with different configurations, resources, and code, but with the same base functionality. Product flavors are used when you want to create multiple versions of the same app that differ in some way, such as a free and a paid version, or versions for different countries or languages.

For example, suppose you are creating a language-learning app that supports multiple languages, such as English, Spanish, and French. You could create three different product flavors, one for each language, and configure each flavor to include the appropriate language resources, such as strings, images, and audio files. Each flavor would share the same core codebase but would have different resources and configurations (or consider ABC 123 Learn and Akshar Learn apps, for which I am handling these use cases).

Android Product Flavors

Product flavors are defined in the build.gradle file of your app module. You can define the configuration for each flavor, including things like applicationId, versionName, versionCode, and buildConfigField values. You can also specify which source sets to include for each flavor, which allows you to create different versions of the app with different code, resources, or assets.

Build variants, on the other hand, are different versions of your app that are created by combining one or more product flavors with a build type. Build types are used to specify the build configuration, such as whether to enable debugging or optimize for size, while product flavors are used to specify the app’s functionality and resources.

For example, if you have two product flavors, “free” and “paid”, and two build types, “debug” and “release”, you would have four different build variants: “freeDebug”, “freeRelease”, “paidDebug”, and “paidRelease”. Each build variant would have its own configuration, resources, and code, and could be signed with a different key or configured for different deployment channels.

Resource Merging & Flavor Dimensions

Resource merging is an important part of using product flavors in Android development. When you have multiple product flavors with their own resources, such as layouts, strings, and images, the Android build system needs to merge them together to create the final APK.

Here’s an example of how resource merging works with product flavors:

Kotlin
android {
    // Define the flavor dimensions
    flavorDimensions "language", "version"
    
    // Define the product flavors
    productFlavors {
        englishFree {
            dimension "language"
            applicationId "com.softaai.app.en"
            resValue "string", "app_name", "My App (English)"
        }
        spanishFree {
            dimension "language"
            applicationId "com.softaai.app.es"
            resValue "string", "app_name", "Mi Aplicación (Español)"
        }
        pro {
            dimension "version"
            applicationId "com.softaai.app.pro"
            resValue "string", "app_name", "My App Pro"
        }
        free {
            dimension "version"
            applicationId "com.softaai.app.free"
            resValue "string", "app_name", "My App Free"
        }
    }
}

In this example, we have two flavor dimensions, “language” and “version”. We define four product flavors, “englishFree”, “spanishFree”, “pro”, and “free”, each with their own application ID and app name.

Well, What is Flavor Dimension?

Flavor dimension is a concept in Android Gradle build system that allows the grouping of related product flavors. It is used when an app has multiple sets of product flavors that need to be combined together. For example, if an app is available in multiple countries and each country has multiple build types, then we can use flavor dimensions to group the country-specific flavors together

When we build the app, the Android build system will merge the resources for each product flavor into the final APK. For example, if we have a layout file called “activity_main.xml” in the “res/layout” folder for both “englishFree” and “spanishFree”, the build system will merge them into a single “activity_main.xml” file that includes the appropriate resources for each language.

Now, let’s take a look at how we can use flavor dimensions to create more complex combinations of product flavors:

Kotlin
android {
    // Define the flavor dimensions
    flavorDimensions "language", "version"
    
    // Define the product flavors
    productFlavors {
        en {
            dimension "language"
            applicationId "com.softaai.app.en"
            resValue "string", "app_name", "My App (English)"
        }
        es {
            dimension "language"
            applicationId "com.softaai.app.es"
            resValue "string", "app_name", "Mi Aplicación (Español)"
        }
        pro {
            dimension "version"
            applicationId "com.softaai.app.pro"
            resValue "string", "app_name", "My App Pro"
        }
        free {
            dimension "version"
            applicationId "com.softaai.app.free"
            resValue "string", "app_name", "My App Free"
        }
        enPro {
            dimension "language"
            dimension "version"
            applicationId "com.softaai.app.enpro"
            resValue "string", "app_name", "My App Pro (English)"
        }
        esPro {
            dimension "language"
            dimension "version"
            applicationId "com.softaai.app.espro"
            resValue "string", "app_name", "Mi Aplicación Pro (Español)"
        }
    }
}

In this example, we have two flavor dimensions, “language” and “version”, and six product flavors. The “en” and “es” flavors represent the English and Spanish versions of the app, while the “pro” and “free” flavors represent the paid and free versions of the app. We also define two additional product flavors, “enPro” and “esPro”, which combine both language and version dimensions.

When we build the app, the Android build system will merge the resources for each product flavor into the final APK. For example, if we have a layout file called “activity_main.xml” in the “res/layout” folder for both “en” and “es” flavors, the build system will merge them into a single “activity_main.xml” file that includes the appropriate resources for each language. Similarly, if we have a string resource called “app_name” in the “pro” and “en” flavors, the build system will merge them into a single “app_name” resource that includes the appropriate version and language.

We can also use flavor dimensions to create more complex combinations of product flavors. In the example above, we define two additional product flavors, “enPro” and “esPro”, which combine both language and version dimensions. This means that we can create four different versions of the app: “enFree”, “esFree”, “enPro”, and “esPro”, each with their own application ID and app name.

Here’s an example of how we can reference resources for different flavor dimensions in our code:

Kotlin
// Get the app name for the current flavor
String appName = getResources().getString(R.string.app_name);

// Get the app name for the "enPro" flavor
String enProAppName = getResources().getString(R.string.app_name, "en", "pro");

// Get the app name for the "esFree" flavor
String esFreeAppName = getResources().getString(R.string.app_name, "es", "free");

In this example, we use the getResources() method to get a reference to the app’s resources. We then use the getString() method to get the app name for the current flavor, as well as for the “enPro” and “esFree” flavors, which have different values for the “language” and “version” dimensions.

Pre-Variant Dependencies

When we use product flavors and flavor dimensions to create different variants of our app, we may also need to use different dependencies for each variant. This is where pre-variant dependencies come into play.

Pre-variant dependencies are dependencies that are defined outside of the product flavors and flavor dimensions. These dependencies are applied to all variants of the app, regardless of the product flavor or flavor dimension. We can define pre-variant dependencies in the build.gradle file, outside of the productFlavors and flavorDimensions blocks.

Here’s an example of how we can define pre-variant dependencies:

Kotlin
dependencies {
    // Pre-variant dependencies
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.appcompat:appcompat:1.4.1'

    // Flavor-specific dependencies
    flavorDimensions 'version', 'language'
    productFlavors {
        pro {
            dimension 'version'
        }
        free {
            dimension 'version'
        }
        en {
            dimension 'language'
        }
        es {
            dimension 'language'
        }
    }

    // Dependencies for specific flavor dimensions
    enImplementation 'com.squareup.retrofit2:retrofit:2.9.0'
    esImplementation 'com.squareup.okhttp3:okhttp:4.9.3'
    proImplementation 'com.google.firebase:firebase-crashlytics:18.4.1'
}

In this example, we define two pre-variant dependencies: com.google.android.material:material:1.5.0 and androidx.appcompat:appcompat:1.4.1. These dependencies will be applied to all variants of the app, regardless of the product flavor or flavor dimension.

We then define four product flavors, two for the “version” dimension and two for the “language” dimension. We also define flavor-specific dependencies for each flavor dimension. For example, we define enImplementation 'com.squareup.retrofit2:retrofit:2.9.0' for the “en” flavor, which means that this dependency will only be applied to variants that include the “en” flavor.

Finally, we define a pro-variant dependency using the proImplementation keyword. This dependency will be applied only to variants that include the “pro” flavor.

Summary

Overall, product flavors and build variants provide a powerful and flexible way to create different versions of our Android app for different use cases. By combining different flavors and types, we can create highly customizable builds that meet the specific needs of our users.

Skill Up: Software & AI Updates!

Receive our latest insights and updates directly to your inbox

Related Posts

error: Content is protected !!