I have been struggling for a while with gradle and build variants.
I have these build types defined:
And these fl
I have been struggling with the same problem. At first I used two branches in my source control, but that was a head ache keeping them in sync. Gradle is a very flexible build system, but the default conventions are not always enough. Here is how I finally resolved it in my code base.
I ended up with essentially the following directory structure (simplified):
+ src
+ main
| + res
| | + values
| | - strings.xml
| + java
| ...
+ debug
| + free
| | + res
| | + values
| | - strings.xml
| + paid
| + res
| + values
| - strings.xml
+ free
| + res
| | + values
| | - strings.xml
| + java
| ...
+ paid
+ res
| + values
| - strings.xml
+ java
...
In the main folder I keep everything that is common for both flavors. In the free folder I keep everything that is unique for the free version (same for paid). The files in the flavor folder will be overlaid on top of main.
The default overlay rules will handle the product flavors "free" and "paid" by using the folders under "src" with the same names. The problem for me started starts with the overlay of build types.
If I created a debug folder with the same structure as the flavor folders it would be overlaid on top of the currently used flavor folder. That led to the same debug-name for both flavors, but I wanted different debug names depending on flavor. After some research I came up with the following modification to my build file.
...
android {
buildTypes {
debug {
...
}
release {
...
}
}
productFlavors {
free {}
paid {}
}
}
android.applicationVariants.all { variant ->
if (variant.buildType.name == "release") {
...
}
else if (variant.buildType.name == "debug") {
switch (variant.name) {
case "FreeDebug":
variant.mergeResources.doFirst {
android.sourceSets.debug.setRoot("src/debug/free")
}
break;
case "PaidDebug":
variant.mergeResources.doFirst {
android.sourceSets.debug.setRoot("src/debug/paid")
}
break;
}
}
}
...
Now the build variant will be built by first overlaying the following folders:
PaidRelease -> /src/main + /src/paid
PaidDebug -> /src/main + /src/paid + /src/debug/paid
FreeRelease -> /src/main + /src/free
FreeDebug -> /src/main + /src/free + /src/debug/free
The folder structure while creating build variants should be:
app
|
->src
|
->buildvariantname1(as defined in gradle)
|
->java (follow the same structure here, as in main folder)
->res (follow the same structure here, as in main folder)
Now on selecting the specific variant, like buildVariantname1debug, the changes written in the res folder under this variant will be selected.
The app name should be defined under string.xml under res->values folder so that the app name gets fetched depending upon the value in the xml under each build variant. Same goes for app icons.
First image shows how to declare build variants(flavors with different package names)
The second image shows, how the project structure looks like if you want each flavor to have a different code, drawables and manifest as well. Keep in mind MainActivity is deleted from the main folder so that it can exist in each build variant
As per the Gradle Sourcesets and Dependencies guide, you can add a new folder src/freeDebug/res
or src/paidRelease/res
, etc to customize particular attributes for each Build Variant.