Repository: flutter
Issue: Flutter Gradle Plugin uses antipatterns
Labels: platform-android,tool,t: gradle,P2,team-android,triaged-android

[Flutter Gradle Plugin](https://github.com/flutter/flutter/blob/3.7.9/packages/flutter_tools/gradle/flutter.gradle) makes use of a few patterns that are considered to be "bad Gradle".

1. Names of AGP tasks are "guessed", instead of hooking up into official extension points.

   I learned about this from [Extend the Android Gradle Plugin article](https://developer.android.com/studio/build/extend-agp). [Here's a paragraph](https://developer.android.com/studio/build/extend-agp#variant-api-artifacts-tasks) that might be useful:

    > 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.

   This is not what FGP does. Instead, it finds tasks by gluing strings together:

    ```groovy
            Task copyFlutterAssetsTask = project.tasks.create(
                name: "copyFlutterAssets${variant.name.capitalize()}",
                type: Copy,
            ) {
                 // ...
                dependsOn "clean${mergeAssets.name.capitalize()}"
                mergeAssets.mustRunAfter("clean${mergeAssets.name.capitalize()}")
                // ...
            }


            // ...
            def compressAssetsTask = project.tasks.findByName("compress${variant.name.capitalize()}Assets")
            if (compressAssetsTask) {
                compressAssetsTask.dependsOn copyFlutterAssetsTask
            }
    ```

    This is exactly what the Android docs advise against.

2. Dependencies between tasks are defined explicitly, instead of being inferred on the basis of inputs/outputs. Also, FGP tasks output their files into AGP task's output directories.

    I realized this after reading [this great article by a former Gradle engineer](https://melix.github.io/blog/2021/10/gradle-quickie-dependson.html).

    For example, `copyFluterAssets{flavor}` puts its output into the output directory of `merge{flavor}Assets` task [here](https://github.com/flutter/flutter/blob/3.7.6/packages/flutter_tools/gradle/flutter.gradle#L954). The relevant excerpt:

    > multiple tasks contributing to the same output directory is the typical example of what would break caching. In fact, it breaks all kinds of up-to-date checking, that is to say, the ability for Gradle to understand that it doesn’t need to execute a task when nothing changed.

    Let's take the [`copyFlutterAssetsTask`](https://github.com/flutter/flutter/blob/1d90b7654afadaa848aca307971b4cb934f17144/packages/flutter_tools/lib/src/android/gradle_utils.dart#L164-L209) again as an example.

    ```groovy
    Task copyFlutterAssetsTask = project.tasks.create(
        name: "copyFlutterAssets${variant.name.capitalize()}",
        type: Copy,
    ) {
        dependsOn compileTask // explicit dependency - bad
        with compileTask.assets
        if (isUsedAsSubproject) {
            dependsOn packageAssets // explicit dependency - bad
            dependsOn cleanPackageAssets // explicit dependency - bad
            into packageAssets.outputDir // contributes its own output into output dir of another task - bad
            return
        }
       
       
        dependsOn mergeAssets // explicit dependency - bad
        dependsOn "clean${mergeAssets.name.capitalize()}" // explicit dependency - bad
        mergeAssets.mustRunAfter("clean${mergeAssets.name.capitalize()}") // forcing order - bad
        into mergeAssets.outputDir // contributes its own output into output dir of another task - bad
    }
    ```

It's not anything critical, of course, but I think it's good to have these points noted somewhere and fix them in the long run. I think it'd be good to do it _after_ #121541  because writing Kotlin is faster and more pleasant than writing Groovy :)

This is somewhat related to #119196.

Thanks @gnprice for [motivating me to write this down](https://github.com/flutter/flutter/issues/117043#issuecomment-1489690949).