September 19, 2023 in Mobile App Development

Android Flavors

A typical normal day at work
 The QA team has asked me to upload a version of one of the apps we are working on to start testing it. When it comes to development and testing apps, we use Firebase App distribution. Moreover, we let the apps point to the corresponding Staging-Backend Endpoints Base URL. It is worth mentioning that we display some test values in the app for development and testing purposes to ensure a smooth testing process. Okay
 Lucky us, the QA team approved the app and gave us the green light to release it to the Playstore.Yaay! It’s a happy story, yes? Hmm. Not really! Here comes the nightmare. To prepare a production build of the app, we have to let the app point to the Production-Backend Endpoints Base URL. Moreover, we have to hide all of the aforementioned unwanted values.

That is how I used to spend my working days up until I stumbled upon the Product Flavors. Product flavors are a powerful feature of the Gradle plugin from Android Studio to create customized versions of products. They form part of what we call Build Variants.

Build Variants

Simply, it is exposing your app in different versions or flavors by keeping only a single project.

By default, in every project, there are two options debug and release, as shown in Figure 1.

Figure 1

Configuring Android Builds in your application

In this article, I will demystify how to configure builds in Android. By the end of the article, we will be having:

1- Three different environments, namely Dev, Stg, Production

2- Three different values for the same Base API URL variable

3- Three different values for the same ApplicationID reflecting each environment.

4- A unique Version code and A Version name for every build.

Figure 2. shows how to create a new directory named Config in the project root directory.

Figure 2

In the Config directory, we create three files. dev. properties, stg. properties and prod.properties.

https://alyabdelshafy.medium.com/media/4ee5b8d522e59845037304876341cbd9Figure 3

The config files are plain texts used for supplying build settings and other configurable properties to the Gradle build systems without changing the source code.

Please note that the config files’ content is in the form of key-value and supports different types such as boolean, string, integer.

The three subsequent figures show how we added four variables in each file of the three; APPLICATION_ID, BASE_URL, VERSION_CODE, and VERSION_NAME.

stg.properties

https://alyabdelshafy.medium.com/media/6071e41d19e7b3004ae2d2ed6b80f011Figure 4

dev.properties

https://alyabdelshafy.medium.com/media/019de177c933309c2799e09449fa278bFigure 5

prod.properties

https://alyabdelshafy.medium.com/media/6071e41d19e7b3004ae2d2ed6b80f011Figure 6

Read configuration based on .properties file

After adding the config files, let see how to let Gradle read those configurations. For example, the APPLICATION_ID

Furthermore, let me highlight that values like VERSION_CODE, VERSION_NAME can be changed in our build.gradle file at the build time.

Figure 7. shows how to add an ext (ExtraPropertiesExtension) entry.

https://alyabdelshafy.medium.com/media/8903a43b1bd16e7062f2226a06aa29f8Figure 7

Let’s pay a closer look at the previous code. Yeah, we are getting the current build flavor and read the corresponding .properties file located in the config directory and save it in the config variable. We also have two methods in the previous code
1- getCurrentFlavor()
2- getProps(Path)

getCurrentFlavor() extracts the flavor name from one of the Gradle tasks and returns. It uses a regex to do this job.

https://alyabdelshafy.medium.com/media/cac7185b3c3b8f72fc56ed17ba954c75

getProps(Path) reads a properties file from a given path and returns its contents.

https://alyabdelshafy.medium.com/media/8d1fb1f1861f9fb4448f11429b9619f1

Changing the properties in Build.gradle file

The following step highlights how we can change the properties like APPLICATION_ID, BASE_URL in our build.gradle file at the build time.

Let’s open the app (module) level build.gradle as shown in Figure 7.

Figure 7

Under the android block, we add flavorDimensions and productFlavors properties. Here, I am specifying our build flavors to contain three flavors as the following Figure 8.

https://alyabdelshafy.medium.com/media/9aa3a65819c4b7e665bb174f29dbb916Figure 8

In the previous code, we also read the .properties file in the respective flavor and assign the value to applicationId, versionCode, and versionName fields. Let’s examine the above lines a bit. We are substituting applicationId using envConfig.APPLICATION_ID.replace(“””, “”). Here we are using the app-id specified in the respective config file. All our config property values are specified as a string within double-quotes. Gradle generates the BuildConfig.java file on the fly while building and uses the values specified in the substitutions. Hence, we make sure to strip double-quotes using replace(“””, “”).

versionCode is an integer and is substituted with the value of VERSION_CODE by converting the string value to an integer.

Figure 9 shows how we can change the properties under defaultConfig.

We are iterating over the Config key-value pairs read from the properties file and adding them as build config fields.

Please note that the if condition prevents us from adding duplicate entries into BuildConfig.java, as versionCode, versionName and applicationId are already part of build.gradle.

https://alyabdelshafy.medium.com/media/743b03870828d45f6f3f1f7ab9daf7a5Figure 9

Now that our configs are added as build configs

Figure 10 shows how we can access them in the code. Open MainActivity.kt file and add the below lines in the onCreate method.

https://alyabdelshafy.medium.com/media/4b13ac9498ba6ee4da0e69179c0f4f2eFigure 10

Select Build Variants tab from sidebar and select devDebug as the variant as shown in Figure 11.

Figure 11

Run the app to see the logs as shown in Figure 12.

Figure 12

Finally ????????, we are changing the config variables values depend on each flavor, and you can use it wherever you want in your code

Renaming the app according to each flavor

By default, in Android, the app name is specified as a string resource in AndroidManifest.xml file like android:label=”@string/app_name” under the application tag.

We can specify the app name as a string resource in the build.gradle file. We do this in the productFlavors block we defined earlier, as shown below.

Figure 13

Note: To avoid duplicate values for the app_name, make sure to remove the default app name inside the main/res/values/strings.xml file.

If we now run all the flavors, below is how it would look like:

Interesting, yes! We finally did it.

Where to Go From Here?

The above article is just an example of how you can use flavors, but there are many more. For example, you can also use them to ease up implementing your free and paid versions of your app.

If you want to learn more, have a look at the link below:

This article was only the first of a series of upcoming articles on optimizing our day-to-day coding situations



By browsing this website, you agree to our privacy policy.
I Agree