blob: 06981f9145f2831ca2970bfcf4fa3b7bcce5c5f5 [file] [log] [blame]
/*
* Copyright (C) 2012 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
import com.android.annotations.NonNull
import com.android.build.api.dsl.ApplicationExtension
import com.android.build.api.dsl.BuildFeatures
import com.android.build.api.dsl.ComposeOptions
import com.android.build.api.dsl.DynamicFeatureExtension
import com.android.build.api.dsl.LibraryExtension
import com.android.build.api.dsl.TestExtension
import com.android.build.api.transform.Transform
import com.android.build.api.variant.VariantFilter
import com.android.build.gradle.api.AndroidSourceSet
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.BaseVariantOutput
import com.android.build.gradle.api.ViewBindingOptions
import com.android.build.gradle.internal.CompileOptions
import com.android.build.gradle.internal.ExtraModelInfo
import com.android.build.gradle.internal.SourceSetSourceProviderWrapper
import com.android.build.gradle.internal.coverage.JacocoOptions
import com.android.build.gradle.internal.dependency.SourceSetManager
import com.android.build.gradle.internal.dsl.AaptOptions
import com.android.build.gradle.internal.dsl.AdbOptions
import com.android.build.gradle.internal.dsl.BuildType
import com.android.build.gradle.internal.dsl.DataBindingOptions
import com.android.build.gradle.internal.dsl.DefaultConfig
import com.android.build.gradle.internal.dsl.DexOptions
import com.android.build.gradle.internal.dsl.ExternalNativeBuild
import com.android.build.gradle.internal.dsl.LintOptions
import com.android.build.gradle.internal.dsl.Lockable
import com.android.build.gradle.internal.dsl.PackagingOptions
import com.android.build.gradle.internal.dsl.ProductFlavor
import com.android.build.gradle.internal.dsl.SigningConfig
import com.android.build.gradle.internal.dsl.Splits
import com.android.build.gradle.internal.dsl.TestOptions
import com.android.build.gradle.internal.errors.DeprecationReporter
import com.android.build.gradle.internal.scope.GlobalScope
import com.android.build.gradle.internal.services.DslServices
import com.android.builder.core.LibraryRequest
import com.android.builder.errors.IssueReporter
import com.android.builder.model.SourceProvider
import com.android.builder.testing.api.DeviceProvider
import com.android.builder.testing.api.TestServer
import com.android.repository.Revision
import com.google.common.collect.ImmutableList
import com.google.common.collect.Lists
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.Incubating
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.artifacts.Configuration
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.tasks.SourceSet
import java.io.File
/**
* Base extension for all Android plugins.
*
* You don't use this extension directly. Instead, use one of the following:
*
* * [ApplicationExtension]: `android` extension for the `com.android.application` plugin
* used to create an Android app.
* * [LibraryExtension]: `android` extension for the `com.android.library` plugin used to
* [create an Android library](https://developer.android.com/studio/projects/android-library.html)
* * [TestExtension]: `android` extension for the `com.android.test` plugin used to create
* a separate android test project.
* * [DynamicFeatureExtension]: `android` extension for the `com.android.feature` plugin
* used to create dynamic features.
*
* The following applies the Android plugin to an app project `build.gradle` file:
*
* ```
* // Applies the application plugin and makes the 'android' block available to specify
* // Android-specific build options.
* apply plugin: 'com.android.application'
* ```
*
* To learn more about creating and organizing Android projects, read
* [Projects Overview](https://developer.android.com/studio/projects/index.html)
*/
// All the public methods are meant to be exposed in the DSL. We can't use lambdas in this class
// (yet), because the DSL reference generator doesn't understand them.
abstract class BaseExtension protected constructor(
protected val dslServices: DslServices,
protected val globalScope: GlobalScope,
/** All build outputs for all variants, can be used by users to customize a build output. */
override val buildOutputs: NamedDomainObjectContainer<BaseVariantOutput>,
private val sourceSetManager: SourceSetManager,
private val extraModelInfo: ExtraModelInfo,
private val isBaseModule: Boolean
) : AndroidConfig, Lockable {
private val _transforms: MutableList<Transform> = mutableListOf()
/** Secondary dependencies for the custom transform. */
private val _transformDependencies: MutableList<List<Any>> = mutableListOf()
private val _dexOptions = dslServices.newInstance(DexOptions::class.java)
@Deprecated("Using dexOptions is obsolete.")
override val dexOptions: DexOptions
get() {
dslServices.deprecationReporter.reportObsoleteUsage(
"dexOptions",
DeprecationReporter.DeprecationTarget.DEX_OPTIONS
)
return _dexOptions
}
private val deviceProviderList: MutableList<DeviceProvider> = Lists.newArrayList()
private val testServerList: MutableList<TestServer> = Lists.newArrayList()
private val transformList: MutableList<Transform> = Lists.newArrayList()
@get:Incubating
abstract val composeOptions: ComposeOptions
abstract override val dataBinding: DataBindingOptions
abstract val viewBinding: ViewBindingOptions
override var defaultPublishConfig: String = "release"
set(_) {
dslServices.deprecationReporter.reportObsoleteUsage(
"defaultPublishConfig",
DeprecationReporter.DeprecationTarget.VERSION_8_0
)
}
override var variantFilter: Action<VariantFilter>? = null
protected val logger: Logger = Logging.getLogger(this::class.java)
private var isWritable = true
/**
* Disallow further modification on the extension.
*/
fun disableWrite() {
isWritable = false
lock()
}
protected fun checkWritability() {
if (!isWritable) {
throw GradleException(
"Android tasks have already been created.\n" +
"This happens when calling android.applicationVariants,\n" +
"android.libraryVariants or android.testVariants.\n" +
"Once these methods are called, it is not possible to\n" +
"continue configuring the model."
)
}
}
/** For groovy only (so `compileSdkVersion=2` works) */
fun setCompileSdkVersion(apiLevel: Int) {
compileSdkVersion(apiLevel)
}
open fun buildToolsVersion(version: String) {
buildToolsVersion = version
}
open fun flavorDimensions(vararg dimensions: String) {
checkWritability()
flavorDimensionList.clear()
flavorDimensionList.addAll(dimensions)
}
fun sourceSets(action: Action<NamedDomainObjectContainer<AndroidSourceSet>>) {
checkWritability()
sourceSetManager.executeAction(action)
}
fun aaptOptions(action: Action<AaptOptions>) {
checkWritability()
action.execute(aaptOptions)
}
/**
* Specifies options for the DEX tool, such as enabling library pre-dexing.
*
* For more information about the properties you can configure in this block, see [DexOptions].
*/
@Deprecated("Setting dexOptions is obsolete.")
fun dexOptions(action: Action<DexOptions>) {
checkWritability()
action.execute(dexOptions)
}
fun lintOptions(action: Action<LintOptions>) {
checkWritability()
action.execute(lintOptions)
}
fun externalNativeBuild(action: Action<ExternalNativeBuild>) {
checkWritability()
action.execute(externalNativeBuild)
}
/**
* Specifies options for how the Android plugin should run local and instrumented tests.
*
* For more information about the properties you can configure in this block, see [TestOptions].
*/
fun testOptions(action: Action<TestOptions>) {
checkWritability()
action.execute(testOptions)
}
fun compileOptions(action: Action<CompileOptions>) {
checkWritability()
action.execute(compileOptions)
}
fun packagingOptions(action: Action<PackagingOptions>) {
checkWritability()
action.execute(packagingOptions)
}
fun jacoco(action: Action<JacocoOptions>) {
checkWritability()
action.execute(jacoco)
}
/**
* Specifies options for the
* [Android Debug Bridge (ADB)](https://developer.android.com/studio/command-line/adb.html),
* such as APK installation options.
*
* For more information about the properties you can configure in this block, see [AdbOptions].
*/
fun adbOptions(action: Action<AdbOptions>) {
checkWritability()
action.execute(adbOptions)
}
fun splits(action: Action<Splits>) {
checkWritability()
action.execute(splits)
}
/**
* Specifies options for the
* [Data Binding Library](https://developer.android.com/topic/libraries/data-binding/index.html).
*
* For more information about the properties you can configure in this block, see [DataBindingOptions]
*/
fun dataBinding(action: Action<DataBindingOptions>) {
checkWritability()
action.execute(dataBinding)
}
/**
* Specifies options for the View Binding lLibrary.
*
* For more information about the properties you can configure in this block, see [ViewBindingOptions].
*/
fun viewBinding(action: Action<ViewBindingOptions>) {
checkWritability()
action.execute(viewBinding)
}
fun deviceProvider(deviceProvider: DeviceProvider) {
checkWritability()
deviceProviderList.add(deviceProvider)
}
override val deviceProviders: List<DeviceProvider>
get() = deviceProviderList
fun testServer(testServer: TestServer) {
checkWritability()
testServerList.add(testServer)
}
override val testServers: List<TestServer>
get() = testServerList
fun registerTransform(transform: Transform, vararg dependencies: Any) {
_transforms.add(transform)
_transformDependencies.add(listOf(dependencies))
}
override val transforms: List<Transform>
get() = ImmutableList.copyOf(_transforms)
override val transformsDependencies: List<List<Any>>
get() = ImmutableList.copyOf(_transformDependencies)
open fun defaultPublishConfig(value: String) {
defaultPublishConfig = value
}
fun setPublishNonDefault(publishNonDefault: Boolean) {
logger.warn("publishNonDefault is deprecated and has no effect anymore. All variants are now published.")
}
open fun variantFilter(variantFilter: Action<VariantFilter>) {
this.variantFilter = variantFilter
}
open fun resourcePrefix(prefix: String) {
resourcePrefix = prefix
}
abstract fun addVariant(variant: BaseVariant)
fun registerArtifactType(name: String, isTest: Boolean, artifactType: Int) {
extraModelInfo.registerArtifactType(name, isTest, artifactType)
}
fun registerBuildTypeSourceProvider(
name: String,
buildType: BuildType,
sourceProvider: SourceProvider
) {
extraModelInfo.registerBuildTypeSourceProvider(name, buildType, sourceProvider)
}
fun registerProductFlavorSourceProvider(
name: String,
productFlavor: ProductFlavor,
sourceProvider: SourceProvider
) {
extraModelInfo.registerProductFlavorSourceProvider(name, productFlavor, sourceProvider)
}
fun registerJavaArtifact(
name: String,
variant: BaseVariant,
assembleTaskName: String,
javaCompileTaskName: String,
generatedSourceFolders: MutableCollection<File>,
ideSetupTaskNames: Iterable<String>,
configuration: Configuration,
classesFolder: File,
javaResourceFolder: File,
sourceProvider: SourceProvider
) {
extraModelInfo.registerJavaArtifact(
name, variant, assembleTaskName,
javaCompileTaskName, generatedSourceFolders, ideSetupTaskNames,
configuration, classesFolder, javaResourceFolder, sourceProvider
)
}
fun registerMultiFlavorSourceProvider(
name: String,
flavorName: String,
sourceProvider: SourceProvider
) {
extraModelInfo.registerMultiFlavorSourceProvider(name, flavorName, sourceProvider)
}
@NonNull
fun wrapJavaSourceSet(sourceSet: SourceSet): SourceProvider {
return SourceSetSourceProviderWrapper(sourceSet)
}
/**
* The path to the Android SDK that Gradle uses for this project.
*
* To learn more about downloading and installing the Android SDK, read
* [Update Your Tools with the SDK Manager](https://developer.android.com/studio/intro/update.html#sdk-manager)
*/
val sdkDirectory: File
get() {
return dslServices.sdkComponents.flatMap { it.sdkDirectoryProvider }.get().asFile
}
/**
* The path to the [Android NDK](https://developer.android.com/ndk/index.html) that Gradle uses for this project.
*
* You can install the Android NDK by either
* [using the SDK manager](https://developer.android.com/studio/intro/update.html#sdk-manager)
* or downloading
* [the standalone NDK package](https://developer.android.com/ndk/downloads/index.html).
*/
val ndkDirectory: File
get() {
// do not call this method from within the plugin code as it forces part of SDK initialization.
return dslServices.sdkComponents.map {
it.versionedNdkHandler(
compileSdkVersion
?: throw kotlin.IllegalStateException("compileSdkVersion not set in the android configuration"),
ndkVersion,
ndkPath
).ndkPlatform.getOrThrow().ndkDirectory
}.get()
}
// do not call this method from within the plugin code as it forces SDK initialization.
override val bootClasspath: List<File>
get() = try {
globalScope.bootClasspath.get().map { it.asFile }
} catch (e: IllegalStateException) {
listOf()
}
/**
* The path to the
* [Android Debug Bridge (ADB)](https://developer.android.com/studio/command-line/adb.html)
* executable from the Android SDK.
*/
val adbExecutable: File
get() {
return globalScope.versionedSdkLoader.flatMap {
it.adbExecutableProvider }.get().asFile
}
/** This property is deprecated. Instead, use [adbExecutable]. */
@Deprecated("This property is deprecated", ReplaceWith("adbExecutable"))
val adbExe: File
get() {
return adbExecutable
}
open fun getDefaultProguardFile(name: String): File {
if (!ProguardFiles.KNOWN_FILE_NAMES.contains(name)) {
dslServices
.issueReporter
.reportError(
IssueReporter.Type.GENERIC, ProguardFiles.UNKNOWN_FILENAME_MESSAGE
)
}
return ProguardFiles.getDefaultProguardFile(name, dslServices.buildDirectory)
}
// ---------------
// TEMP for compatibility
/** {@inheritDoc} */
override var generatePureSplits: Boolean
get() = false
set(_) = logger.warn(
"generatePureSplits is deprecated and has no effect anymore. Use bundletool to generate configuration splits."
)
@get:Suppress("WrongTerminology")
@Deprecated("Use aidlPackagedList instead", ReplaceWith("aidlPackagedList"))
override val aidlPackageWhiteList: MutableCollection<String>?
get() = aidlPackagedList
override val aidlPackagedList: MutableCollection<String>?
get() = throw GradleException("aidlPackagedList is not supported.")
// For compatibility with FeatureExtension.
override val baseFeature: Boolean
get() = isBaseModule
@Incubating
fun composeOptions(action: Action<ComposeOptions>) {
action.execute(composeOptions)
}
abstract fun compileSdkVersion(version: String)
abstract fun compileSdkVersion(apiLevel: Int)
// Kept for binary and source compatibility until the old DSL interfaces can go away.
abstract override val flavorDimensionList: MutableList<String>
abstract override var resourcePrefix: String?
abstract override var ndkVersion: String?
abstract var ndkPath: String?
abstract override var buildToolsVersion: String
abstract override val buildToolsRevision: Revision
abstract override val libraryRequests: MutableCollection<LibraryRequest>
abstract fun useLibrary(name: String)
abstract fun useLibrary(name: String, required: Boolean)
abstract override val aaptOptions: AaptOptions
abstract override val adbOptions: AdbOptions
abstract override val buildTypes: NamedDomainObjectContainer<BuildType>
abstract fun buildTypes(action: Action<in NamedDomainObjectContainer<BuildType>>)
abstract override val compileOptions: CompileOptions
abstract override var compileSdkVersion: String?
abstract override val defaultConfig: DefaultConfig
abstract fun defaultConfig(action: Action<DefaultConfig>)
abstract override val externalNativeBuild: ExternalNativeBuild
abstract override val jacoco: JacocoOptions
abstract override val lintOptions: LintOptions
abstract override val packagingOptions: PackagingOptions
abstract override val productFlavors: NamedDomainObjectContainer<ProductFlavor>
abstract fun productFlavors(action: Action<NamedDomainObjectContainer<ProductFlavor>>)
abstract override val signingConfigs: NamedDomainObjectContainer<SigningConfig>
abstract fun signingConfigs(action: Action<NamedDomainObjectContainer<SigningConfig>>)
abstract override val sourceSets: NamedDomainObjectContainer<AndroidSourceSet>
abstract override val splits: Splits
abstract override val testOptions: TestOptions
// these are indirectly implemented by extensions when they implement the new public
// extension interfaces via delegates.
abstract val buildFeatures: BuildFeatures
abstract var namespace: String?
}