Skip to content

Flutter Gradle Plugin uses antipatterns #123934

@bartekpacia

Description

@bartekpacia

Flutter Gradle Plugin 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. Here's a paragraph that might be useful:

    When interacting with AGP, use specially made extension points instead of registering the typical Gradle lifecycle callbacks (such as afterEvaluate()) 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:

            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.

    For example, copyFluterAssets{flavor} puts its output into the output directory of merge{flavor}Assets task here. 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 again as an example.

    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
    }
  3. Build structure
    https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources

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.

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listplatform-androidAndroid applications specificallyt: gradle"flutter build" and "flutter run" on Androidteam-androidOwned by Android platform teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-androidTriaged by Android platform team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions