The new build system goals are:
A product flavor defines a customized version of the application build by the project. A single project can have different flavors which change the generated application.
Although different flavors could be very different applications, using Library Projects is a better use case for this, and the build system still supports this.
This new concept is designed to help when the differences are very, very minimum, for instance when using Google Play’s multi-apk support (e.g. the difference could be only gl textures compressed using a different format.)
If the answer to “Is this the same application?” is yes, then this is probably the way to go over Library Projects.
Product flavors can customize the following properties:
A project starts with a default Configuration. All the above properties can be set and it has its own source code, resources and manifest.
If the project does not create product flavors, then the application is built from this default configuration.
When a project declares Product Flavors, these extends the main configuration.
The source code of the product flavor is used in addition to the source code of the main configuration (1).
The resources of the product flavor overrides the resources of the main configuration.
The Manifest of the product flavor is merged on top of the Manifest of the main configuration.
(1) This allows some flexibility but also adds some restrictions:
Note about the AndroidManifest attributes that can be set through the default Configuration or the flavor configurations:
Values present in the manifest file will be overridden with the values coming from the build configuration. All values, except for the package name can be omitted from the manifest file.
A build type allows configuration of how an application is packaged for debugging or release purpose.
This concept is not meant to be used to create different versions of the same application. This is orthogonal to Product Flavor.
A Build Type provides configuration for the following build properties:
For instance, one could make a Build Type that uses Proguard but creates a debuggable apk.
(2) This is appended to the manifest package name. The goal here is to allow having different build types create different apks that can all be installed at the same time. This is optional.
Like Product Flavors, Build Types can provide their own source code, resources and manifest.
The typical use cases are:
The source code and resources provided by the Build Types affects the project the same way Product Flavors do.
We’ve seen Product Flavors and Build Types and how both configure the output of a project.
In fact, the output of a project can only be the cross product of the Build Type and, if applicable, the Product Flavor. This is call a build variant.
If product flavors are defined, it is not possible to omit them.
For a project not customizing any Build Type or Product Flavor, the available build variants are debug and release versions, as the default configuration is implied.
However, if a project declares two flavors, for instance free and forpay, the available build variants are
We have seen above how source code and resources provided by Build Types and Product Flavors extend or override the main configuration. When actually building an app, the Build Type and Product Flavor are both applied with the following rules:
All the source folders are used together (default config, build type, product flavor, and generated source code(4)) to create a single output.
This means the same restrictions mentioned above applies, with the addition that Build Types and Product Flavors cannot provide different versions of the same class.
(4) generated source is output from resource compilation (R.java), aidl and renderscript compilation, and things like BuildConfig which can be impacted by the BuildType. These are different per build variants.
Resources combination uses the following priority (lower number is higher priority and override higher number):
We’ve seen how variants are created from a Build Type and a Product Flavor. In some case it is useful to be able to have several dimensions of flavors. This is particularly useful when only packaging is impacted to use the multi-apk support in the Play Store.
For instance, let’s imagine a game that has GL texture for different formats, and has native component for arm, x86 and mips. Such a project could use a flavor dimension for the GL textures and one for the ABI to package.
Flavor groups are first defined. The order is important as it impacts Android resource priority.
Then each flavor is assigned to a group.
Variant are then created from each combinations of Build Types and Product Flavor Group.
Here’s an example giving us all the variant for 2 Texture formats and 2 ABIs.
Due to Build Types and Product Flavors all providing their own sources, resources and manifest, the project structure need to change from the root level src/res/manifest used in the current build system.
Instead the build system moves to a top level src folder, containing folders for each build types, flavors as well as default config, and tests for each flavors. Each of those sub folders are self-contained for the element they represent and can contain a manifest, java source code, resources, etc...
A typical project will then have the following folder structure:
With possibly multiple Product Flavors it is important to test all of them.
The test projects are now part of the main projects. Sourcesets containing tests for the default configuration and each flavors are automatically used, and a test application is generated for each variant.
For a project with several flavors, the structure of the source folders will look like:
The test applications are meant to run against a given Build Type variant. It is the “debug” variant by default, but it can be configured.
Library Projects are built in a very similar way to regular projects with a few exceptions.
Testing the library is important and this is done through the test component of the project. However, unlike a normal project, this component doesn’t generate a separate application from only its source set. Instead it implicitly references the library itself and packages it in its own apk.
This build is always a debug build.
When the Library Project is built and packaged into a distribution blob, then the build is always a release build.
Libraries can be packaging as binary bundle. These can be uploaded to online repository (Maven or Ivy) and reused by other projects.
They can also be used directly as part of a multi-project setup.
This is planned but it not available at the moment.