如何使用resolvedconfiguration . getresolveartifacts强制变量选择?



我正在使用一个大型的,多模块的Android应用程序,并且我正在尝试定义一个Gradle任务来收集所有运行时依赖的jar。我在app/build.gradle:

中尝试这样做
task collectDeps {
doLast {
configurations.releaseRuntimeClasspath.resolvedConfiguration.resolvedArtifacts.each {
// do stuff
}
}
}

我过去在其他Java项目中使用过这个代码片段,所以我知道它在概念上是可行的;这是我第一次在一个有多种构建类型和/或变体的项目上尝试它。

当在Android项目上运行时,执行此任务会抛出一个变量解析错误:

Execution failed for task ':app:collectDeps'.
> Could not resolve all dependencies for configuration ':app:releaseRuntimeClasspath'.
> The consumer was configured to find a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.1.1', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm'. However we cannot choose between the following variants of project :myModule:
- Configuration ':myModule:releaseRuntimeElements' variant android-aar-metadata declares a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm':
- Unmatched attributes:
- Provides attribute 'artifactType' with value 'android-aar-metadata' but the consumer didn't ask for it
- Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it
- Provides a library but the consumer didn't ask for it
- Configuration ':myModule:releaseRuntimeElements' variant android-art-profile declares a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.1.1', attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release', attribute 'org.jetbrains.kotlin.platform.type' with value 'androidJvm':
- Unmatched attributes:
- Provides attribute 'artifactType' with value 'android-art-profile' but the consumer didn't ask for it
- Provides attribute 'com.android.build.gradle.internal.attributes.VariantAttr' with value 'release' but the consumer didn't ask for it
- Provides a library but the consumer didn't ask for it

为了简洁,我已经修改了错误;总共有~20种改型。注意,myModule是顶层应用的一个项目依赖;如果我删除了依赖项,错误是相同的,但来自不同的模块。

我还应该在这里指出,每个其他构建目标工作良好;应用程序已经相当成熟,我唯一做的改动就是在app/build.gradle中添加了这个新任务。所以我假设有一些关于我解决Gradle不喜欢的依赖的方式,但我正在努力弄清楚是什么,或者如何解决它。

搜索这个错误不是很有帮助;Gradle文档对如何解析变量的描述相当模糊,提供的解决方案似乎集中在改变依赖项如何添加到项目中;但我不一定想这样做,因为构建对其他所有用例都很好。

理想情况下,我希望能够在我的collectDeps任务中强制执行分辨率的变体(事实上,理想情况下collectDeps将在插件中定义)。这可能吗?

如果有问题,构建使用的是Gradle 7.2和v7.1.1的Android Gradle Plugin

可能有更好的方法来处理这个问题,但我最终设法通过从Sonatype的开源Nexus扫描插件中获得灵感来解决我的问题。代码看起来像这样(这是在Kotlin中,但可以毫不费力地修改为Groovy):

project.allprojects.forEach { project ->
val cfg = project.configurations.releaseRuntimeClasspath
try {
cfg.resolvedConfiguration.resolvedArtifacts.forEach {
// do stuff
}
} catch(e: Exception) {
when(e) {
is ResolveException, is AmbiguousVariantSelectionException -> {
val copyConfiguration = createCopyConfiguration(project)
cfg.allDependencies.forEach {
if(it is ProjectDependency) {
project.evaluationDependsOn(it.dependencyProject.path)
} else {
copyConfiguration.dependencies.add(it)
}
}
copyConfiguration.resolvedConfiguration.resolvedArtifacts.forEach {
// do stuff
}
}
else -> throw(e)
}
}
}
private fun createCopyConfiguration(project: Project): Configuration {
var configurationName = "myCopyConfiguration"
var i = 0
while(project.configurations.findByName(configurationName) != null) {
configurationName += i
i++
}
val copyConfiguration = project.configurations.create(configurationName)
copyConfiguration.attributes {
val factory = project.objects
this.attribute(Usage.USAGE_ATTRIBUTE, factory.named(Usage::class.java, Usage.JAVA_RUNTIME))
}
return copyConfiguration
}

基本思想是,如果由于歧义的变体选择而无法解析配置,我创建并注入一个指定属性org.gradle.usage='java-runtime'的新父配置;这足以消除变体的歧义。

请注意,我没有用任何其他属性测试它,所以它可能可以通过设置,例如,artifactType属性来工作;但是我的用例更具体地与运行时类路径相关,所以这对我有用

最新更新