I am developing an Android application using Android Studio (v 2.1, gradle plugin v 2.1.0). My application has various versions which share a lot of common code so I decided to use flavor dimensions and product flavors to customize code and resources when and where it is requested. This worked fined as long as I only had two flavor dimensions. As an example, my app.gradle
was
… flavorDimensions "fruit", "color" productFlavors { apple { dimension "fruit" } pear { dimension "fruit" } red { dimension "color" } yellow { dimension "color" } } …
and my src
folder was
src/ appleRed/ appleYellow/ pearRed/ pearYellow/
each one with a custom version of my code. Again, as an example
src/ appleRed/java/com/example/ExampleFragment.java appleYellow/java/com/example/ExampleFragment.java pearRed/java/com/example/ExampleFragment.java pearYellow/java/com/example/ExampleFragment.java
of course, there is no instance of ExampleFragment
in src/main
.
At some point during development, I had to include a free and a paid version of the app. I thought that it could be easily achieved by adding a new flavor dimension named version
and two product flavors named free
and paid
:
… flavorDimensions "fruit", "color”, “version” productFlavors { apple { dimension "fruit" } pear { dimension "fruit" } red { dimension "color" } yellow { dimension "color" } free { dimension "version" } paid { dimension “version” } } …
but all of a sudden the custom code generated by the combination of fruit
and color
was not detected by Android Studio anymore. So no appleRed
, appleYellow
, pearRed
nor pearYellow
can be used to have custom code and the only way I was able to regain my configuration was to use all the combinations of all the three flavour dimensions:
src/ appleRedFree/java/com/example/ExampleFragment.java appleRedPaid/java/com/example/ExampleFragment.java appleYellowFree/java/com/example/ExampleFragment.java appleYellowPaid/java/com/example/ExampleFragment.java pearRedFree/java/com/example/ExampleFragment.java pearRedPaid/java/com/example/ExampleFragment.java pearYellowFree/java/com/example/ExampleFragment.java pearYellowPaid/java/com/example/ExampleFragment.java
This is not good because ExampleFragment
is duplicated across the same fruitColor*
combination (appleRedFree
, appleRedPaid
have the same ExampleFragment
). Same problem happens for resources (the ones in res
folder).
My questions are:
1) Is this the expected behaviour from gradle in Android Studio (i.e., not being able to combine a subset of product flavors, following their priority based on their dimension, when having more than two flavour dimensions)?
2) Given the fact that this is the expected behaviour, is there another way I can achieve my customisation without duplicated code or without having a single file with an if-statement inside (e.g., if (BuildConfig.FLAVOR_version == "free") ...
) ?
Please note that I’m talking about having custom code which could be complex, so I’m not asking for basic customisation like a build config variable, variant filtering, or something like that.
The flavor dimensions define the cartesian product that will be used to produce variants. Example: flavorDimensions("dimA", "dimB") productFlavors { row1 { ... dimension = "dimA" } row2 { ... dimension = "dimA" } row3 { ... dimension = "dimA" } col1 { ...
When to use Product Flavors. When we want to address the issue of having separate project code for each version of the app while still having one project code. Given a scenario where you have a free and a paid app you can limit features in the free and expose all the other features in the paid version of the app.
A flavorDimension is something like a flavor category and every combination of a flavor from each dimension will produce a variant. In your case, you must define one flavorDimension named "type" and another dimension named "organization".
You want to use same extra source directory for some flavors;
appleRedFree + appleRedPaid --> src/appleRed
pearRedFree + pearRedPaid --> src/pearRed
appleYellowFree + appleYellowPaid --> src/appleYellow
pearYellowFree + pearYellowPaid --> src/pearYellow
You can set sourceSet for your flavors:
android { // Other stuff here flavorDimensions "fruit", "color”, “version” productFlavors { apple { dimension "fruit" } pear { dimension "fruit" } red { dimension "color" } yellow { dimension "color" } free { dimension "version" } paid { dimension “version” } } sourceSets { appleRedFree { java.srcDirs = ['src/main/java', 'src/appleRed/java'] } appleRedPaid { java.srcDirs = ['src/main/java', 'src/appleRed/java'] } appleYellowFree { java.srcDirs = ['src/main/java', 'src/appleYellow/java'] } appleYellowPaid { java.srcDirs = ['src/main/java', 'src/appleYellow/java'] } pearRedFree { java.srcDirs = ['src/main/java', 'src/pearRed/java'] } pearRedPaid { java.srcDirs = ['src/main/java', 'src/pearRed/java'] } pearYellowFree { java.srcDirs = ['src/main/java', 'src/pearYellow/java'] } pearYellowPaid { java.srcDirs = ['src/main/java', 'src/pearYellow/java'] } } // Other stuff here }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With