将具有完全相同配置的许多 sourceSets 中的少数分组

Grouping few of many sourceSets having exactly same configuration

假设我有以下 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']
    }
}

如果您注意到 flavor1flavor3 具有相同的 srcDirs,flavor2flavor4.

也具有相同的 srcDirs

尝试可能性#1

我试图弄清楚是否有一种方法可以通过使用类似这样的方法来避免冗余:

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']
    }
}

以上都不行(已经试过了)。寻找类似的东西,以便我可以为一组口味提供一组通用的 sourceDirs。有人试过做类似的事情并可以提供一些指导吗?


尝试可能性#2

sourceSets的名字需要和口味的名字一样吗?

我可以单独命名 sourceSets,然后像这样将它们映射到 productFlavors 吗?

productFlavors {
    flavor1 {
      sourceset = "src1"
    }
    flavor2 {
      sourceset = "src2"
    }
    flavor3 {
      sourceset = "src1"
    }
    flavor4 {
      sourceset = "src2"
    }
}

sourceSets {
    src1 {
    }
    src2 {
    }
}

尝试可能性#3

能否通过任务以某种方式动态分配源集以实现相同的目的?


更新

Douglas 的 回答有点帮助我非常接近我最终要寻找的东西(减少 build.gradle 中的代码)。他使用了上面的可能性#3。谢谢道格拉斯!赏金猎人的任何更好的选择仍然是受欢迎的(更接近上面的可能性#1和#2)。如果什么都没有出现,那么当我接受他的回答时,当期限结束时,赏金已经是道格拉斯的了。但仍将对找到更好的替代方案保持乐观。

您可以定义一个函数来复制口味(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`
}

然后在源集上调用此函数:

sourceSets {
    copyFlavor(flavor3, flavor1)  // flavor3 = flavor1
    copyFlavor(flavor4, flavor2)  // flavor4 = flavor2
}

当然,如果你有很多flavors才值得,因为只有两个,写一个函数的开销更大。

编辑: 添加我使用的项目结构

为了简化而不需要指定 flavor1 和 flavor2 路径,我使用了 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 有一个字符串 app_namemain 的内容为 "SourceSets"flavor1 的内容为 "SourceSets 1""SourceSets 2" 的内容为 "SourceSets 2" flavor2.

只需以标准方式定义 flavor1 和 flavor2 路径,稍后使用提供的函数复制它们。

编辑 2: 我尝试过的东西可能有些会起作用,但是 none 在这里做了(可能我犯了一些愚蠢的错误)

我尝试过但没有奏效的事情:

甲:
1. flavor3.root = "flavor1"
2.flavor3.root = "flavor1/"
3.flavor3.setRoot("flavor1")
4.flavor3.setRoot("flavor1/")
这些已编译,但我定义用于测试的字符串资源没有改变。

乙:
flavor3.root = flavor1.root
这甚至不能编译,.root 是只写的。

C:
flavor3.root = flavor1
这也编译了,但没有效果。请注意它与 A 不同,因为在 A 中,右侧是一个字符串。

D:
我也有 [].each 的想法,但是当我尝试它时,我可能犯了一些愚蠢的错误并且它也没有用:

    [flavor2, flavor4].each {
        it.res.srcDirs = ["flavor2/res"]
        it.resources.srcDirs = ["flavor2/res"]
        it.assets.srcDirs = ["flavor2/assets"]
    }

最后一个我有一些希望,但无法实现。然后我坚持使用 copyFlavor 函数。以上我也尝试过在前面加上src(例如src/flavor1),但没有成功。

我认为@jmols 在评论中试图表达的是这样的:

从结构开始

repo-assets
    flavor1
    flavor2
repo-res
    flavor1
    flavor2

flavor1
    assets
    res
flavor2
    assets
    res

并使用

sourceSets {
    //flavor1.setRoot('flavor1') // default
    //flavor2.setRoot('flavor2') // default
    flavor3.setRoot('flavor1')
    flavor4.setRoot('flavor2')
}

有关 setRoot 和默认结构,请参见 http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Project-Structure。 这是 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.

您也非常接近第一种可能性:

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']
    }
}

以上在IDEA编辑器中看起来不太好,显示了很多警告。如果你想获得代码完成,你可以设置类型:

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']
        }
    }
}

另一个技巧:通过这种方式,风格的定义与源集列表位于同一位置。

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']
        }
    }

无论你走哪条路,srcDirssee 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]