Grouping few of many sourceSets having exactly same configuration

亡梦爱人 提交于 2019-12-29 07:51:33

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!