Gradle flavors for android with custom source sets - what should the gradle files look like?
I think you'd be better off not defining custom sourceSets
but using the default gradle configuration. I used to do custom sourcesets until I realized the conventions are, well, convenient.
You'll want something like this:
+ src
+ main // this is your common code
+ java
+ res
+ flavor1
+ java
+ res
+ flavor2
+ java
+ res
Then you can just go ahead and remove the sourcesets closure from your build.gradle
NOTE: For the gradle
configuration, resources are merged or overridden whereas all java
code is put on the same class-path. For example, the AndroidManifest.xml
files for each flavor need only have the differences from main
's manifest file. Having an asset, for example, ic_launcher
in a flavor overrides the ic_launcher
from main if such file exists. However, having a file HomeActivity.java
in both main
and the flavor is not possible and will give a duplicate file error.
Including and excluding source sets for different flavors in Android Studio
It works in a slightly different structure:
sourceSets {
main {
java.srcDir 'path_to_my_dir/common'
}
flavor1 {
java.srcDirs += [
'path_to_my_dir/feature1'
]
}
flavor2 {
java.srcDirs += [
'path_to_my_dir/feature2'
'path_to_my_dir/feature3'
]
}
}
Using Build Flavors - Structuring source folders and build.gradle correctly
If you got in the Studio preferences, under the Gradle section, you can enable auto-import for your project (we'll enable this by default later). This will let Studio re-import your build.gradle whenever you edit it.
Creating flavors doesn't mean you're going to use custom code for them so we don't create the folders. You do need to create them yourself.
If you look at my IO talk you'll see how we mix in together values from the flavors and build type to create the variant.
For the Java source:
src/main/java
src/flavor1/java
src/debug/java
are all 3 used to create a single output. This means they can't define the same class.
If you want to have a different version of the same class in the two flavor you'll need to create it in both flavors.
src/flavor1/java/com/foo/A.java
src/flavor2/java/com/foo/A.java
And then your code in src/main/java can do
import com.foo.A
depending on the flavor selected, the right version of com.foo.A is used.
This also means both version of A must have the same API (at least when it comes to the API used by classes in src/main/java/...
Edit to match revised question
Additionally, it's important to put the same A class only in source folders that are mutually exclusive. In this case src/flavor1/java and src/flavor2/java are never selected together, but main and flavor1 are.
If you want to provide a different version of an activity in different flavor do not put it in src/main/java.
Do note that if you had 3 flavors and only wanted a custom one for flavor1, while flavor2 and flavor3 shared the same activity you could create a common source folders for those two other activities. You have total flexibility in creating new source folders and configuring the source set to use them.
On to your other points:
It's normal that the 2nd flavor source folder is not blue. You need to switch to the 2nd flavor to enable it, and then you'll be able to create packages and classes inside. Until then, Studio doesn't consider it to be a source folder. We'll hopefully improve this in the future to make the IDE aware of those unactive source folders.
I think it's also normal that you can't create resource files in the res folder. The menu system hasn't been updated to deal with all these extra resource folders. This will come later.
Making two build flavors use the same res file in Gradle Kotlin DSL?
sourceSets {
getByName("FlavorB").res.srcDirs(
"src/flavorb/res"
)
}
Build.gradle flavor sources
Instead of configuring sourceSets
within the productFlavors
block, try:
productFlavors{
flavor1{
}
flavor2{
}
}
sourceSets{
main{
java.srcDirs = ['src/main']
//other typical sourceSets stuff
}
flavor1.java.srcDirs = ['src/flavor1']
flavor2.java.srcDirs = ['src/flavor2']
}
Android flavors, Gradle sourceSets merging
Warning: this approach has changed a little bit on Android Plugin for Gradle 3.0.0
Use productFlavors
for each partner app and define a build type test
for test builds.
productFlavors {
partner1 {
applicationId "com.partner1"
}
partnerN {
applicationId "com.partnerN"
}
}
buildTypes {
debug {
// use defaults
}
release {
// the 'prod' version, use defaults
}
test {
// config as you want!
applicationIdSuffix ".test"
versionNameSuffix " Test"
debuggable true
minifyEnabled false
signingConfig signingConfigs.debug
}
}
You can use mix and match source folders as the Android Plug-in for Gradle shows:
To build each version of your app, the build system combines source code and resources from:
src/main/
- the main source directory (the default configuration common to all variants)src/<buildType>/
- the source directorysrc/<productFlavor>/
- the source directory
Edit: This user guide is another source of help: http://tools.android.com/tech-docs/new-build-system/user-guide
Edit 2: according to the link above:
Additional sourcesets are also created for each variants:
android.sourceSets.flavor1Debug
Locationsrc/flavor1Debug/
android.sourceSets.flavor1Release
Locationsrc/flavor1Release/
android.sourceSets.flavor2Debug
Locationsrc/flavor2Debug/
android.sourceSets.flavor2Release
Locationsrc/flavor2Release/
Then, you can use /src/partner1Test/
to define resources specifics to partner1
flavor AND Test
build, that is a partner1Test
build variant.
Gradle productflavors sourcesets and old project structure
You need to first declare your flavors and then customize the sourceSets.
What happens is that when you customize the sourceSets it created android.sourceSets.dev, but then when creating android.productFlavors.dev it attempts to create a matching android.sourceSets.dev and fails (because it's already there).
We can't really know that the already created sourceSet is meant to be the same thing, so we fail rather than potentially using a sourceSet for that flavor when you meant it to be used for something else.
Related Topics
Moving an Image Using Accelerometer of Android
Speech to Text from Own Sound File
Practical Way to Find Out If Sms Has Been Sent
How to Merge Two Mp3 Files into One (Combine/Join)
How to Send Location of the Device on Server When Needed
Inflate a View in a Background Thread
Android.Content.Res.Resources$Notfoundexception: Unable to Find Resource Id #0Xffffffff
Difference Between Addvalueeventlistener() and Addlistenerforsinglevalueevent() of Firebase
Inflate Layout Programmatically Within Another Layout
Flutter - How to Pass Custom Arguments in Firebase Dynamic Links for App Invite Feature
Searchview in Optionsmenu Not Full Width
How to Implement Rounded Corners to a Mapfragment
Android - Getting from a Uri to an Inputstream to a Byte Array
Sending Pictures to a Web Server
How to Fix "Fail to Connect to Camera Service" Exception in Android Emulator