Search code examples
androidandroid-studiogradleandroid-productflavorsandroid-sourcesets

Grouping few of many sourceSets having exactly same configuration


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.


Solution

  • 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]