I'd like to know if there is a way for a root project to define/inject some properties in it's dependencies. More specifically, the problem I'm having is that a library project has to know whether to take "free" or "pro" java sources and other resources before assemble/compile task is run. Kind of like specifying product flavors for library projects (that are inherited from it's parent project), but that isn't supported by the Android plugin for Gradle. Changing the library project structure, i.e. creating "free" and "pro" libs is not an option.
Edit: The best I've managed to achieve so far is something like this:
root: build.gradle
android {
...
productFlavors {
free, pro
}
sourceSets {
free {
project(':..:lib') {
groupFreePro = 'free'
// java.srcDirs = ['src', 'free/src']
}
}
pro {
project(':..:lib') {
groupFreePro = 'pro'
// java.srcDirs = ['src', 'pro/src']
}
}
...
}
}
library: gradle.build
android {
...
sourceSets {
main {
java.srcDirs = [groupFreePro + '/src']
res.srcDirs = [groupFreePro + '/res']
}
}
...
}
}
That way I inject the groupFreePro variable into the lib project. But there is a problem with this approach:
By the time, when the lib project get's to it's android -> sourceSets task the groupFreePro is always set to "pro". I presume that's because all the sourceSets at the root project are read (and not just the one variant that I want to build with; "free" for example) and thus the last set/task always overrides any previously set values of groupFreePro.
If I try to set the value of groupFreePro any other way it either gets overriden (like in the above case), or I don't know the appropriate task/time/place where I should call this variable injection stuff to set the variable to the desired value. Uncommenting java.srcDirs
in root project doesn't help either.
I tried solving these problems on my own, but I'm really new to Gradle and also lack of proper documentation (at least for the Android part) leaves me guessing what to do most of the time so I do a lot of trial and error (but now I'm kind of stuck).
This is how I've solved the problem for now. It's not a perfect solution, but it's good enough for now.
I've updated the answer to include the latest 0.9.2 Gradle plugin and it's new(est) features (mostly just updated the library build scripts).
root: gradle.build
// global variables
ext {
// can be set to default values or blank
groupFreePro = "free"
}
// start parameters
println "Start parametes: tasks = " + gradle.startParameter.getTaskNames()
gradle.startParameter.getTaskNames().each { task ->
if (task.contains("Free") || task.contains("F")) {
groupFreePro = "free"
} else if (task.contains("Pro") || task.contains("P")) {
groupFreePro = "pro"
}
println "groupFreePro = " + groupFreePro
}
android {
...
}
The task.contains("F")
is there to handle the abbreviated versions or running tasks (if we wanted to run the script as gradle aFD
).
The global variables under ext
can be set to default values. In that case, even if you run the script without the "Free/Pro" in the task name, it should work just fine. The downside of default values is that the build may not crash if not set up properly (if you want the build to work only if "Free/Pro" in the task name is specified).
library: gradle.build
android {
...
defaultPublishConfig groupFreePro + groupDebugRelease.capitalize()
productFlavors {
free
pro
}
...
sourceSets {
main {
java.srcDirs = ['/src']
res.srcDirs = ['/res']
}
free {
java.srcDirs = ["free/src"]
res.srcDirs = ["free/res"]
}
pro {
java.srcDirs = ["pro/src"]
res.srcDirs = ["pro/res"]
}
}
...
}
dependencies {
freeCompile fileTree(dir: 'free/lib', include: '*.jar')
}
defaultPublishConfig
so that I don't need to specify
java.srcDirs = ["src", groupFreePro + "/src"]
res.srcDirs = [groupFreePro + "/res"]
any more, as well as custom flavour compiling now be used i.e. flavor1Compile
(in the dependencies
block).
The option of writing compile project(path: ':project', configuration: 'flavor1Debug')
in the dependencies
block doesn't really work for us because you have to pass these options through dependencies and if you have multiple flavour groups/dimensions this means that more or less all of the flavour combinations have to be handled in "non-last" dependencies (i.e. dependencies that have other dependencies (that have multiple flavours)) as well.
The println
lines are just to see and make sure the right params are passed.
The upside of this solution (compared to Varun's) is that you need to run just one (original) task. That also means that it works (or at least it should) with Android Studio without any problems.
The downside of this solution is that it doesn't work if you wanted to build all variants using gradle assemble
command (or alike) that is missing the Free
part of the task. I guess that could also be handled but I'm not doing that, because the current solution is good enough for me at the moment (though if I improve the current solution, I'll probably update this answer as well).
There are other solutions possible by using gradle.taskGraph.whenReady
but I don't know how to properly set srcDirs
(of dependencies in particular). Suggestions welcome.
This feature is now available after Version 0.9 of the Gradle plugin for Android.
Take a look here: http://tools.android.com/tech-docs/new-build-system/migrating_to_09
Copy pasting here:
Libraries
The DSL for the library projects is now the same as for the application projects. This means you can create more build types, and create flavors.
- You can create/configure more build types, in the buildTypes { ... } container.
- You can create product flavors using the productFlavors { ... } container.
- You can create signingConfigs using the signingConfigs { ... } container.
For example if you have in your library:
android {
debug {
}
release {
}
debugSigningConfig {
}
}
You would replace it with:
android {
buildTypes {
debug {
}
release {
}
}
signingConfigs {
debug {
}
}
}
Here is the LibraryVariant
and here is the ApkVariant
Looking at the above DSL
it does not look like multiple productFlavors
is supported for the LibraryVariant
types..
If your free/pro
are not going to change much you can create a aar
each for pro and free and use them as dependencies as needed by your app.
UPDATE:
I have some code at github. It works but requires calling an additional task before the actual build/assemble task is called on the app. https://github.com/varunkochar/Trying-Android-Gradle/tree/master/FakeLibraryProductFlavors
UPDATE:
With the latest android gradle plugin v0.9.0, the LibraryProject now also supports the same DSL as an ApplicationProject. So, you can use the latest version and use the inbuilt ability of library projects to build with custom flavors. Source: http://tools.android.com/tech-docs/new-build-system
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