问题
Lets say I have the following sourceSets
:
sourceSets {
flavor1 {
assets.srcDirs = ['repo-assets/flavor1']
res.srcDirs = ['repo-res/flavor1']
}
flavor2 {
assets.srcDirs = ['repo-assets/flavor2']
res.srcDirs = ['repo-res/flavor2']
}
flavor3 {
assets.srcDirs = ['repo-assets/flavor1']
res.srcDirs = ['repo-res/flavor1']
}
flavor4 {
assets.srcDirs = ['repo-assets/flavor2']
res.srcDirs = ['repo-res/flavor2']
}
}
If you notice flavor1
and flavor3
have same srcDirs and so does flavor2
and flavor4
.
Trying Possibility#1
I was trying to figure out if there is a way to avoid the redundancy by using something like this:
sourceSets {
flavor1, flavor3 {
assets.srcDirs = ['repo-assets/flavor1']
res.srcDirs = ['repo-res/flavor1']
}
flavor2, flavor4 {
assets.srcDirs = ['repo-assets/flavor2']
res.srcDirs = ['repo-res/flavor2']
}
}
The above does not work (already tried). Looking for something similar so that i can just provide a common set of sourceDirs
for a set of flavors. Anyone tried doing something similar and can provide some pointers?
Trying Possibility#2
Does the name of sourceSets
need to be same as that of flavors?
Can i name the sourceSets
separately and then map them to productFlavors
like this?
productFlavors {
flavor1 {
sourceset = "src1"
}
flavor2 {
sourceset = "src2"
}
flavor3 {
sourceset = "src1"
}
flavor4 {
sourceset = "src2"
}
}
sourceSets {
src1 {
}
src2 {
}
}
Trying Possibility#3
Can the sourcesets be dynamically assigned via tasks somehow to achieve the same stuff?
UPDATE
Douglas's answer sort of helped me get very close to what i was looking for eventually (reducing the code in build.gradle). He used Possibility#3 above. Thanks Douglas! Any better alternative from bounty hunters is still welcome (something closer to possibilities #1 and #2 above). If nothing comes up the bounty is Douglas's already when the period ends as I've accepted his answer. But still will remain optimistic about finding a better alternative.
回答1:
You were also pretty close with your first possibility:
sourceSets {
[flavor1, flavor3].each {
it.assets.srcDirs = ['repo-assets/flavor1']
it.res.srcDirs = ['repo-res/flavor1']
}
[flavor2, flavor4].each {
it.assets.srcDirs = ['repo-assets/flavor2']
it.res.srcDirs = ['repo-res/flavor2']
}
}
The above doesn't look nice in IDEA editor, a lot of warnings are shown. You can set the type if you want to get code completion:
import com.android.build.gradle.api.AndroidSourceSet
android {
sourceSets {
[flavor2, flavor4].each { AndroidSourceSet ss ->
ss.assets.srcDirs = ['repo-assets/flavor2']
ss.res.srcDirs = ['repo-res/flavor2']
}
}
}
Another trick: this way the definition of the flavor is co-located with the source set listing.
android
productFlavors {
flavor1 {
applicationId "flavor1.app.id"
}
flavor2 {
applicationId "flavor2.app.id"
}
[flavor1, flavor2].each {
sourceSets[it.name].assets.srcDirs = ['repo-assets/flavor1']
sourceSets[it.name].res.srcDirs = ['repo-assets/flavor1']
}
}
Whichever way you go there's also a noteworthy thing about srcDirs
, see source:
println assets.srcDirs // say it's [src/flavor/assets]
assets.srcDirs = ['dir1', 'dir2'] // overwrites existing directories: output would be [dir1, dir2]
assets.srcDirs 'dir1', 'dir2' // appends existing directories: output would be [src/flavor/assets, dir1, dir2]
assets.srcDir 'dir1' // appends only one dir, output would be [src/flavor/assets, dir1]
回答2:
I think what @jmols is trying to say in comments is something like this:
Go from structure
repo-assets
flavor1
flavor2
repo-res
flavor1
flavor2
to
flavor1
assets
res
flavor2
assets
res
and use
sourceSets {
//flavor1.setRoot('flavor1') // default
//flavor2.setRoot('flavor2') // default
flavor3.setRoot('flavor1')
flavor4.setRoot('flavor2')
}
See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Project-Structure for setRoot
and default structure.
Here's the source code of setRoot, notice that it resets all customizations, that's why it's crucial to match the default structure. Its built-in call is located here.
回答3:
You can define a function to copy flavors (outside of android {}
):
def copyFlavor(flavordest, flavororig) {
flavordest.resources.srcDirs = flavororig.resources.srcDirs
flavordest.res.srcDirs = flavororig.res.srcDirs
flavordest.aidl.srcDirs = flavororig.aidl.srcDirs
flavordest.java.srcDirs = flavororig.java.srcDirs
flavordest.assets.srcDirs = flavororig.assets.srcDirs
flavordest.renderscript.srcDirs = flavororig.renderscript.srcDirs
// if you don't need all of this, remove them. There are much more too, like `jni` and `jniLibs`
}
then call this function on source sets:
sourceSets {
copyFlavor(flavor3, flavor1) // flavor3 = flavor1
copyFlavor(flavor4, flavor2) // flavor4 = flavor2
}
Of course, it's only worth if you have many flavors, for only two, the overhead of writing a function is greater.
Edit: adding the project structure I used
To simplify and not need to specify flavor1 and flavor2 paths, I used the standard structure for flavors:
app/
src/
androidTest/
flavor1/
assets/
res/
values/strings.xml
flavor2/
assets/
res/
values/strings.xml
main/
assets/
java/
res/
values/strings.xml
test/
values.xml
has a string app_name
with content "SourceSets"
for main
, "SourceSets 1"
for flavor1
and "SourceSets 2"
for flavor2
.
Just define flavor1 and flavor2 path the standard way and copy them later using the function provided.
Edit 2: Things I tried and probably some would work, but none did here (probably I made some stupid mistake from)
Things I tried and didn't work:
A:
1. flavor3.root = "flavor1"
2. flavor3.root = "flavor1/"
3. flavor3.setRoot("flavor1")
4. flavor3.setRoot("flavor1/")
These compiled, but the string resource I had defined to test didn't change.
B:flavor3.root = flavor1.root
This doesn't even compile, .root
is write-only.
C:flavor3.root = flavor1
This also compiled, but had no effect. Notice it differs from A because in A, the right-hand-side is a string.
D:
I had the idea of [].each
too, but when I tried it, I probably made some stupid mistake and it didn't work either:
[flavor2, flavor4].each {
it.res.srcDirs = ["flavor2/res"]
it.resources.srcDirs = ["flavor2/res"]
it.assets.srcDirs = ["flavor2/assets"]
}
The last one I had some hope, but couldn't manage. Then I stuck to the copyFlavor
function. All above I also tried with prepending src
(e.g., src/flavor1
), unsuccessful.
来源:https://stackoverflow.com/questions/36112157/grouping-few-of-many-sourcesets-having-exactly-same-configuration