blob: 8e7dfe8ec5ad7cc2dde55f022a95b0df2e28a3a6 [file] [log] [blame]
/*
* Copyright (C) 2022 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.api.component.impl
import com.android.SdkConstants
import com.android.build.api.artifact.ScopedArtifact
import com.android.build.api.artifact.impl.ArtifactsImpl
import com.android.build.api.component.impl.features.InstrumentationCreationConfigImpl
import com.android.build.api.component.impl.features.PrivacySandboxCreationConfigImpl
import com.android.build.api.dsl.KotlinMultiplatformAndroidCompilation
import com.android.build.api.variant.AndroidVersion
import com.android.build.api.variant.Component
import com.android.build.api.variant.ComponentIdentity
import com.android.build.api.variant.Instrumentation
import com.android.build.api.variant.InternalSources
import com.android.build.api.variant.JavaCompilation
import com.android.build.api.variant.ManifestFiles
import com.android.build.api.variant.ScopedArtifacts
import com.android.build.api.variant.SourceDirectories
import com.android.build.api.variant.impl.AndroidResourcesImpl
import com.android.build.api.variant.impl.FileBasedDirectoryEntryImpl
import com.android.build.api.variant.impl.FlatSourceDirectoriesImpl
import com.android.build.api.variant.impl.KotlinMultiplatformFlatSourceDirectoriesImpl
import com.android.build.api.variant.impl.LayeredSourceDirectoriesImpl
import com.android.build.api.variant.impl.ManifestFilesImpl
import com.android.build.api.variant.impl.ProviderBasedDirectoryEntryImpl
import com.android.build.api.variant.impl.SourceType
import com.android.build.api.variant.impl.SourcesImpl
import com.android.build.gradle.internal.api.DefaultAndroidSourceSet
import com.android.build.gradle.internal.component.KmpComponentCreationConfig
import com.android.build.gradle.internal.component.features.AndroidResourcesCreationConfig
import com.android.build.gradle.internal.component.features.BuildConfigCreationConfig
import com.android.build.gradle.internal.component.features.ManifestPlaceholdersCreationConfig
import com.android.build.gradle.internal.component.features.PrivacySandboxCreationConfig
import com.android.build.gradle.internal.component.features.ResValuesCreationConfig
import com.android.build.gradle.internal.component.legacy.ModelV1LegacySupport
import com.android.build.gradle.internal.component.legacy.OldVariantApiLegacySupport
import com.android.build.gradle.internal.core.MergedJavaCompileOptions
import com.android.build.gradle.internal.core.ProductFlavor
import com.android.build.gradle.internal.core.dsl.KmpComponentDslInfo
import com.android.build.gradle.internal.dependency.VariantDependencies
import com.android.build.gradle.internal.dependency.getProvidedClasspath
import com.android.build.gradle.internal.dsl.AbstractPublishing
import com.android.build.gradle.internal.publishing.AndroidArtifacts
import com.android.build.gradle.internal.publishing.ComponentPublishingInfo
import com.android.build.gradle.internal.publishing.VariantPublishingInfo
import com.android.build.gradle.internal.scope.BuildFeatureValues
import com.android.build.gradle.internal.scope.MutableTaskContainer
import com.android.build.gradle.internal.scope.getDirectories
import com.android.build.gradle.internal.services.TaskCreationServices
import com.android.build.gradle.internal.services.VariantServices
import com.android.build.gradle.internal.tasks.factory.GlobalTaskCreationConfig
import com.android.build.gradle.internal.variant.VariantPathHelper
import com.android.builder.core.ComponentType
import com.android.utils.appendCapitalized
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.util.PatternSet
import java.io.File
import java.util.Locale
import java.util.function.Predicate
abstract class KmpComponentImpl<DslInfoT: KmpComponentDslInfo>(
val dslInfo: DslInfoT,
protected val internalServices: VariantServices,
override val buildFeatures: BuildFeatureValues,
override val variantDependencies: VariantDependencies,
override val paths: VariantPathHelper,
override val artifacts: ArtifactsImpl,
override val taskContainer: MutableTaskContainer,
override val services: TaskCreationServices,
override val global: GlobalTaskCreationConfig,
final override val androidKotlinCompilation: KotlinMultiplatformAndroidCompilation,
manifestFile: File
): Component, KmpComponentCreationConfig, ComponentIdentity by dslInfo.componentIdentity {
final override val withJava: Boolean
get() = dslInfo.withJava
final override val dirName: String
get() = paths.dirName
final override val baseName: String
get() = paths.baseName
override val componentType: ComponentType
get() = dslInfo.componentType
override val description: String = "Kotlin multiplatform android plugin"
override fun computeTaskNameInternal(prefix: String, suffix: String): String =
prefix.appendCapitalized(name, suffix)
override fun computeTaskNameInternal(prefix: String): String = prefix.appendCapitalized(name)
override fun getArtifactName(name: String): String = name
override val productFlavorList: List<ProductFlavor> = emptyList()
override val debuggable = false
// public variant api
override val instrumentationCreationConfig by lazy(LazyThreadSafetyMode.NONE) {
InstrumentationCreationConfigImpl(
this,
internalServices
)
}
override val instrumentation: Instrumentation
get() = instrumentationCreationConfig.instrumentation
override val compileConfiguration: Configuration
get() = variantDependencies.compileClasspath
override val runtimeConfiguration: Configuration
get() = variantDependencies.runtimeClasspath
// DSL delegates
override val applicationId: Provider<String>
get() = dslInfo.applicationId
override val namespace: Provider<String>
get() = dslInfo.namespace
override val minSdk: AndroidVersion
get() = dslInfo.minSdkVersion
final override val useBuiltInKotlinSupport = false
override val sources = KmpSourcesImpl(
dslInfo,
internalServices,
manifestFile,
androidKotlinCompilation
)
final override fun getJavaClasspath(
configType: AndroidArtifacts.ConsumedConfigType,
classesType: AndroidArtifacts.ArtifactType,
generatedBytecodeKey: Any?
): FileCollection = getJavaClasspath(
this, configType, classesType, generatedBytecodeKey
)
override val compileClasspath: FileCollection by lazy(LazyThreadSafetyMode.NONE) {
getJavaClasspath(
AndroidArtifacts.ConsumedConfigType.COMPILE_CLASSPATH,
AndroidArtifacts.ArtifactType.CLASSES_JAR,
generatedBytecodeKey = null
)
}
override val providedOnlyClasspath: FileCollection by lazy(LazyThreadSafetyMode.NONE) {
getProvidedClasspath(
compileClasspath = variantDependencies.getArtifactCollection(
AndroidArtifacts.ConsumedConfigType.COMPILE_CLASSPATH,
AndroidArtifacts.ArtifactScope.ALL,
AndroidArtifacts.ArtifactType.CLASSES_JAR
),
runtimeClasspath = variantDependencies.getArtifactCollection(
AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH,
AndroidArtifacts.ArtifactScope.ALL,
AndroidArtifacts.ArtifactType.CLASSES_JAR
)
)
}
override fun computeLocalFileDependencies(filePredicate: Predicate<File>): FileCollection =
variantDependencies.computeLocalFileDependencies(
internalServices,
filePredicate
)
override fun computeLocalPackagedJars(): FileCollection =
computeLocalFileDependencies { file ->
file
.name
.lowercase(Locale.US)
.endsWith(SdkConstants.DOT_JAR)
}
override fun publishBuildArtifacts() {
com.android.build.gradle.internal.scope.publishBuildArtifacts(
creationConfig = this,
publishInfo = VariantPublishingInfo(
components = listOf(
ComponentPublishingInfo(
componentName = name,
type = AbstractPublishing.Type.AAR
)
)
)
)
}
override fun computeTaskName(action: String, subject: String): String =
computeTaskName(name, action, subject)
override val lifecycleTasks = LifecycleTasksImpl()
// Unsupported features
override val androidResources: AndroidResourcesImpl? = null
override val androidResourcesCreationConfig: AndroidResourcesCreationConfig? = null
override val resValuesCreationConfig: ResValuesCreationConfig? = null
override val buildConfigCreationConfig: BuildConfigCreationConfig? = null
override val manifestPlaceholdersCreationConfig: ManifestPlaceholdersCreationConfig? = null
override val modelV1LegacySupport: ModelV1LegacySupport? = null
override val oldVariantApiLegacySupport: OldVariantApiLegacySupport? = null
override val javaCompilation: JavaCompilation
get() = if (dslInfo.withJava) {
JavaCompilationImpl(
MergedJavaCompileOptions(),
buildFeatures.dataBinding,
internalServices
)
} else {
throw IllegalAccessException("The kotlin multiplatform android plugin doesn't" +
" configure the jvm options for compilation. To setup compilation options, use" +
" the kotlin specific options.")
}
override val annotationProcessorConfiguration: Configuration
get() = throw IllegalAccessException("The kotlin multiplatform android plugin doesn't" +
" configure annotation processors. To configure annotation processors, use" +
" the kapt options.")
class KmpSourcesImpl(
dslInfo: KmpComponentDslInfo,
variantServices: VariantServices,
manifestFile: File,
compilation: KotlinMultiplatformAndroidCompilation
): InternalSources {
override val java = if (dslInfo.withJava) {
KotlinMultiplatformFlatSourceDirectoriesImpl(
name = SourceType.JAVA.folder,
variantServices = variantServices,
variantDslFilters = PatternSet().also { filter ->
filter.include("**/*.java")
},
compilation = compilation
)
} else {
null
}
override val kotlin = KotlinMultiplatformFlatSourceDirectoriesImpl(
name = SourceType.KOTLIN.folder,
variantServices = variantServices,
variantDslFilters = PatternSet().also { filter ->
filter.include("**/*.kt", "**/*.kts")
},
compilation = compilation
)
override val resources = KotlinMultiplatformFlatSourceDirectoriesImpl(
name = SourceType.JAVA_RESOURCES.folder,
variantServices = variantServices,
variantDslFilters = PatternSet().also { filter ->
filter.exclude("**/*.java", "**/*.kt")
},
compilation = compilation
)
override fun resources(action: (FlatSourceDirectoriesImpl) -> Unit) {
action(resources)
}
override fun kotlin(action: (FlatSourceDirectoriesImpl) -> Unit) {
action(kotlin)
}
override fun java(action: (FlatSourceDirectoriesImpl) -> Unit) {
java?.let(action)
}
override val manifestFile: Provider<File> = variantServices.provider {
manifestFile
}
private val extras by lazy(LazyThreadSafetyMode.NONE) {
variantServices.domainObjectContainer(
FlatSourceDirectoriesImpl::class.java,
SourcesImpl.SourceProviderFactory(
variantServices,
),
)
}
override fun getByName(name: String): SourceDirectories.Flat = extras.maybeCreate(name)
// Not supported
override val res = null
override val assets = null
override val jniLibs = null
override val shaders = null
override val mlModels = null
override val aidl = null
override val renderscript = null
override val baselineProfiles = null
override val manifestOverlayFiles = variantServices.provider { emptyList<File>() }
override fun aidl(action: (FlatSourceDirectoriesImpl) -> Unit) {}
override fun renderscript(action: (FlatSourceDirectoriesImpl) -> Unit) {}
override fun res(action: (LayeredSourceDirectoriesImpl) -> Unit) {}
override fun assets(action: (LayeredSourceDirectoriesImpl) -> Unit) {}
override fun jniLibs(action: (LayeredSourceDirectoriesImpl) -> Unit) {}
override fun shaders(action: (LayeredSourceDirectoriesImpl) -> Unit) {}
override fun mlModels(action: (LayeredSourceDirectoriesImpl) -> Unit) {}
override fun baselineProfiles(action: (FlatSourceDirectoriesImpl) -> Unit) {}
override val artProfile: Provider<File>? = null
override val sourceProviderNames: List<String> = emptyList()
override val multiFlavorSourceProvider: DefaultAndroidSourceSet? = null
override val variantSourceProvider: DefaultAndroidSourceSet? = null
override val manifests: ManifestFiles =
ManifestFilesImpl(
variantServices
).also { sourceFilesImpl ->
sourceFilesImpl.addSourceFile(manifestFile)
}
}
open fun syncAndroidAndKmpClasspathAndSources() {
artifacts
.forScope(ScopedArtifacts.Scope.PROJECT)
.getScopedArtifactsContainer(ScopedArtifact.CLASSES)
.initialScopedContent
.from(androidKotlinCompilation.output.classesDirs)
androidKotlinCompilation.compileDependencyFiles = services.fileCollection(
global.bootClasspath,
getJavaClasspath(
AndroidArtifacts.ConsumedConfigType.COMPILE_CLASSPATH,
AndroidArtifacts.ArtifactType.CLASSES_JAR
)
)
// Include all kotlin sourceSets (the ones added directly to the compilation and the ones
// that added transitively through a dependsOn dependency).
sources.kotlin.addStaticSources(
services.provider {
androidKotlinCompilation.allKotlinSourceSets.flatMap { sourceSet ->
sourceSet.kotlin.srcDirs.map { srcDir ->
FileBasedDirectoryEntryImpl(
name = "Kotlin",
directory = srcDir
)
}
}
}
)
// Include all kotlin sourceSets (the ones added directly to the compilation and the ones
// that added transitively through a dependsOn dependency).
sources.java?.addStaticSources(
services.provider {
androidKotlinCompilation.allKotlinSourceSets.flatMap { sourceSet ->
sourceSet.kotlin.srcDirs.map { srcDir ->
FileBasedDirectoryEntryImpl(
name = "Java",
// Java sources are currently located at the sourceSetDir/java
// (e.g. src/androidMain/java)
directory = File(srcDir.parentFile, "java")
)
}
}
}
)
val projectDir = services.projectInfo.projectDirectory
sources.resources.addStaticSources(
services.provider {
androidKotlinCompilation.allKotlinSourceSets.map { sourceSet ->
ProviderBasedDirectoryEntryImpl(
name = "Java resources",
elements = sourceSet.resources.sourceDirectories.getDirectories(projectDir),
filter = PatternSet().exclude("**/*.java", "**/*.kt"),
)
}
}
)
}
override val privacySandboxCreationConfig: PrivacySandboxCreationConfig?
get() = if(dslInfo.privacySandboxDsl.enable) {
PrivacySandboxCreationConfigImpl()
} else {
null
}
}