In this article, I will present a totally new feature introduced by Gradle (in comparison with Ant) : the ability to build an app against different environments. I mean to be able to have (almost) the same flexibility as C preprocessor directives, giving us the ability to provide specific resources, or even classes, for a specific environment.

Use cases

These are several use cases where this function can be very useful :

  • In a industrialized environment, the back end providing web-services to an application will be running on several different instances, one instance for the productions and several instances for the development.  This way, developers are able to build and test new features on an instance which will not interfere with the one in production. On the mobile application point of view, it would often mean to use a different base URL to contact the server.
  • Sometimes, you want to propose a free and a paid version of your application, in this case it can be useful (isn’t it ? (: ) to use the same code and include only some part of the application in the free version.
  • You could also want to propose slightly different versions of your application for each country for, using specific resources for each version, like styles, colors, or fonts.

In this case, C preprocessor directives are perfect since we can assign different value s based on which environment has been defined. But there is sadly not such feature with Java. So we have to play with build tools to be able to do the same. Previously, Android app were build with the good old Ant build system. The fact is Ant is not able to do this task in decent conditions. For example, if we want just to be able to specify some properties for each environment you would have to wrote those kind of boilerplate XML files. But with Gradle, all became much more easier. This is the main topic of this article and I will present how to implement these kind of things in your own Android project (using Gradle of course).

Fork the example ! 

As usual, my articles do not come alone ;). I strongly recommend you to fork the following project, since all the examples I will present come from it. At the same time, you will be able to test yourself these awesome build variant features.

The Gradle way

The build variants are named “flavor” for Gradle. Define flavor will allow you to :

  • Use specific source code.
  • Use specific resources.
  • Use specific package id (allow you to install each flavor at the same time on the same device.
  • Use specific minimum, target SDKs and version code.

Basically a flavor is defined in the android closure in your Gradle file :

android {
    ...
    productFlavors {
        exactPi {
            applicationId 'vb.android.app.quality.exactPi'
        }

        approximationPi {
            applicationId 'vb.android.app.quality.approximationPi'
        }

        daggerMockedPi {
            applicationId 'vb.android.app.quality.daggerMockedPi'
        }

        mockWebServerPi {
            applicationId 'vb.android.app.quality.mockWebServerPi'
        }
    }
}

As you can see I defined 4 flavors. The first thing to know is that each flavor is the same object than the defaultConfig, meaning that, each flavor inherit the properties of your defaultConfig, and of course, you can override them. as I do for the applicationId. To know all the properties you can override, I strongly recommend you to read this documentation ;).

Nevertheless, I think you need at least to know what is the purpose of applicationId : it defined the id of your app, for your device, and for the Google Play Store. Previously, this id was based on the package defined in the manifest, but with Gradle this is no more the case. And that is a HUGE improvement over Ant. No need anymore to launch ugly XML script to parse the sources to replace the package when we want to have the prod and the dev version of an app at the same time on the same phone. Now, when you defined different applicationId, you are able to hold different versions of your app on your phone, and push them on the store.

Defining specific resources and sources

So now, we know how to define different flavors, and how to differentiate then through applicationId. So lets dive into more specific customization, and start by managing specific resources. Firstly, take a look at the folder hierarchy of the demo project :

flavors-res

As you can see, there are 7 folders inside the /src folder !

  • /main, which contains most of sources and resources of the project.
  • /androidTest, which contains the functional tests of your project.
  • /approximationPi, which contains the specific items of the approximationPi flavor. 
  • /daggerMockedPi, which contains the specific items of daggerMockedPi flavor.
  • /exactPi, which contains the specific items of daggerMockedPi flavor.
  • /daggerMockedPi, which contains the specific items of daggerMockedPi flavor.
  • /test, which contains the unit tests of your project.

The beauty is just here : you can defined whatever sources and resources you want inside these flavor folders. When you build your application, you have to choose a flavor, and all the content of its folder will be automatically merged with the main folder. In the example, you can see I define various specific java class, ressources like different ressources for each flavor. This let me having specific behaviour for each of my flavors.

Basically, you have always to define a flavor to work with (I will explain in the next paragraph how to do it), and the files of this flavor are merged with the files from the mail folder. So be careful, you can not define a version of the files which is already defined in a flavor in the main folder, since you always have to pick a flavor. This works exactly the same for .java classes (in the demo project, the class Constants.java is defined in the flavors).

Building those variants

As I said in the previous paragraph, if you defined flavor you automatically need to select one through Android Studio. To do so, just enable all the sub menus of Android Studio by clicking on the button at the left bottom of the window (in green in the example below :

flavors-choose

Then you can select the build variant you want to use. By the way you can see that a target is made of the flavor and the build type (remember, you are building a release version of your application when you publish it on the Google Play Store 😉 ). If you want to build your flavors through the CLI, just run for example :

gradle :app:assembleExactPiDebug

Conclusion

Be able to build flavors is  really an awesome feature which come along with Gradle. All that I just presented was of course totally feasible with Ant (I was doing this for professional and personal projects) but it was really annoying. Now it is very easy and very fast to build different versions of an app. As always, do not hesitate to ask me any questions relative to this subjects ;).

Go social !Tweet about this on TwitterShare on Google+Share on FacebookShare on LinkedInEmail this to someone