Preface: this is not a question about how to use build types and product flavors in an Android app. I understand the basic concepts involved. This question is more about trying to understand which configuration should be specified in a build type, which configuration should be specified in a product flavor, and whether any distinction is actually necessary.
This week, I’ve been learning more about gradle configuration for Android apps. I initially thought I had a good handle on build types vs product flavors, but the deeper I got into the documentation the more I realized the distinction between the two was not clear to me at all.
Since there is a well-defined hierarchy (in the sense that properties specified in build types take precedence over those specified in product flavors), I don’t understand why there is a need to distinguish between build types and product flavors at all. Would it not be better to merge all properties and methods into the product flavor DSL object, and then just treat build type as a (default) flavor dimension?
Some concrete examples that led to my confusion:
signingConfigproperty can be set in both build types and product flavors… but
minifyEnabled(and, I assume,
shrinkResources?) can only be configured in build types.
applicationIdcan only be specified in product flavors… and
applicationIdSuffixcan only be specified in build types!?
The actual question(s):
Given the above examples: is there a clear distinction between the roles of build types vs product flavors?
If so, what is the best way to understand it?
If not, is the plan to eventually merge build types and product flavors into a single configurable DSL object?
Expanding on what @CommonsWare said in the comments, the basic idea is that build types are for different builds of your application that aren’t functionally different — if you have a debug and release version of your app, they’re the same app, but one contains debugging code, maybe more logging, etc., and the other is streamlined and optimized and possibly obfuscated via ProGuard. With flavors, the intent is that the app is notably different in some way. The clearest example would be a free vs. a paid version of your app, but developers may also differentiate based on where it’s being distributed (which could affect in-app billing API use).
There are developers that make many, many different versions of a similar app for different customers — an example might be a simple app that opens up a web page in a web view, with different URLs and branding for each version — this is a good use of flavors.
To reiterate, if it’s “the same application”, modulo some differences that aren’t important to the end user, and especially if all of the variants except for one are for your own testing and development use and only one variant will be deployed to end users, then it’s a good candidate for build types. If it’s “a different” application and multiple variants would be deployed to users, then perhaps it’s a candidate for a product flavor.
You’ve already seen that there are some functionality differences between build types and flavors, in that some options are supported for one but not the other. But the concepts are different even though they’re similar, and there’s no plan to merge them together.
buildType configure how we package our app
Flavor configure different classes and resources.
in Flavor1 your MainActivity can do something, and in Flavor2 different implementation
differente App name
Each product flavor can have its own values of the following properties, among others, which are based on the same properties from
Here’s how I distill the difference down to its essence:
buildTypeis the how of the build.
flavoris the what of the build.
build types are used to indicate
debug/release mode with different certificates and enabling
flavors are used to have custom features (for example free or paid version),
minimum and target API levels, device and API requirements like the
drawable so you can have different code and resources in different