The Android Gradle plugin (AGP) is the official build system for Android applications. It includes support for compiling many different types of sources and linking them together into an application that you can run on a physical Android device or an emulator.

AGP contains extension points for plugins to control build inputs and extend its functionality through new steps that can be integrated with standard build tasks. Previous versions of AGP did not have official APIs clearly separated from internal implementations. Starting in version 7.0, AGP has a set of[official, stable APIs](https://developer.android.com/reference/tools/gradle-api)that you can rely on.

## AGP API lifecycle

AGP follows the[Gradle feature lifecycle](https://docs.gradle.org/current/userguide/feature_lifecycle.html)to designate the state of its APIs:

- **Internal**: Not intended for public use
- **Incubating**: Available for public use but not final, which means that they may not be backward compatible in the final version
- **Public**: Available for public use and stable
- **Deprecated**: No longer supported, and replaced with new APIs

## Deprecation policy

AGP is evolving with the deprecation of old APIs and their replacement with new, stable APIs and a new Domain Specific Language (DSL). This evolution will span multiple AGP releases, and you can learn more about it at the[AGP API/DSL migration timeline](https://developer.android.com/studio/releases/gradle-plugin-roadmap).

When AGP APIs are deprecated, for this migration or otherwise, they will continue to be available in the current major release but will generate warnings. Deprecated APIs will be fully removed from AGP in the subsequent major release. For example, if an API is deprecated in AGP 7.0, it will be available in that version and generate warnings. That API will no longer be available in AGP 8.0.

To see examples of new APIs used in common build customizations, take a look at the[Android Gradle plugin recipes](https://github.com/android/gradle-recipes). They provide examples of common build customizations. You can also find more details about the new APIs in our[reference documentation](https://developer.android.com/reference/tools/gradle-api).

## Gradle build basics

This guide doesn't cover the entire Gradle build system. However, it does cover the minimum necessary set of concepts to help you integrate with our APIs, and links out to the main Gradle documentation for further reading.

We do assume basic knowledge about how Gradle works, including how to configure projects, edit build files, apply plugins, and run tasks. To learn about the basics of Gradle with respect to AGP, we recommend reviewing[Configure your build](https://developer.android.com/studio/build). To learn about the general framework for customizing Gradle plugins, see[Developing Custom Gradle Plugins](https://docs.gradle.org/current/userguide/custom_plugins.html).

### Gradle lazy types glossary

Gradle offers a number of types that behave "lazily," or help defer heavy computations or[`Task`](https://docs.gradle.org/current/javadoc/org/gradle/api/Task.html)creation to later phases of the build. These types are at the core of many Gradle and AGP APIs. The following list includes the main Gradle types involved in lazy execution, and their key methods.

[`Provider<T>`](https://docs.gradle.org/current/javadoc/org/gradle/api/provider/Provider.html)
:   Provides a value of type`T`(where "T" means any type), which can be read during the execution phase using[`get()`](https://docs.gradle.org/current/javadoc/org/gradle/api/provider/Provider.html#get--)or transformed into a new`Provider<S>`(where "S" means some other type) using the`map()`,`flatMap()`, and`zip()`methods. Note that`get()`should never be called during the configuration phase.

    - [`map()`](https://docs.gradle.org/current/javadoc/org/gradle/api/provider/Prov%0Aider.html#map-org.gradle.api.Transformer-): Accepts a[lambda](https://kotlinlang.org/docs/lambdas.html#higher-%0Aorder-functions)and produces a`Provider`of type`S`,`Provider<S>`. The lambda argument to`map()`takes the value`T`and produces the value`S`. The lambda is not executed immediately; instead, its execution is deferred to the moment`get()`is called on the resulting`Provider<S>`, making the whole chain lazy.
    - [`flatMap()`](https://docs.gradle.org/current/javadoc/org/gradle/api/provider/Provider.html#flatMap-org.gradle.api.Transformer-): Also accepts a lambda and produces`Provider<S>`, but the lambda takes a value`T`and produces`Provider<S>`(instead of producing the value`S`directly). Use flatMap() when S cannot be determined at configuration time and you can obtain only`Provider<S>`. Practically speaking, if you used`map()`and ended up with a`Provider<Provider<S>>`result type, that probably means you should have used`flatMap()`instead.
    - [`zip()`](https://docs.gradle.org/current/javadoc/org/gradle/api/provider/Provider.html#zip-org.gradle.api.provider.Provider-java.util.function.BiFunction-): Lets you combine two`Provider`instances to produce a new`Provider`, with a value computed using a function that combines the values from the two input`Providers`instances.

[`Property<T>`](https://docs.gradle.org/current/javadoc/org/gradle/api/provider/Property.html)
:   Implements`Provider<T>`, so it also provides a value of type`T`. Unlike with`Provider<T>`, which is read-only, you can also set a value for the`Property<T>`. There are two ways to do so:

    - Set a value of type`T`directly when it's available, without the need for deferred computations.
    - Set another`Provider<T>`as the source of the value of the`Property<T>`. In this case, the value`T`is materialized only when`Property.get()`is called.

[`TaskProvider`](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskProvider.html)
:   Implements`Provider<Task>`. To generate a`TaskProvider`, use[`tasks.register()`](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskContainer.html#register-java.lang.String-)and not[`tasks.create()`](https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskContainer.html#create-java.lang.String-), to ensure tasks are only instantiated lazily when they're needed. You can use`flatMap()`to access the outputs of a`Task`before the`Task`is created, which can be useful if you want to use the outputs as inputs to other`Task`instances.

Providers and their transformation methods are essential for setting up inputs and outputs of tasks in a lazy way, that is, without the need to create all tasks up front and resolve the values.

Providers also carry task dependency information. When you create a`Provider`by transforming a`Task`output, that`Task`becomes an implicit dependency of the`Provider`and will be created and run whenever the value of the`Provider`is resolved, such as when another`Task`requires it.

Here's an example of registering two tasks,`GitVersionTask`and`ManifestProducerTask`, while deferring creation of the`Task`instances until they are actually required. The`ManifestProducerTask`input value is set to a`Provider`obtained from the output of`GitVersionTask`, so`ManifestProducerTask`implicitly depends on`GitVersionTask`.  

    // Register a task lazily to get its TaskProvider.
    val gitVersionProvider: TaskProvider =
        project.tasks.register("gitVersionProvider", GitVersionTask::class.java) {
            it.gitVersionOutputFile.set(
                File(project.buildDir, "intermediates/gitVersionProvider/output")
            )
        }

    ...

    /**
     * Register another task in the configuration block (also executed lazily,
     * only if the task is required).
     */
    val manifestProducer =
        project.tasks.register(variant.name + "ManifestProducer", ManifestProducerTask::class.java) {
            /**
             * Connect this task's input (gitInfoFile) to the output of
             * gitVersionProvider.
             */
            it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
        }

These two tasks will only execute if they are explicitly requested. This can happen as part of a Gradle invocation, for example, if you run`./gradlew
debugManifestProducer`, or if the output of`ManifestProducerTask`is connected to some other task and its value becomes required.

While you will write custom tasks that consume inputs and/or produce outputs, AGP doesn't offer public access to its own tasks directly. They are an implementation detail subject to change from version to version. Instead, AGP offers the Variant API and access to the output of its tasks, or*build artifacts* , that you can read and transform. See[Variant API, Artifacts, and Tasks](https://developer.android.com/build/extend-agp#variant-api-artifacts-tasks)in this document for more information.

## Gradle build phases

Building a project is inherently a complicated and resource demanding process, and there are various features such as task configuration avoidance, up-to-date checks, and the configuration caching feature that help minimize the time spent on reproducible or unnecessary computations.

To apply some of these optimizations, Gradle scripts and plugins must obey strict rules during each of the distinct Gradle build phases: initialization, configuration, and execution. In this guide, we will focus on the configuration and execution phases. You can find more information about all the phases in the[Gradle build lifecycle guide](https://docs.gradle.org/current/userguide/build_lifecycle.html).

### Configuration phase

During the configuration phase, the build scripts for all projects that are part of the build are evaluated, the plugins are applied, and build dependencies are resolved. This phase should be used to configure the build using DSL objects and for registering tasks and their inputs lazily.

Because the configuration phase always runs, regardless of which task is requested to run, it is especially important to keep it lean and restrict any computations from depending on inputs other than the build scripts themselves. That is, you shouldn't execute external programs or read from the network, or perform long computations that can be deferred to the execution phase as proper`Task`instances.
| **Note:** With the upcoming configuration caching feature the result of this phase will be cached for subsequent runs, but only if[special care](https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:requirements)is taken to let the build system know about any dynamic inputs such as file reads or access to environment variables.

### Execution phase

In the execution phase, the requested tasks and their dependent tasks are executed. Specifically, the`Task`class method(s) marked with`@TaskAction`are executed. During task execution, you are allowed to read from inputs (such as files) and resolve lazy providers by calling`Provider<T>.get()`. Resolving lazy providers this way kicks off a sequence of`map()`or`flatMap()`calls that follow the task dependency information contained within the provider. Tasks are run lazily to materialize the required values.

## Variant API, Artifacts, and Tasks

The Variant API is an extension mechanism in the Android Gradle plugin that lets you manipulate the various options, normally set using the[DSL](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/dsl/ApplicationExtension)in build configuration files, that influence the Android build. The Variant API also gives you access to intermediate and final artifacts that are created by the build, such as class files, the merged manifest, or APK/AAB files.

### Android build flow and extension points

When interacting with AGP, use specially made extension points instead of registering the typical Gradle lifecycle callbacks (such as[`afterEvaluate()`](https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html#afterEvaluate-org.gradle.api.Action-)) or setting up explicit`Task`dependencies. Tasks created by AGP are considered implementation details and are not exposed as a public API. You must avoid trying to get instances of the`Task`objects or guessing the`Task`names and adding callbacks or dependencies to those`Task`objects directly.

AGP completes the following steps to create and execute its`Task`instances, which in turn produce the build artifacts. The main steps involved in[`Variant`](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/variant/Variant)object creation are followed by callbacks that let you make changes to certain objects created as part of a build. It's important to note that all of the callbacks happen during the[configuration phase](https://developer.android.com/build/extend-agp#configuration-phase)(described on this page) and must run fast, deferring any complicated work to proper`Task`instances during the execution phase instead.

1. **DSL parsing** : This is when build scripts are evaluated, and when the various properties of the Android DSL objects from the`android`block are created and set. The Variant API callbacks described in the following sections are also registered during this phase.
2. [`finalizeDsl()`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/extension/AndroidComponentsExtension#finalizedsl): Callback that lets you change DSL objects before they are locked for component (variant) creation.`VariantBuilder`objects are created based on data contained in the DSL objects.

3. **DSL locking**: DSL is now locked and changes are no longer possible.

4. [`beforeVariants()`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/extension/AndroidComponentsExtension#beforevariant%0As): This callback can influence which components are created, and some of their properties, through[`VariantBuilder`](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/variant/VariantBuilder). It still allows modifications to the build flow and the artifacts that are produced.

5. **Variant creation**: The list of components and artifacts that will be created is now finalized and cannot be changed.

6. [`onVariants()`](https://developer.android.com/reference/tools/gradle-api/4.2/com/android/build/api/extension/AndroidComponentsExtension#onvariants): In this callback, you get access to the created`Variant`objects and you can set values or providers for the`Property`values they contain, to be computed lazily.

7. **Variant locking**: Variant objects are now locked and changes are no longer possible.

8. **Tasks created** :`Variant`objects and their`Property`values are used to create the`Task`instances that are necessary to perform the build.

AGP introduces an[`AndroidComponentsExtension`](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/extension/AndroidComponentsExtension)that lets you register callbacks for`finalizeDsl()`,`beforeVariants()`and`onVariants()`. The extension is available in build scripts through the`androidComponents`block:  

    // This is used only for configuring the Android build through DSL.
    android { ... }

    // The androidComponents block is separate from the DSL.
    androidComponents {
       finalizeDsl { extension ->
          ...
       }
    }

However, our recommendation is to keep build scripts only for declarative configuration using the android block's DSL and[move any custom imperative logic to`buildSrc`](https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources)or external plugins. You can also take a look at the[`buildSrc`samples](https://github.com/android/gradle-recipes/tree/agp-7.0/BuildSrc/)in our Gradle recipes GitHub repository to learn how to create a plugin in your project. Here is an example of registering the callbacks from plugin code:  

    abstract class ExamplePlugin: Plugin<Project> {

        override fun apply(project: Project) {
            val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
            androidComponents.finalizeDsl { extension ->
                ...
            }
        }
    }

Let's take a closer look at the available callbacks and the type of use cases that your plugin can support in each of them:

#### `finalizeDsl(callback: (DslExtensionT) -> Unit)`

In this callback, you are able to access and modify the DSL objects that were created by parsing the information from the`android`block in the build files. These DSL objects will be used to initialize and configure variants in later phases of the build. For example, you can programmatically create new configurations or override properties---but keep in mind that all values must be resolved at configuration time, so they must not rely on any external inputs. After this callback finishes executing, the DSL objects are no longer useful and you should no longer hold references to them or modify their values.  

    abstract class ExamplePlugin: Plugin<Project> {

        override fun apply(project: Project) {
            val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
            androidComponents.finalizeDsl { extension ->
                extension.buildTypes.create("extra").let {
                    it.isJniDebuggable = true
                }
            }
        }
    }

#### `beforeVariants()`

At this stage of the build, you get access to`VariantBuilder`objects, which determine the variants that will be created and their properties. For example, you can programmatically disable certain variants, their tests, or change a property's value (for example,`minSdk`) only for a chosen variant. Similar to`finalizeDsl()`, all of the values you provide must be resolved at configuration time and not depend on external inputs. The`VariantBuilder`objects must not be modified once execution of the`beforeVariants()`callback finishes.  

    androidComponents {
        beforeVariants { variantBuilder ->
            variantBuilder.minSdk = 23
        }
    }

The`beforeVariants()`callback optionally takes a[`VariantSelector`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/extension/VariantSelector), which you can obtain through the[`selector()`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/extension/AndroidComponentsExtension#selector())method on the[`androidComponentsExtension`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/extension/AndroidComponentsExtension). You can use it to filter components participating in the callback invocation based on their name, build type, or product flavor.  

    androidComponents {
        beforeVariants(selector().withName("adfree")) { variantBuilder ->
            variantBuilder.minSdk = 23
        }
    }

#### `onVariants()`

By the time`onVariants()`is called, all the artifacts that will be created by AGP are already decided so you can no longer disable them. You can, however, modify some of the values used for the tasks by setting them for`Property`attributes in the`Variant`objects. Because the`Property`values will only be resolved when AGP's tasks are executed, you can safely wire them up to providers from your own custom tasks that will perform any required computations, including reading from external inputs such as files or the network.  

    // onVariants also supports VariantSelectors:
    onVariants(selector().withBuildType("release")) { variant ->
        // Gather the output when we are in single mode (no multi-apk).
        val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

        // Create version code generating task
        val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
            it.outputFile.set(project.layout.buildDirectory.file("${variant.name}/versionCode.txt"))
        }
        /**
         * Wire version code from the task output.
         * map() will create a lazy provider that:
         * 1. Runs just before the consumer(s), ensuring that the producer
         * (VersionCodeTask) has run and therefore the file is created.
         * 2. Contains task dependency information so that the consumer(s) run after
         * the producer.
         */
        mainOutput.versionCode.set(versionCodeTask.map { it.outputFile.get().asFile.readText().toInt() })
    }

| **Note:** When you generate files per variant make sure to add`${variant.name}/`to all filenames to prevent them from being overwritten when building multiple variants.

### Contribute generated sources to the build

Your plugin can contribute a few types of generated sources, such as:

- Application code in the`java`directory
- [Android resources](https://developer.android.com/guide/topics/resources/available-resources)in the`res`directory
- [Java resources](https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_project_layout)in the`resources`directory
- [Android assets](https://developer.android.com/reference/android/content/res/AssetManager)in the`assets`directory

For the full list of sources you can add, see the[Sources API](https://developer.android.com/reference/tools/gradle-api/7.4/com/android/build/api/variant/Sources).

This code snippet shows how to add a custom source folder called`${variant.name}`to the Java source set using the`addStaticSourceDirectory()`function. The Android toolchain then processes this folder.  

    onVariants { variant ->
        variant.sources.java?.let { java ->
            java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
        }
    }

See the[addJavaSource recipe](https://github.com/android/gradle-recipes/tree/agp-8.0/Kotlin/addJavaSource)for more details.

This code snippet shows how to add a directory with Android resources generated from a custom task to the`res`source set. The process is similar for other source types.  

    onVariants(selector().withBuildType("release")) { variant ->
        // Step 1. Register the task.
        val resCreationTask =
           project.tasks.register<ResCreatorTask>("create${variant.name}Res")

        // Step 2. Register the task output to the variant-generated source directory.
        variant.sources.res?.addGeneratedSourceDirectory(
           resCreationTask,
           ResCreatorTask::outputDirectory)
        }

    ...

    // Step 3. Define the task.
    abstract class ResCreatorTask: DefaultTask() {
       @get:OutputFiles
       abstract val outputDirectory: DirectoryProperty

       @TaskAction
       fun taskAction() {
          // Step 4. Generate your resources.
          ...
       }
    }

See the[addCustomAsset recipe](https://github.com/android/gradle-recipes/tree/agp-8.0/Kotlin/addCustomAsset)for more details.

### Access and modify artifacts

In addition to letting you modify simple properties on the`Variant`objects, AGP also contains an extension mechanism that allows you to read or transform intermediate and final artifacts produced during the build. For example, you can read the final, merged`AndroidManifest.xml`file contents in a custom`Task`to analyze it, or you can replace its content entirely with that of a manifest file generated by your custom`Task`.

You can find the list of artifacts currently supported in the reference documentation for the[`Artifact`](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/artifact/Artifact)class. Every artifact type has certain properties that are useful to know:

#### Cardinality

The cardinality of an[`Artifact`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/artifact/Artifact)represents its number of[`FileSystemLocation`](https://docs.gradle.org/current/javadoc/org/gradle/api/file/FileSystemLocation.html)instances, or the number of files or directories of the artifact type. You can get information about the cardinality of an artifact by checking its parent class: Artifacts with a single`FileSystemLocation`will be a subclass of[`Artifact.Single`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/artifact/Artifact.Single); artifacts with multiple`FileSystemLocation`instances will be a subclass of[`Artifact.Multiple`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/artifact/Artifact.Multiple).

#### `FileSystemLocation`type

You can check if an`Artifact`represents files or directories by looking at its parameterized`FileSystemLocation`type, which can be either a[`RegularFile`](https://docs.gradle.org/current/javadoc/org/gradle/api/file/RegularFile.html)or a[`Directory`](https://docs.gradle.org/current/javadoc/org/gradle/api/file/Directory.html).

#### Supported operations

Every`Artifact`class can implement any of the following interfaces to indicate which operations it supports:

- [`Transformable`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/artifact/Artifact.Transformable): Allows an`Artifact`to be used as an input to a`Task`that performs arbitrary transformations on it and outputs a new version of the`Artifact`.
- [`Appendable`](https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/artifact/Artifact.Appendable): Applies only to artifacts that are subclasses of`Artifact.Multiple`. It means that the`Artifact`can be appended to, that is, a custom`Task`can create new instances of this`Artifact`type which will be added to the existing list.
- [`Replaceable`](https://developer.android.com/reference/tools/gradle-api/4.1/com/android/build/api/artifact/Artifact.Replaceable): Applies only to artifacts that are subclasses of`Artifact.Single`. A replaceable`Artifact`can be replaced by an entirely new instance, produced as an output of a`Task`.

In addition to the three artifact-modifying operations, every artifact supports a[`get()`](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/artifact/Artifacts#get)(or[`getAll()`](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/artifact/Artifacts#getall)) operation, which returns a`Provider`with the final version of the artifact (after all operations on it are finished).

Multiple plugins can add any number of operations on artifacts into the pipeline from the`onVariants()`callback, and AGP will ensure they are chained properly so that all tasks run at the right time and artifacts are correctly produced and updated. This means that when an operation changes any outputs by appending, replacing, or transforming them, the next operation will see the updated version of these artifacts as inputs, and so on.

The entry point into registering operations is the`Artifacts`class. The following code snippet shows how you can get access to an instance of`Artifacts`from a property on the`Variant`object in the`onVariants()`callback.

You can then pass in your custom`TaskProvider`to get a[`TaskBasedOperation`](https://developer.android.com/reference/tools/gradle-%0Aapi/7.1/com/android/build/api/artifact/TaskBasedOperation)object (1), and use it to connect its inputs and outputs using one of the`wiredWith*`methods (2).

The exact method you need to choose depends on the cardinality and`FileSystemLocation`type implemented by the`Artifact`that you want to transform.

And finally, you pass in the`Artifact`type to a method representing the chosen operation on the`*OperationRequest`object that you get in return, for example,[`toAppendTo()`](https://developer.android.com/reference/tools/gradle-%0Aapi/7.1/com/android/build/api/artifact/OutOperationRequest#toappendto),[`toTransform()`](https://developer.android.com/reference/tools/gradle-%0Aapi/7.1/com/android/build/api/artifact/InAndOutFileOperationRequest#totransform), or[`toCreate()`](https://developer.android.com/reference/tools/gradle-%0Aapi/7.1/com/android/build/api/artifact/OutOperationRequest#tocreate)(3).  

    androidComponents.onVariants { variant ->
        val manifestUpdater = // Custom task that will be used for the transform.
                project.tasks.register(variant.name + "ManifestUpdater", ManifestTransformerTask::class.java) {
                    it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
                }
        // (1) Register the TaskProvider w.
        val variant.artifacts.use(manifestUpdater)
             // (2) Connect the input and output files.
            .wiredWithFiles(
                ManifestTransformerTask::mergedManifest,
                ManifestTransformerTask::updatedManifest)
            // (3) Indicate the artifact and operation type.
            .toTransform(SingleArtifact.MERGED_MANIFEST)
    }

In this example,`MERGED_MANIFEST`is a`SingleArtifact`, and it is a`RegularFile`. Because of that, we need to use the[`wiredWithFiles`](https://developer.android.com/reference/tools/gradle-api/7.0/com/android/build/api/artifact/TaskBasedOperation#wiredWithFiles(kotlin.Function1,%20kotlin.Function1))method, which accepts a single`RegularFileProperty`reference for the input, and a single`RegularFileProperty`for the output. There are other`wiredWith*`methods on the`TaskBasedOperation`class that will work for other combinations of`Artifact`cardinality and`FileSystemLocation`types.

To learn more about extending AGP, we recommend reading the following sections from the Gradle build system manual:

- [Developing Custom Gradle Plugins](https://docs.gradle.org/current/userguide/custom_plugins.html)
- [Implementing Gradle plugins](https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html)
- [Developing Custom Gradle Task Types](https://docs.gradle.org/current/userguide/custom_tasks.html)
- [Lazy Configuration](https://docs.gradle.org/current/userguide/lazy_configuration.html)
- [Task Configuration Avoidance](https://docs.gradle.org/current/userguide/task_configuration_avoidance.html)