blob: 764a6a39a85692a7f3edb25011b2c1bae1ba68c8 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.gradle.internal
import com.android.build.api.attributes.BuildTypeAttr.Companion.ATTRIBUTE
import com.android.build.api.attributes.ProductFlavorAttr
import com.android.build.api.component.impl.ComponentPropertiesImpl
import com.android.build.api.component.impl.TestComponentImpl
import com.android.build.api.component.impl.TestComponentPropertiesImpl
import com.android.build.api.variant.impl.VariantImpl
import com.android.build.api.variant.impl.VariantPropertiesImpl
import com.android.build.gradle.internal.dependency.AarResourcesCompilerTransform
import com.android.build.gradle.internal.dependency.AarToClassTransform
import com.android.build.gradle.internal.dependency.AarTransform
import com.android.build.gradle.internal.dependency.AlternateCompatibilityRule
import com.android.build.gradle.internal.dependency.AlternateDisambiguationRule
import com.android.build.gradle.internal.dependency.AndroidXDependencySubstitution.replaceOldSupportLibraries
import com.android.build.gradle.internal.dependency.ClassesDirToClassesTransform
import com.android.build.gradle.internal.dependency.EnumerateClassesTransform
import com.android.build.gradle.internal.dependency.ExtractAarTransform
import com.android.build.gradle.internal.dependency.ExtractProGuardRulesTransform
import com.android.build.gradle.internal.dependency.FilterShrinkerRulesTransform
import com.android.build.gradle.internal.dependency.GenericTransformParameters
import com.android.build.gradle.internal.dependency.IdentityTransform
import com.android.build.gradle.internal.dependency.JetifyTransform
import com.android.build.gradle.internal.dependency.LibraryDependencySourcesTransform
import com.android.build.gradle.internal.dependency.LibrarySymbolTableTransform
import com.android.build.gradle.internal.dependency.MockableJarTransform
import com.android.build.gradle.internal.dependency.ModelArtifactCompatibilityRule.Companion.setUp
import com.android.build.gradle.internal.dependency.PlatformAttrTransform
import com.android.build.gradle.internal.dependency.VersionedCodeShrinker.Companion.of
import com.android.build.gradle.internal.dependency.getDexingArtifactConfigurations
import com.android.build.gradle.internal.dependency.registerDexingOutputSplitTransform
import com.android.build.gradle.internal.dsl.BaseFlavor
import com.android.build.gradle.internal.dsl.BuildType
import com.android.build.gradle.internal.dsl.DefaultConfig
import com.android.build.gradle.internal.dsl.ProductFlavor
import com.android.build.gradle.internal.dsl.SigningConfig
import com.android.build.gradle.internal.publishing.AndroidArtifacts
import com.android.build.gradle.internal.res.getAapt2FromMavenAndVersion
import com.android.build.gradle.internal.res.namespaced.AutoNamespacePreProcessTransform
import com.android.build.gradle.internal.res.namespaced.AutoNamespaceTransform
import com.android.build.gradle.internal.res.namespaced.init
import com.android.build.gradle.internal.scope.GlobalScope
import com.android.build.gradle.internal.services.getBuildService
import com.android.build.gradle.internal.utils.getDesugarLibConfig
import com.android.build.gradle.internal.utils.setDisallowChanges
import com.android.build.gradle.internal.variant.ComponentInfo
import com.android.build.gradle.internal.variant.VariantInputModel
import com.android.build.gradle.options.BooleanOption
import com.android.build.gradle.options.StringOption
import com.android.build.gradle.options.SyncOptions
import com.android.builder.model.CodeShrinker
import com.google.common.base.Strings
import com.google.common.collect.Maps
import org.gradle.api.Action
import org.gradle.api.ActionConfiguration
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.artifacts.transform.TransformSpec
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributesSchema
import org.gradle.api.attributes.Usage
import org.gradle.api.internal.artifacts.ArtifactAttributes
/**
* configures the dependencies for a set of variant inputs.
*/
class DependencyConfigurator(
private val project: Project,
private val projectName: String,
private val globalScope: GlobalScope,
private val variantInputModel: VariantInputModel<DefaultConfig, BuildType, ProductFlavor, SigningConfig>
) {
fun configureDependencySubstitutions(): DependencyConfigurator {
// If Jetifier is enabled, replace old support libraries with AndroidX.
if (globalScope.projectOptions[BooleanOption.ENABLE_JETIFIER]) {
replaceOldSupportLibraries(project)
}
return this
}
fun configureGeneralTransforms(): DependencyConfigurator {
val dependencies: DependencyHandler = project.dependencies
// The aars/jars may need to be processed (e.g., jetified to AndroidX) before they can be
// used
// Arguments passed to an ArtifactTransform must not be null
val jetifierSkipIfPossible =
globalScope.projectOptions[BooleanOption.JETIFIER_SKIP_IF_POSSIBLE]
val jetifierBlackList = Strings.nullToEmpty(
globalScope.projectOptions[StringOption.JETIFIER_BLACKLIST]
)
val autoNamespaceDependencies =
globalScope.extension.aaptOptions.namespaced &&
globalScope.projectOptions[BooleanOption.CONVERT_NON_NAMESPACED_DEPENDENCIES]
val jetifiedAarOutputType = if (autoNamespaceDependencies) {
AndroidArtifacts.ArtifactType.MAYBE_NON_NAMESPACED_PROCESSED_AAR
} else {
AndroidArtifacts.ArtifactType.PROCESSED_AAR
}
if (globalScope.projectOptions[BooleanOption.ENABLE_JETIFIER]) {
dependencies.registerTransform(
JetifyTransform::class.java
) { spec: TransformSpec<JetifyTransform.Parameters> ->
spec.parameters.projectName.set(projectName)
spec.parameters.skipIfPossible.set(jetifierSkipIfPossible)
spec.parameters.blackListOption.set(jetifierBlackList)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.AAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
jetifiedAarOutputType.type
)
}
dependencies.registerTransform(
JetifyTransform::class.java
) { spec: TransformSpec<JetifyTransform.Parameters> ->
spec.parameters.projectName.set(projectName)
spec.parameters.skipIfPossible.set(jetifierSkipIfPossible)
spec.parameters.blackListOption.set(jetifierBlackList)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.JAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_JAR.type
)
}
} else {
dependencies.registerTransform(
IdentityTransform::class.java
) { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(projectName)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.AAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
jetifiedAarOutputType.type
)
}
dependencies.registerTransform(
IdentityTransform::class.java
) { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(projectName)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.JAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_JAR.type
)
}
}
dependencies.registerTransform(
ExtractAarTransform::class.java
) { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(projectName)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_AAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.EXPLODED_AAR.type
)
}
dependencies.registerTransform(
MockableJarTransform::class.java
) { spec: TransformSpec<MockableJarTransform.Parameters> ->
// Query for JAR instead of PROCESSED_JAR as android.jar doesn't need processing
spec.parameters.projectName.set(projectName)
spec.parameters.returnDefaultValues.set(true)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.JAR.type
)
spec.from.attribute(
AndroidArtifacts.MOCKABLE_JAR_RETURN_DEFAULT_VALUES,
true
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.TYPE_MOCKABLE_JAR
)
spec.to.attribute(
AndroidArtifacts.MOCKABLE_JAR_RETURN_DEFAULT_VALUES,
true
)
}
dependencies.registerTransform(
MockableJarTransform::class.java
) { spec: TransformSpec<MockableJarTransform.Parameters> ->
// Query for JAR instead of PROCESSED_JAR as android.jar doesn't need processing
spec.parameters.projectName.set(projectName)
spec.parameters.returnDefaultValues.set(false)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.JAR.type
)
spec.from.attribute(
AndroidArtifacts.MOCKABLE_JAR_RETURN_DEFAULT_VALUES,
false
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.TYPE_MOCKABLE_JAR
)
spec.to.attribute(
AndroidArtifacts.MOCKABLE_JAR_RETURN_DEFAULT_VALUES,
false
)
}
// transform to extract attr info from android.jar
dependencies.registerTransform(
PlatformAttrTransform::class.java
) { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(projectName)
// Query for JAR instead of PROCESSED_JAR as android.jar doesn't need processing
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.JAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.TYPE_PLATFORM_ATTR
)
}
val sharedLibSupport = globalScope
.projectOptions[BooleanOption.CONSUME_DEPENDENCIES_AS_SHARED_LIBRARIES]
for (transformTarget in AarTransform.getTransformTargets()) {
dependencies.registerTransform(
AarTransform::class.java
) { spec: TransformSpec<AarTransform.Parameters> ->
spec.parameters.projectName.set(projectName)
spec.parameters.targetType.set(transformTarget)
spec.parameters.sharedLibSupport.set(sharedLibSupport)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.EXPLODED_AAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
transformTarget.type
)
}
}
if (globalScope.projectOptions[BooleanOption.PRECOMPILE_DEPENDENCIES_RESOURCES]) {
dependencies.registerTransform(
AarResourcesCompilerTransform::class.java
) { reg: TransformSpec<AarResourcesCompilerTransform.Parameters> ->
reg.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.EXPLODED_AAR.type
)
reg.to
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.COMPILED_DEPENDENCIES_RESOURCES.type
)
reg.parameters { params: AarResourcesCompilerTransform.Parameters ->
val (first, second) = getAapt2FromMavenAndVersion(
globalScope
)
params.aapt2FromMaven
.from(first)
params.aapt2Version
.set(second)
params.errorFormatMode
.set(
SyncOptions.getErrorFormatMode(
globalScope.projectOptions
)
)
params.aapt2DaemonBuildService
.setDisallowChanges(getBuildService(project.gradle.sharedServices))
}
}
}
// API Jar: Produce a single API jar that can also contain the library R class from the AAR
val apiUsage: Usage = project.objects.named(Usage::class.java, Usage.JAVA_API)
dependencies.registerTransform(
AarToClassTransform::class.java
) { reg: TransformSpec<AarToClassTransform.Params> ->
reg.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_AAR.type
)
reg.from.attribute(
Usage.USAGE_ATTRIBUTE,
apiUsage
)
reg.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES_JAR.type
)
reg.to.attribute(
Usage.USAGE_ATTRIBUTE,
apiUsage
)
reg.parameters { params: AarToClassTransform.Params ->
params.forCompileUse.set(true)
params.generateRClassJar
.set(
globalScope.projectOptions.get(
BooleanOption.COMPILE_CLASSPATH_LIBRARY_R_CLASSES
)
)
}
}
// Produce a single runtime jar from the AAR.
val runtimeUsage: Usage = project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME)
dependencies.registerTransform(
AarToClassTransform::class.java
) { reg: TransformSpec<AarToClassTransform.Params> ->
reg.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_AAR.type
)
reg.from.attribute(
Usage.USAGE_ATTRIBUTE,
runtimeUsage
)
reg.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES_JAR.type
)
reg.to.attribute(
Usage.USAGE_ATTRIBUTE,
runtimeUsage
)
reg.parameters { params: AarToClassTransform.Params ->
params.forCompileUse.set(false)
params.generateRClassJar.set(false)
}
}
if (globalScope.projectOptions[BooleanOption.ENABLE_PROGUARD_RULES_EXTRACTION]) {
dependencies.registerTransform(
ExtractProGuardRulesTransform::class.java
) { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(projectName)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_JAR.type
)
spec.to
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.UNFILTERED_PROGUARD_RULES.type
)
}
}
dependencies.registerTransform(
LibrarySymbolTableTransform::class.java
) { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(projectName)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.EXPLODED_AAR.type
)
spec.to
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.SYMBOL_LIST_WITH_PACKAGE_NAME.type
)
}
if (autoNamespaceDependencies) {
dependencies.registerTransform(AutoNamespacePreProcessTransform::class.java) { spec ->
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.MAYBE_NON_NAMESPACED_PROCESSED_AAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PREPROCESSED_AAR_FOR_AUTO_NAMESPACE.type
)
spec.parameters.init(globalScope)
}
dependencies.registerTransform(AutoNamespacePreProcessTransform::class.java) { spec ->
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.JAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PREPROCESSED_AAR_FOR_AUTO_NAMESPACE.type
)
spec.parameters.init(globalScope)
}
dependencies.registerTransform(AutoNamespaceTransform::class.java) { spec ->
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PREPROCESSED_AAR_FOR_AUTO_NAMESPACE.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_AAR.type
)
spec.parameters.init(globalScope)
}
}
// Transform to go from external jars to CLASSES and JAVA_RES artifacts. This returns the
// same exact file but with different types, since a jar file can contain both.
for (classesOrResources in arrayOf(
AndroidArtifacts.ArtifactType.CLASSES_JAR.type,
AndroidArtifacts.ArtifactType.JAVA_RES.type
)) {
dependencies.registerTransform(IdentityTransform::class.java) { spec: TransformSpec<GenericTransformParameters?> ->
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_JAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
classesOrResources
)
}
}
// The Kotlin Kapt plugin should query for PROCESSED_JAR, but it is currently querying for
// JAR, so we need to have the workaround below to make it get PROCESSED_JAR. See
// http://issuetracker.google.com/111009645.
project.configurations.all { configuration: Configuration ->
if (configuration.name.startsWith("kapt")) {
configuration
.attributes
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.PROCESSED_JAR.type
)
}
}
// When consuming classes from Android libraries, there are 2 transforms:
// 1. `android-classes-directory` -> `android-classes`
// 2. `android-classes-jar` -> `android-classes`
// Currently Gradle always takes transform flow #1, which is ideal for incremental dexing.
// (We don't know why Gradle does that, but IncrementalDesugaringTest should catch it if
// this behavior changes.)
dependencies.registerTransform(
ClassesDirToClassesTransform::class.java,
Action { spec: TransformSpec<GenericTransformParameters?> ->
spec.from
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES_DIR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES.type
)
}
)
dependencies.registerTransform(
IdentityTransform::class.java,
Action { spec: TransformSpec<GenericTransformParameters?> ->
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES_JAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES.type
)
}
)
dependencies.registerTransform(
LibraryDependencySourcesTransform::class.java,
Action { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(projectName)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.EXPLODED_AAR.type
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.AAR_CLASS_LIST_AND_RES_SYMBOLS.type
)
}
)
// When consuming classes from Java libraries, there are 2 transforms:
// 1. `java-classes-directory` -> `android-classes`
// 2. `jar` -> `processed-jar` -> `android-classes-jar` -> `android-classes`
// Currently Gradle always takes transform flow #2, which is not ideal for incremental
// dexing.
// TODO(147137579): Configure Gradle to take transform flow #1.
dependencies.registerTransform(IdentityTransform::class.java) { spec: TransformSpec<GenericTransformParameters?> ->
spec.from
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
ArtifactTypeDefinition.JVM_CLASS_DIRECTORY
)
spec.to.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES.type
)
}
val schema = dependencies.attributesSchema
// custom strategy for build-type and product-flavor.
setBuildTypeStrategy(schema)
setupFlavorStrategy(schema)
setupModelStrategy(schema)
return this
}
private fun setBuildTypeStrategy(schema: AttributesSchema) {
// this is ugly but because the getter returns a very base class we have no choices.
val dslBuildTypes = variantInputModel.buildTypes.values.map { it.buildType }
if (dslBuildTypes.isEmpty()) {
return
}
val alternateMap: MutableMap<String, List<String>> =
Maps.newHashMap()
for (buildType in dslBuildTypes) {
if (!buildType.matchingFallbacks.isEmpty()) {
alternateMap[buildType.name] = buildType.matchingFallbacks
}
}
if (!alternateMap.isEmpty()) {
val buildTypeStrategy =
schema.attribute(
ATTRIBUTE
)
buildTypeStrategy
.compatibilityRules
.add(
AlternateCompatibilityRule.BuildTypeRule::class.java
) { config: ActionConfiguration ->
config.setParams(
alternateMap
)
}
buildTypeStrategy
.disambiguationRules
.add(
AlternateDisambiguationRule.BuildTypeRule::class.java
) { config: ActionConfiguration ->
config.setParams(
alternateMap
)
}
}
}
private fun setupFlavorStrategy(schema: AttributesSchema) {
// this is ugly but because the getter returns a very base class we have no choices.
val flavors = variantInputModel.productFlavors.values.map { it.productFlavor }
// first loop through all the flavors and collect for each dimension, and each value, its
// fallbacks
// map of (dimension > (requested > fallbacks))
val alternateMap: MutableMap<String, MutableMap<String, List<String>>> =
Maps.newHashMap()
for (flavor in flavors) {
if (flavor.matchingFallbacks.isNotEmpty()) {
val name = flavor.name
val dimension = flavor.dimension!!
val dimensionMap =
alternateMap.computeIfAbsent(
dimension
) { s: String? -> Maps.newHashMap() }
dimensionMap[name] = flavor.matchingFallbacks
}
handleMissingDimensions(alternateMap, flavor)
}
// also handle missing dimensions on the default config.
handleMissingDimensions(alternateMap, variantInputModel.defaultConfigData.defaultConfig)
// now that we know we have all the fallbacks for each dimensions, we can create the
// rule instances.
for ((key, value) in alternateMap) {
addFlavorStrategy(schema, key, value)
}
}
private fun setupModelStrategy(attributesSchema: AttributesSchema) {
setUp(attributesSchema)
}
private fun handleMissingDimensions(
alternateMap: MutableMap<String, MutableMap<String, List<String>>>,
flavor: BaseFlavor
) {
val missingStrategies = flavor.missingDimensionStrategies
if (missingStrategies.isNotEmpty()) {
for ((dimension, value) in missingStrategies) {
val dimensionMap = alternateMap.computeIfAbsent(dimension) { Maps.newHashMap() }
dimensionMap[value.requested] = value.fallbacks
}
}
}
/** Configure artifact transforms that require variant-specific attribute information. */
fun <VariantT: VariantImpl<VariantPropertiesT>, VariantPropertiesT: VariantPropertiesImpl> configureVariantTransforms(
variants: List<ComponentInfo<VariantT, VariantPropertiesT>>,
testComponents: List<ComponentInfo<TestComponentImpl<out TestComponentPropertiesImpl>, TestComponentPropertiesImpl>>
): DependencyConfigurator {
val allComponents: List<ComponentPropertiesImpl> = (variants + testComponents).map { it.properties }
val dependencies = project.dependencies
if (globalScope.projectOptions[BooleanOption.ENABLE_DEXING_ARTIFACT_TRANSFORM]) {
for (artifactConfiguration in getDexingArtifactConfigurations(
allComponents
)) {
artifactConfiguration.registerTransform(
globalScope.project.name,
dependencies,
project.files(globalScope.bootClasspath),
getDesugarLibConfig(globalScope.project),
SyncOptions.getErrorFormatMode(globalScope.projectOptions),
globalScope.projectOptions.get(BooleanOption.ENABLE_INCREMENTAL_DEXING_TRANSFORM)
)
}
}
if (globalScope.projectOptions[BooleanOption.ENABLE_PROGUARD_RULES_EXTRACTION]) {
val shrinkers: Set<CodeShrinker> = allComponents
.asSequence()
.map { it.variantScope.codeShrinker }
.filterNotNull()
.toSet()
for (shrinker in shrinkers) {
dependencies.registerTransform(
FilterShrinkerRulesTransform::class.java
) { reg: TransformSpec<FilterShrinkerRulesTransform.Parameters> ->
reg.from
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.UNFILTERED_PROGUARD_RULES.type
)
reg.to
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.FILTERED_PROGUARD_RULES.type
)
reg.from.attribute(
VariantManager.SHRINKER_ATTR,
shrinker.toString()
)
reg.to.attribute(
VariantManager.SHRINKER_ATTR,
shrinker.toString()
)
reg.parameters { params: FilterShrinkerRulesTransform.Parameters ->
params.shrinker
.set(of(shrinker))
params.projectName.set(project.name)
}
}
}
}
if (globalScope.projectOptions[BooleanOption.ENABLE_DUPLICATE_CLASSES_CHECK]) {
dependencies.registerTransform(
EnumerateClassesTransform::class.java
) { spec: TransformSpec<GenericTransformParameters> ->
spec.parameters.projectName.set(globalScope.project.name)
spec.from.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.CLASSES_JAR.type
)
spec.to
.attribute(
ArtifactAttributes.ARTIFACT_FORMAT,
AndroidArtifacts.ArtifactType.ENUMERATED_RUNTIME_CLASSES.type
)
}
}
registerDexingOutputSplitTransform(dependencies)
return this
}
companion object {
@JvmStatic
fun addFlavorStrategy(
schema: AttributesSchema,
dimension: String,
alternateMap: Map<String, List<String>>
) {
val attr = Attribute.of(dimension, ProductFlavorAttr::class.java)
val flavorStrategy = schema.attribute(attr)
flavorStrategy
.compatibilityRules
.add(AlternateCompatibilityRule.ProductFlavorRule::class.java) {
it.setParams(alternateMap)
}
flavorStrategy
.disambiguationRules
.add(AlternateDisambiguationRule.ProductFlavorRule::class.java) {
it.setParams(alternateMap)
}
}
}
}