Android Gradle Recipes

repository·agp-9.0·Indexed 25 days ago

https://github.com/android/gradle-recipes

A collection of implementation patterns and recipes for developers using Android Gradle Plugin (AGP) version 9.0. It covers common build tasks, API interactions, and plugin customizations, including the use of finalizeDsl, BuildConfig generation, custom source type registration, and managing MultipleArtifact and ScopedArtifact collections.

Tokens
17.5K
Snippets
62
Records
105
Agent score
76%

What's inside android-gradle-recipes

  1. What is the Fused Library Plugin?

    agp-9.0

    The Fused Library Plugin is an Android Gradle Plugin designed for Android library developers who need to publish multiple Android libraries within a single .aar artifact.

    Warning: This plugin is currently in an early testing phase. Artifacts and plugin behavior may be unstable. Frequent breaking changes may occur, and there is no guarantee of correctness for distributed artifacts. It is recommended to use the most recent Android Studio Canary and AGP alpha releases.

  2. Browse recipes by theme

    agp-9.0

    Recipes are categorized into themes to help you find solutions for specific Android build concerns. Available themes include:

    • Android Assets: Handling assets and source folders (e.g., legacyTaskBridging, addGeneratedSourceFolder).
    • Android Manifest: Manipulating the manifest (e.g., transformManifest, createSingleArtifact).
    • Artifact API: Interacting with the AGP Artifact API for transformations and listening to artifacts (e.g., listenToArtifacts, transformDirectory, getScopedArtifacts).
    • DSL: Extending the Android Gradle Plugin DSL (e.g., extendingAgp).
    • Dependency Resolution: Managing variant dependency substitution.
    • Sources: Managing source sets and generated folders (e.g., addCustomSourceType).
  3. Explore AGP 9.0 Recipes via Call Chains

    agp-9.0

    The gradle-recipes repository provides a mapping of common Android Gradle Plugin (AGP) 9.0 tasks to the specific API call chains required to implement them. You can find recipes by searching for the functional goal (e.g., "transforming a manifest" or "adding build config fields") and following the corresponding method chain.

    Key call chains include:

    • Extending AGP DSL: DslExtension.Builder().extendProjectWith().extendBuildTypeWith().extendProductFlavorWith().build()
    • Variant Artifact Manipulation: Using variant.artifacts.use().wiredWith().to...() patterns to append, create, or transform artifacts.
    • Variant Lifecycle Hooks: Using androidComponents.onVariants {} to perform actions when variants are created.
    • Source Set Management: Using variant.sources.*.addGeneratedSourceDirectory() or addStaticSourceDirectory() to manage source files.
  4. Browse recipes by plugin feature

    agp-9.0

    Recipes are also organized by the specific plugin features they target. Key feature categories include:

    • Fused Library Plugin: Recipes for applying the fused library plugin.
    • Kotlin Multiplatform: Recipes for Kotlin Multiplatform library setups.
    • TestFixtures: Recipes for managing test fixtures.
  5. Implement DSL extensions using the Variant Extension pattern

    agp-9.0

    When creating DSL extensions for Project, BuildType, or ProductFlavor, you must provide a VariantExtension. The VariantExtension should act as the single source of truth for a specific variant by merging values from all registered extensions.

    Key Implementation Rules:

    1. Use Gradle Providers: All fields in the variant extension must be implemented using org.gradle.api.provider.Property or related classes. This ensures that the final value is resolved correctly regardless of the order in which plugins are configured.
    2. Task Inputs: Only use the values from the VariantExtension as Task inputs. Do not use values from the Project, BuildType, or ProductFlavor extensions directly in tasks, as they might be further modified by other plugins via the onVariants API.
    3. Avoid Configuration Phase Access: Never call org.gradle.api.provider.Property.get() during the configuration phase. Instead, pass the Property instance itself as the Task input so the value is resolved during execution.
  6. Registering callbacks using onVariants in a plugin

    agp-9.0

    The onVariants API allows you to access and modify variant objects after all AGP artifacts have been determined. Because of this timing, you can only modify Property values that are resolved during task execution (e.g., applicationId). This API is useful for wiring variant properties to providers from custom tasks.

    Unlike beforeVariants, onVariants provides access to variants only after their configuration is finalized, meaning you cannot change structural aspects of the variant, only the values of its properties.

    val releaseSelector = androidComponents.selector().withBuildType("release")
    
    androidComponents.onVariants(releaseSelector) { variant ->
         variant.applicationId.set("newApplicationId")
    }
  7. Manage Variant Artifacts

    agp-9.0

    AGP 9.0 provides a robust API for interacting with variant artifacts. Depending on your goal, use the following patterns:

    • Append to Scoped Artifacts: variant.artifacts.forScope().use().toAppend()
    • Get Scoped Artifacts: variant.artifacts.forScope().use().toGet()
    • Transform All Classes: variant.artifacts.forScope().use().toTransform()
    • Create a Single Artifact: variant.artifacts.use().wiredWith().toCreate()
    • Listen to Artifacts: variant.artifacts.use().wiredWith().toListenTo()
    • Transform Multiple Artifacts: variant.artifacts.use().wiredWith().toTransform() (for multiple) or variant.artifacts.use().wiredWithDirectories().toTransformMany() (for directories).
  8. How Android Variant source types work

    agp-9.0

    In the Android Variant API, source folders are managed through the Component.sources method. This provides access to all source folders for various types such as java, kotlin, java resources, android resources, shaders, and assets.

    There are two types of SourceDirectories available:

    1. Flat: Directories are stored as a simple collection.
    2. Layered: Directories are stored as a Provider<List<Collection<Directory>>>. For example, assets is a Layered source type.

    You can extend any of these source types using the addGeneratedSourceDirectory mechanism.

  9. Limitations on renaming APKs via AGP transformations

    agp-9.0

    While you can use workers to transform APKs (e.g., by copying them to a new location), it is not recommended to simply rename the APKs generated by the default task.

    Android Studio expects specific file names for deployment. If you rename the files (for example, adding a date/time stamp), Studio's deployment mechanism will fail because it will no longer be able to locate the expected files. The AGP API is designed to allow copying/transforming artifacts, but not to change the primary output names that Studio relies on.

  10. Use beforeVariants to configure VariantBuilder properties

    agp-9.0

    The beforeVariants method allows you to register a callback that receives a VariantBuilder. The VariantBuilder contains writable properties that impact the project configuration and build flows.

    Important Lifecycle Note: You must use VariantBuilder within beforeVariants to change build flow settings (like minification). Once beforeVariants callbacks have finished, AGP creates Variant instances. Variant instances can only impact task execution and cannot be used to change the build flow (e.g., you cannot toggle isMinifyEnabled using a Variant instance).

  11. Use the `include` configuration to fuse dependencies

    agp-9.0

    Instead of standard implementation or api configurations, the Fused Library Plugin uses a new configuration called include. This configuration declares which dependencies will be fused into the resulting .aar file.

    Supported dependency types:

    • Project dependencies: include(project(":module-name"))
    • External dependencies: include("group:artifact:version")
    • File dependencies: include(files("path/to/file.jar"))

    Restrictions:

    • This configuration is not transitive; dependencies of included components will not be included in the fused artifact.
    • There is no support for file dependencies except for .jar files.
    • DataBinding dependencies are prohibited.
    dependencies {
        include(project(":androidLib1"))
        include(project(":androidLib2"))
        include("com.google.code.gson:gson:2.11.0")
        include(files("libs/simple-jar-with-A_DoIExist-class.jar"))
    }
  12. How custom source types and SourceDirectories work

    agp-9.0

    When you register a custom source type, AGP manages them as SourceDirectories.

    Custom sources are always of type Flat, which means the directories are provided as a Provider<Collection<Directory>>. This is in contrast to Layered source directories.

    If you need to add a folder whose content is generated by a task during execution, use SourceDirectories.addGeneratedSourceDirectory and provide the pointer to the output folder where the files will be generated.