blob: 10684b283ecbdb341d18a41f283b21dece88c63a [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.plugins
import com.android.SdkConstants
import com.android.build.api.dsl.BuildFeatures
import com.android.build.api.dsl.CommonExtension
import com.android.build.api.dsl.SettingsExtension
import com.android.build.api.extension.impl.VariantApiOperationsRegistrar
import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.api.variant.Variant
import com.android.build.api.variant.VariantBuilder
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.api.AndroidBasePlugin
import com.android.build.gradle.internal.ApiObjectFactory
import com.android.build.gradle.internal.AvdComponentsBuildService
import com.android.build.gradle.internal.BadPluginException
import com.android.build.gradle.internal.ClasspathVerifier.checkClasspathSanity
import com.android.build.gradle.internal.CompileOptions
import com.android.build.gradle.internal.DependencyConfigurator
import com.android.build.gradle.internal.ExtraModelInfo
import com.android.build.gradle.internal.SdkComponentsBuildService
import com.android.build.gradle.internal.SdkLocator.sdkTestDirectory
import com.android.build.gradle.internal.TaskManager
import com.android.build.gradle.internal.VariantManager
import com.android.build.gradle.internal.VariantTaskManager
import com.android.build.gradle.internal.api.DefaultAndroidSourceSet
import com.android.build.gradle.internal.component.TestComponentCreationConfig
import com.android.build.gradle.internal.component.TestFixturesCreationConfig
import com.android.build.gradle.internal.component.VariantCreationConfig
import com.android.build.gradle.internal.core.dsl.VariantDslInfo
import com.android.build.gradle.internal.core.dsl.impl.features.AndroidTestOptionsDslInfoImpl
import com.android.build.gradle.internal.crash.afterEvaluate
import com.android.build.gradle.internal.crash.runAction
import com.android.build.gradle.internal.dependency.CONFIG_NAME_ANDROID_JDK_IMAGE
import com.android.build.gradle.internal.dependency.JacocoInstrumentationService
import com.android.build.gradle.internal.dependency.SourceSetManager
import com.android.build.gradle.internal.dependency.VariantDependencies
import com.android.build.gradle.internal.dsl.BuildType
import com.android.build.gradle.internal.dsl.CommonExtensionImpl
import com.android.build.gradle.internal.dsl.DefaultConfig
import com.android.build.gradle.internal.dsl.ModulePropertyKey
import com.android.build.gradle.internal.dsl.ProductFlavor
import com.android.build.gradle.internal.dsl.SigningConfig
import com.android.build.gradle.internal.errors.DeprecationReporterImpl
import com.android.build.gradle.internal.errors.IncompatibleProjectOptionsReporter
import com.android.build.gradle.internal.getManagedDeviceAvdFolder
import com.android.build.gradle.internal.getSdkDir
import com.android.build.gradle.internal.ide.dependencies.LibraryDependencyCacheBuildService
import com.android.build.gradle.internal.ide.dependencies.MavenCoordinatesCacheBuildService
import com.android.build.gradle.internal.ide.v2.GlobalSyncService
import com.android.build.gradle.internal.ide.v2.NativeModelBuilder
import com.android.build.gradle.internal.lint.LintFixBuildService
import com.android.build.gradle.internal.profile.AnalyticsUtil
import com.android.build.gradle.internal.projectIsolationActive
import com.android.build.gradle.internal.scope.DelayedActionsExecutor
import com.android.build.gradle.internal.services.Aapt2DaemonBuildService
import com.android.build.gradle.internal.services.Aapt2ThreadPoolBuildService
import com.android.build.gradle.internal.services.AndroidLocationsBuildService
import com.android.build.gradle.internal.services.ClassesHierarchyBuildService
import com.android.build.gradle.internal.services.DslServices
import com.android.build.gradle.internal.services.DslServicesImpl
import com.android.build.gradle.internal.services.FakeDependencyJarBuildService
import com.android.build.gradle.internal.services.LintClassLoaderBuildService
import com.android.build.gradle.internal.services.StringCachingBuildService
import com.android.build.gradle.internal.services.SymbolTableBuildService
import com.android.build.gradle.internal.services.VersionedSdkLoaderService
import com.android.build.gradle.internal.services.getBuildService
import com.android.build.gradle.internal.tasks.factory.BootClasspathConfig
import com.android.build.gradle.internal.tasks.factory.BootClasspathConfigImpl
import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig
import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfigImpl
import com.android.build.gradle.internal.tasks.factory.TaskManagerConfig
import com.android.build.gradle.internal.tasks.factory.TaskManagerConfigImpl
import com.android.build.gradle.internal.testing.ManagedDeviceRegistry
import com.android.build.gradle.internal.utils.enforceMinimumVersionsOfPlugins
import com.android.build.gradle.internal.utils.getKotlinAndroidPluginVersion
import com.android.build.gradle.internal.utils.syncAgpAndKgpSources
import com.android.build.gradle.internal.variant.ComponentInfo
import com.android.build.gradle.internal.variant.LegacyVariantInputManager
import com.android.build.gradle.internal.variant.VariantFactory
import com.android.build.gradle.internal.variant.VariantInputModel
import com.android.build.gradle.internal.variant.VariantModel
import com.android.build.gradle.internal.variant.VariantModelImpl
import com.android.build.gradle.options.SyncOptions
import com.android.builder.errors.IssueReporter.Type
import com.android.builder.model.v2.ide.ProjectType
import com.android.sdklib.AndroidTargetHash
import com.android.sdklib.SdkVersionInfo
import com.google.common.annotations.VisibleForTesting
import com.google.common.base.Preconditions.checkState
import com.google.wireless.android.sdk.stats.GradleBuildProfileSpan.ExecutionType
import com.google.wireless.android.sdk.stats.GradleBuildProject
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.repositories.ArtifactRepository
import org.gradle.api.artifacts.repositories.FlatDirectoryArtifactRepository
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.provider.Provider
import org.gradle.build.event.BuildEventsListenerRegistry
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import java.io.File
import java.util.Arrays
import java.util.concurrent.atomic.AtomicBoolean
import java.util.function.Consumer
/** Base class for all Android plugins */
abstract class BasePlugin<
BuildFeaturesT: BuildFeatures,
BuildTypeT: com.android.build.api.dsl.BuildType,
DefaultConfigT: com.android.build.api.dsl.DefaultConfig,
ProductFlavorT: com.android.build.api.dsl.ProductFlavor,
AndroidResourcesT: com.android.build.api.dsl.AndroidResources,
InstallationT: com.android.build.api.dsl.Installation,
AndroidT: CommonExtension<
BuildFeaturesT,
BuildTypeT,
DefaultConfigT,
ProductFlavorT,
AndroidResourcesT,
InstallationT>,
AndroidComponentsT:
AndroidComponentsExtension<
in AndroidT,
in VariantBuilderT,
in VariantT>,
VariantBuilderT: VariantBuilder,
VariantDslInfoT: VariantDslInfo,
CreationConfigT: VariantCreationConfig,
VariantT: Variant>(
val registry: ToolingModelBuilderRegistry,
val componentFactory: SoftwareComponentFactory,
listenerRegistry: BuildEventsListenerRegistry,
private val gradleBuildFeatures: org.gradle.api.configuration.BuildFeatures,
): AndroidPluginBaseServices(listenerRegistry), Plugin<Project> {
init {
checkClasspathSanity()
}
protected class ExtensionData<
BuildFeaturesT: BuildFeatures,
BuildTypeT: com.android.build.api.dsl.BuildType,
DefaultConfigT: com.android.build.api.dsl.DefaultConfig,
ProductFlavorT: com.android.build.api.dsl.ProductFlavor,
AndroidResourcesT: com.android.build.api.dsl.AndroidResources,
InstallationT: com.android.build.api.dsl.Installation,
AndroidT: CommonExtension<
out BuildFeaturesT,
out BuildTypeT,
out DefaultConfigT,
out ProductFlavorT,
out AndroidResourcesT,
out InstallationT>>(
val oldExtension: BaseExtension,
val newExtension: AndroidT,
val bootClasspathConfig: BootClasspathConfigImpl,
)
@Suppress("DEPRECATION")
private val buildOutputs by lazy {
withProject("buildOutputs") {
it.container(
com.android.build.gradle.api.BaseVariantOutput::class.java
)
}
}
private val extensionData by lazy {
createExtension(
dslServices,
variantInputModel,
buildOutputs,
extraModelInfo,
versionedSdkLoaderService
)
}
// TODO: BaseExtension should be changed into AndroidT
@Deprecated("use newExtension")
val extension: BaseExtension by lazy { extensionData.oldExtension }
private val newExtension: AndroidT by lazy { extensionData.newExtension }
private val variantApiOperations by lazy {
VariantApiOperationsRegistrar<AndroidT, VariantBuilderT, VariantT>(
extensionData.newExtension
)
}
val managedDeviceRegistry: ManagedDeviceRegistry by lazy(LazyThreadSafetyMode.NONE) {
ManagedDeviceRegistry(AndroidTestOptionsDslInfoImpl((newExtension as CommonExtensionImpl<*, *, *, *, *, *>)))
}
private val globalConfig by lazy {
withProject("globalConfig") { project ->
@Suppress("DEPRECATION")
GlobalTaskCreationConfigImpl(
project,
extension,
(newExtension as CommonExtensionImpl<*, *, *, *, *, *>),
dslServices,
versionedSdkLoaderService,
bootClasspathConfig,
createCustomLintPublishConfig(project),
createCustomLintChecksConfig(project),
createAndroidJarConfig(project),
createFakeDependencyConfig(project),
createSettingsOptions(dslServices),
managedDeviceRegistry
)
}
}
@get:VisibleForTesting
val variantManager: VariantManager<AndroidT, VariantBuilderT, VariantDslInfoT, CreationConfigT> by lazy {
withProject("variantManager") { project ->
@Suppress("DEPRECATION", "UNCHECKED_CAST")
VariantManager(
project,
dslServices,
extension,
newExtension,
variantApiOperations as VariantApiOperationsRegistrar<AndroidT, VariantBuilder, Variant>,
variantFactory,
variantInputModel,
globalConfig,
projectServices
)
}
}
@get:VisibleForTesting
val variantInputModel: LegacyVariantInputManager by lazy {
withProject("LegacyVariantInputManager") { project ->
LegacyVariantInputManager(
dslServices,
variantFactory.componentType,
SourceSetManager(
project,
isPackagePublished(),
dslServices,
DelayedActionsExecutor()
))
}
}
private val sdkComponentsBuildService by lazy {
withProject("sdkComponentsBuildService") { project ->
SdkComponentsBuildService.RegistrationAction(project, projectServices.projectOptions)
.execute()
}
}
protected val dslServices: DslServicesImpl by lazy {
DslServicesImpl(
projectServices,
sdkComponentsBuildService,
getProjectTypeV2()
) {
versionedSdkLoaderService
}
}
private val taskManagerConfig: TaskManagerConfig by lazy {
TaskManagerConfigImpl(dslServices, componentFactory)
}
protected val versionedSdkLoaderService: VersionedSdkLoaderService by lazy {
withProject("versionedSdkLoaderService") { project ->
VersionedSdkLoaderService(
dslServices,
project,
{
@Suppress("DEPRECATION")
extension.compileSdkVersion
},
{
@Suppress("DEPRECATION")
extension.buildToolsRevision
},
)
}
}
private val bootClasspathConfig: BootClasspathConfigImpl by lazy {
extensionData.bootClasspathConfig
}
private val variantFactory: VariantFactory<VariantBuilderT, VariantDslInfoT, CreationConfigT> by lazy {
createVariantFactory()
}
protected val extraModelInfo: ExtraModelInfo = ExtraModelInfo()
private val hasCreatedTasks = AtomicBoolean(false)
protected abstract fun createExtension(
dslServices: DslServices,
dslContainers: DslContainerProvider<DefaultConfig, BuildType, ProductFlavor, SigningConfig>,
@Suppress("DEPRECATION")
buildOutputs: NamedDomainObjectContainer<com.android.build.gradle.api.BaseVariantOutput>,
extraModelInfo: ExtraModelInfo,
versionedSdkLoaderService: VersionedSdkLoaderService
): ExtensionData<BuildFeaturesT, BuildTypeT, DefaultConfigT, ProductFlavorT, AndroidResourcesT, InstallationT, AndroidT>
protected abstract fun createComponentExtension(
dslServices: DslServices,
variantApiOperationsRegistrar: VariantApiOperationsRegistrar<AndroidT, VariantBuilderT, VariantT>,
bootClasspathConfig: BootClasspathConfig
): AndroidComponentsT
abstract override fun getAnalyticsPluginType(): GradleBuildProject.PluginType
protected abstract fun createVariantFactory(): VariantFactory<VariantBuilderT, VariantDslInfoT, CreationConfigT>
protected abstract fun createTaskManager(
project: Project,
variants: Collection<ComponentInfo<VariantBuilderT, CreationConfigT>>,
testComponents: Collection<TestComponentCreationConfig>,
testFixturesComponents: Collection<TestFixturesCreationConfig>,
globalTaskCreationConfig: GlobalTaskCreationConfig,
localConfig: TaskManagerConfig,
extension: BaseExtension,
): VariantTaskManager<VariantBuilderT, CreationConfigT>
protected abstract fun getProjectType(): Int
/** The project type of the IDE model v2. */
protected abstract fun getProjectTypeV2(): ProjectType
override fun apply(project: Project) {
runAction {
basePluginApply(project, gradleBuildFeatures)
pluginSpecificApply(project)
project.pluginManager.apply(AndroidBasePlugin::class.java)
}
}
protected abstract fun pluginSpecificApply(project: Project)
override fun configureProject(project: Project) {
val gradle = project.gradle
val stringCachingService: Provider<StringCachingBuildService> =
StringCachingBuildService.RegistrationAction(project).execute()
val mavenCoordinatesCacheBuildService =
MavenCoordinatesCacheBuildService.RegistrationAction(project, stringCachingService)
.execute()
LibraryDependencyCacheBuildService.RegistrationAction(
project, mavenCoordinatesCacheBuildService
).execute()
GlobalSyncService.RegistrationAction(project, mavenCoordinatesCacheBuildService)
.execute()
val projectOptions = projectServices.projectOptions
val issueReporter = projectServices.issueReporter
Aapt2ThreadPoolBuildService.RegistrationAction(project, projectOptions).execute()
Aapt2DaemonBuildService.RegistrationAction(project, projectOptions).execute()
val locationsProvider = getBuildService(
project.gradle.sharedServices,
AndroidLocationsBuildService::class.java,
)
AvdComponentsBuildService.RegistrationAction(
project,
projectOptions,
getManagedDeviceAvdFolder(
project.objects,
project.providers,
locationsProvider.get()
),
sdkComponentsBuildService,
project.providers.provider {
@Suppress("DEPRECATION")
extension.compileSdkVersion
},
project.providers.provider {
@Suppress("DEPRECATION")
extension.buildToolsRevision
},
).execute()
SymbolTableBuildService.RegistrationAction(project).execute()
ClassesHierarchyBuildService.RegistrationAction(project).execute()
LintFixBuildService.RegistrationAction(project).execute()
LintClassLoaderBuildService.RegistrationAction(project).execute()
JacocoInstrumentationService.RegistrationAction(project).execute()
FakeDependencyJarBuildService.RegistrationAction(project).execute()
projectOptions
.allOptions
.forEach(projectServices.deprecationReporter::reportOptionIssuesIfAny)
IncompatibleProjectOptionsReporter.check(projectOptions, issueReporter)
// TODO(b/189990965) Re-enable checking minimum versions of certain plugins once
// https://github.com/gradle/gradle/issues/23838 is fixed
if (!gradleBuildFeatures.projectIsolationActive()) {
enforceMinimumVersionsOfPlugins(project, issueReporter)
}
// Apply the Java plugin
project.plugins.apply(JavaBasePlugin::class.java)
project.tasks
.named("assemble")
.configure { task ->
task.description = "Assembles all variants of all applications and secondary packages."
}
// As soon as project is evaluated we can clear the shared state for deprecation reporting.
gradle.projectsEvaluated { DeprecationReporterImpl.clean() }
createAndroidJdkImageConfiguration(project)
}
/** Creates the androidJdkImage configuration */
private fun createAndroidJdkImageConfiguration(project: Project) {
val config = project.configurations.create(CONFIG_NAME_ANDROID_JDK_IMAGE)
config.isVisible = false
config.isCanBeConsumed = false
config.description = "Configuration providing JDK image for compiling Java 9+ sources"
project.dependencies
.add(
CONFIG_NAME_ANDROID_JDK_IMAGE,
project.files(
versionedSdkLoaderService
.versionedSdkLoader
.flatMap { it.coreForSystemModulesProvider }
)
)
}
companion object {
fun createCustomLintChecksConfig(project: Project): Configuration {
val lintChecks = project.configurations.maybeCreate(VariantDependencies.CONFIG_NAME_LINTCHECKS)
lintChecks.isVisible = false
lintChecks.description = "Configuration to apply external lint check jar"
lintChecks.isCanBeConsumed = false
return lintChecks
}
private fun createCustomLintPublishConfig(project: Project): Configuration {
val lintChecks = project.configurations
.maybeCreate(VariantDependencies.CONFIG_NAME_LINTPUBLISH)
lintChecks.isVisible = false
lintChecks.description = "Configuration to publish external lint check jar"
lintChecks.isCanBeConsumed = false
return lintChecks
}
fun createAndroidJarConfig(project: Project): Configuration {
val androidJarConfig: Configuration = project.configurations
.maybeCreate(VariantDependencies.CONFIG_NAME_ANDROID_APIS)
androidJarConfig.description = "Configuration providing various types of Android JAR file"
androidJarConfig.isCanBeConsumed = false
return androidJarConfig
}
private fun createFakeDependencyConfig(project: Project): Configuration {
val fakeJarService = getBuildService(
project.gradle.sharedServices,
FakeDependencyJarBuildService::class.java,
).get()
val fakeDependency = project.dependencies.create(project.files(fakeJarService.lazyCachedFakeJar))
val configuration = project.configurations.detachedConfiguration(fakeDependency)
configuration.isCanBeConsumed = false
configuration.isCanBeResolved = true
return configuration
}
// Create the "special" configuration for test buddy APKs. It will be resolved by the test
// running task, so that we can install all the found APKs before running tests.
internal fun createAndroidTestUtilConfiguration(project: Project) {
project.logger
.debug(
"Creating configuration "
+ SdkConstants.GRADLE_ANDROID_TEST_UTIL_CONFIGURATION
)
val configuration = project.configurations
.maybeCreate(SdkConstants.GRADLE_ANDROID_TEST_UTIL_CONFIGURATION)
configuration.isVisible = false
configuration.description = "Additional APKs used during instrumentation testing."
configuration.isCanBeConsumed = false
configuration.isCanBeResolved = true
}
}
override fun configureExtension(project: Project) {
// Create components extension
createComponentExtension(
dslServices,
variantApiOperations,
bootClasspathConfig
)
project.extensions.add("buildOutputs", buildOutputs)
registerModels(
project,
registry,
variantInputModel,
extensionData,
extraModelInfo,
globalConfig)
// create default Objects, signingConfig first as it's used by the BuildTypes.
variantFactory.createDefaultComponents(variantInputModel)
createAndroidTestUtilConfiguration(project)
}
protected open fun registerModels(
project: Project,
registry: ToolingModelBuilderRegistry,
variantInputModel: VariantInputModel<DefaultConfig, BuildType, ProductFlavor, SigningConfig>,
extensionData: ExtensionData<BuildFeaturesT, BuildTypeT, DefaultConfigT, ProductFlavorT, AndroidResourcesT, InstallationT, AndroidT>,
extraModelInfo: ExtraModelInfo,
globalConfig: GlobalTaskCreationConfig
) {
// Register a builder for the custom tooling model
val variantModel: VariantModel = createVariantModel(globalConfig)
registry.register(
com.android.build.gradle.internal.ide.v2.ModelBuilder(
project, variantModel, extensionData.newExtension
)
)
// Register a builder for the native tooling model
val nativeModelBuilderV2 = NativeModelBuilder(
project,
projectServices.issueReporter,
projectServices.projectOptions,
variantModel
)
registry.register(nativeModelBuilderV2)
}
private fun createVariantModel(globalConfig: GlobalTaskCreationConfig): VariantModel {
return VariantModelImpl(
variantInputModel as VariantInputModel<DefaultConfig, BuildType, ProductFlavor, SigningConfig>,
{
@Suppress("DEPRECATION")
extension.testBuildType
},
{ variantManager.mainComponents.map { it.variant } },
{ variantManager.testComponents },
{ variantManager.buildFeatureValues },
getProjectType(),
getProjectTypeV2(),
globalConfig)
}
override fun createTasks(project: Project) {
configuratorService.recordBlock(
ExecutionType.TASK_MANAGER_CREATE_TASKS,
project.path,
null
) {
@Suppress("DEPRECATION")
TaskManager.createTasksBeforeEvaluate(
project,
variantFactory.componentType,
extension.sourceSets,
variantManager.globalTaskCreationConfig
)
}
project.afterEvaluate(
afterEvaluate {
variantInputModel.sourceSetManager.runBuildableArtifactsActions()
configuratorService.recordBlock(
ExecutionType.BASE_PLUGIN_CREATE_ANDROID_TASKS,
project.path,
null
) {
createAndroidTasks(project)
}
}
)
}
@Suppress("DEPRECATION")
@VisibleForTesting
fun createAndroidTasks(project: Project) {
val globalConfig = variantManager.globalTaskCreationConfig
if (hasCreatedTasks.get()) {
return
}
hasCreatedTasks.set(true)
variantManager.variantApiOperationsRegistrar.executeDslFinalizationBlocks()
(globalConfig.compileOptions as CompileOptions)
.finalizeSourceAndTargetCompatibility(project, globalConfig)
if (extension.compileSdkVersion == null) {
if (SyncOptions.getModelQueryMode(projectServices.projectOptions)
== SyncOptions.EvaluationMode.IDE
) {
val newCompileSdkVersion: String = findHighestSdkInstalled()
?: ("android-" + SdkVersionInfo.HIGHEST_KNOWN_STABLE_API)
extension.compileSdkVersion = newCompileSdkVersion
}
dslServices
.issueReporter
.reportError(
Type.COMPILE_SDK_VERSION_NOT_SET,
"compileSdkVersion is not specified. Please add it to build.gradle"
)
}
// Make sure unit tests set the required fields.
checkState(extension.compileSdkVersion != null, "compileSdkVersion is not specified.")
// get current plugins and look for the default Java plugin.
if (project.plugins.hasPlugin(JavaPlugin::class.java)) {
throw BadPluginException(
"The 'java' plugin has been applied, but it is not compatible with the Android plugins."
)
}
if (project.plugins.hasPlugin("me.tatarka.retrolambda")) {
val warningMsg =
"""One of the plugins you are using supports Java 8 language features. To try the support built into the Android plugin, remove the following from your build.gradle:
apply plugin: 'me.tatarka.retrolambda'
To learn more, go to https://d.android.com/r/tools/java-8-support-message.html
"""
dslServices.issueReporter.reportWarning(Type.GENERIC, warningMsg)
}
project.repositories
.forEach(
Consumer { artifactRepository: ArtifactRepository ->
if (artifactRepository is FlatDirectoryArtifactRepository) {
val warningMsg = String.format(
"Using %s should be avoided because it doesn't support any meta-data formats.",
artifactRepository.getName()
)
dslServices
.issueReporter
.reportWarning(Type.GENERIC, warningMsg)
}
})
// don't do anything if the project was not initialized.
// Unless TEST_SDK_DIR is set in which case this is unit tests and we don't return.
// This is because project don't get evaluated in the unit test setup.
// See AppPluginDslTest
if ((!project.state.executed || project.state.failure != null)
&& sdkTestDirectory == null
) {
return
}
variantInputModel.lock()
extension.disableWrite()
@Suppress("DEPRECATION")
syncAgpAndKgpSources(project, extension.sourceSets)
val projectBuilder = configuratorService.getProjectBuilder(
project.path
)
if (projectBuilder != null) {
projectBuilder
.setCompileSdk(extension.compileSdkVersion)
.setBuildToolsVersion(extension.buildToolsRevision.toString())
.setSplits(AnalyticsUtil.toProto(extension.splits))
.setNdkVersion(newExtension.ndkVersion)
getKotlinAndroidPluginVersion(project)?.let {
projectBuilder.kotlinPluginVersion = it
}
}
AnalyticsUtil.recordFirebasePerformancePluginVersion(project)
// create the build feature object that will be re-used everywhere
val buildFeatureValues = variantFactory.createBuildFeatureValues(
extension.buildFeatures, projectServices.projectOptions
)
// create all registered custom source sets from the user on each AndroidSourceSet
variantManager
.variantApiOperationsRegistrar
.onEachSourceSetExtensions { name: String ->
extension
.sourceSets
.forEach(
Consumer { androidSourceSet: com.android.build.gradle.api.AndroidSourceSet? ->
if (androidSourceSet is DefaultAndroidSourceSet) {
androidSourceSet.extras.create(name)
}
})
}
variantManager.createVariants(buildFeatureValues)
val variants = variantManager.mainComponents
projectBuilder?.let { builder ->
variants.forEach { variant ->
variant.variant.experimentalProperties.get().keys.forEach { modulePropertyKey ->
ModulePropertyKey.OptionalString[modulePropertyKey]?.name?.let {
AnalyticsUtil.toProto(it).number
}?.let { builder.optionsBuilder.addModulePropertyKeys(it) }
ModulePropertyKey.BooleanWithDefault[modulePropertyKey]?.name?.let {
AnalyticsUtil.toProto(it).number
}?.let { builder.optionsBuilder.addModulePropertyKeys(it) }
ModulePropertyKey.Dependencies[modulePropertyKey]?.name?.let {
AnalyticsUtil.toProto(it).number
}?.let { builder.optionsBuilder.addModulePropertyKeys(it) }
ModulePropertyKey.OptionalBoolean[modulePropertyKey]?.name?.let {
AnalyticsUtil.toProto(it).number
}?.let { builder.optionsBuilder.addModulePropertyKeys(it) }
}
}
}
val taskManager = createTaskManager(
project,
variants,
variantManager.testComponents,
variantManager.testFixturesComponents,
globalConfig,
taskManagerConfig,
extension
)
taskManager.createTasks(variantFactory.componentType, createVariantModel(globalConfig))
val anyVariantSupportsSdkConsumption =
variants.any { it.variant.privacySandboxCreationConfig != null }
DependencyConfigurator(
project,
projectServices
)
.configureDependencySubstitutions()
.configureDependencyChecks()
.configureGeneralTransforms(globalConfig.namespacedAndroidResources, globalConfig.aarOrJarTypeToConsume)
.configureVariantTransforms(
variants.map { it.variant },
variantManager.nestedComponents,
globalConfig
)
.configureAttributeMatchingStrategies(variantInputModel, anyVariantSupportsSdkConsumption)
.configureCalculateStackFramesTransforms(globalConfig)
.apply {
// Registering Jacoco transforms causes the jacoco configuration to be created.
// Ensure there is at least one variant with enableAndroidTestCoverage
// enabled before registering the transforms.
if (variants.any { it.variant.codeCoverageEnabled }) {
configureJacocoTransforms()
}
}
.apply {
// Registering privacy sandbox transforms creates various detatched
// configurations for tools it uses. Only register them if privacy sandbox
// consumption is enabled.
if (anyVariantSupportsSdkConsumption) {
configurePrivacySandboxSdkConsumerTransforms()
configurePrivacySandboxSdkVariantTransforms(
variants.map { it.variant },
globalConfig.compileSdkHashString,
globalConfig.buildToolsRevision,
globalConfig
)
}
}
// Run the old Variant API, after the variants and tasks have been created.
@Suppress("DEPRECATION")
val apiObjectFactory = ApiObjectFactory(extension, variantFactory, dslServices)
for (variant in variants) {
apiObjectFactory.create(variant.variant)
variant.variant.oldVariantApiLegacySupport?.oldVariantApiCompleted()
}
// lock the Properties of the variant API after the old API because
// of the versionCode/versionName properties that are shared between the old and new APIs.
variantManager.lockVariantProperties()
// Make sure no SourceSets were added through the DSL without being properly configured
variantInputModel.sourceSetManager.checkForUnconfiguredSourceSets()
// configure compose related tasks.
taskManager.createPostApiTasks()
// now publish all variant artifacts for non test variants since
// tests don't publish anything.
for (component in variants) {
component.variant.publishBuildArtifacts()
}
// now publish all testFixtures components artifacts.
for (testFixturesComponent in variantManager.testFixturesComponents) {
testFixturesComponent.publishBuildArtifacts()
}
checkSplitConfiguration()
variantManager.setHasCreatedTasks(true)
variantManager.finalizeAllVariants()
}
private fun findHighestSdkInstalled(): String? {
var highestSdk: String? = null
val folder = withProject("findHighestSdkInstalled") { project ->
File(getSdkDir(project.rootDir, syncIssueReporter, project.providers), "platforms")
}
val listOfFiles = folder.listFiles()
if (listOfFiles != null) {
Arrays.sort(listOfFiles, Comparator.comparing { obj: File -> obj.name }
.reversed())
for (file in listOfFiles) {
if (AndroidTargetHash.getPlatformVersion(file.name) != null) {
highestSdk = file.name
break
}
}
}
return highestSdk
}
private fun checkSplitConfiguration() {
val configApkUrl = "https://d.android.com/topic/instant-apps/guides/config-splits.html"
@Suppress("DEPRECATION")
val generatePureSplits = extension.generatePureSplits
@Suppress("DEPRECATION")
val splits = extension.splits
// The Play Store doesn't allow Pure splits
if (generatePureSplits) {
dslServices
.issueReporter
.reportWarning(
Type.GENERIC,
"Configuration APKs are supported by the Google Play Store only when publishing Android Instant Apps. To instead generate stand-alone APKs for different device configurations, set generatePureSplits=false. For more information, go to "
+ configApkUrl
)
}
if (!generatePureSplits && splits.language.isEnable) {
dslServices
.issueReporter
.reportWarning(
Type.GENERIC,
"Per-language APKs are supported only when building Android Instant Apps. For more information, go to "
+ configApkUrl
)
}
}
/**
* If overridden in a subclass to return "true," the package Configuration will be named
* "publish" instead of "apk"
*/
protected open fun isPackagePublished(): Boolean {
return false
}
// Initialize the android extension with values from the android settings extension
protected fun initExtensionFromSettings(extension: AndroidT) {
settingsExtension?.let {
extension.doInitExtensionFromSettings(it)
}
}
protected open fun AndroidT.doInitExtensionFromSettings(settings: SettingsExtension) {
settings.compileSdk?.let { compileSdk ->
this.compileSdk = compileSdk
settings.compileSdkExtension?.let { compileSdkExtension ->
this.compileSdkExtension = compileSdkExtension
}
}
settings.compileSdkPreview?.let { compileSdkPreview ->
this.compileSdkPreview = compileSdkPreview
}
settings.minSdk?.let { minSdk ->
this.defaultConfig.minSdk = minSdk
}
settings.minSdkPreview?.let { minSdkPreview ->
this.defaultConfig.minSdkPreview = minSdkPreview
}
settings.ndkVersion.let { ndkVersion ->
this.ndkVersion = ndkVersion
}
settings.ndkPath?.let { ndkPath ->
this.ndkPath = ndkPath
}
settings.buildToolsVersion.let { buildToolsVersion ->
this.buildToolsVersion = buildToolsVersion
}
}
}