[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flutter Gradle Plugin uses antipatterns #123934

Open
bartekpacia opened this issue Apr 1, 2023 · 6 comments
Open

Flutter Gradle Plugin uses antipatterns #123934

bartekpacia opened this issue Apr 1, 2023 · 6 comments
Labels
P2 Important issues not at the top of the work list platform-android Android applications specifically t: gradle "flutter build" and "flutter run" on Android team-android Owned by Android platform team tool Affects the "flutter" command-line tool. See also t: labels. triaged-android Triaged by Android platform team

Comments

@bartekpacia
Copy link
Member
bartekpacia commented Apr 1, 2023

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
    }

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.

@danagbemava-nc danagbemava-nc added the in triage Presently being triaged by the triage team label Apr 3, 2023
@danagbemava-nc
Copy link
Member

Hi @bartekpacia, it looks like the issue you linked to #122579 is not related to this issue. Kindly update the issue with the correct link.

Thank you

@danagbemava-nc danagbemava-nc added platform-android Android applications specifically tool Affects the "flutter" command-line tool. See also t: labels. t: gradle "flutter build" and "flutter run" on Android and removed in triage Presently being triaged by the triage team labels Apr 3, 2023
@bartekpacia
Copy link
Member Author

Hi @danagbemava-nc, thanks for triaging this issue, and sorry for the mistake. I meant #121541 - I edited my post.

@reidbaker reidbaker added the P2 Important issues not at the top of the work list label Apr 3, 2023
@reidbaker
Copy link
Contributor

@bartekpacia while is by no means required, As you work on the kotlin conversion stuff please feel free to add groovy/gradle/gradle-kotlin section to the style guide AND/OR add lint checkers for items you see as anti patterns.

I know historically groovy/gradle has been one of the areas we mostly focused on getting it to work without a ton of deep expertise in the language (especially compared to dart).

@bartekpacia
Copy link
Member Author
bartekpacia commented Apr 4, 2023

Good idea.

Re: Gradle style guide – cool idea, but that'd be quite a lot of effort. For now, if somebody's interested I'd recommend reading:

Re: lints checks - I think that we should at least make sure that no warnings are emitted by Gradle in a default flutter created app. These warnings often become errors in later Gradle/AGP versions.

@reidbaker
Copy link
Contributor

Good idea.

Re: Gradle style guide – cool idea, but that'd be quite a lot of effort. For now, if somebody's interested I'd recommend reading:

Re: lints checks - I think that we should at least make sure that no warnings are emitted by Gradle in a default flutter created app. These warnings often become errors in later Gradle/AGP versions.

Yeah I agree creating a style guide that is solid is a lot of work. My intent was more to indicate that if you run across things that bother you feel free to add a gradle style section so we can start to enforce what you have found to be best practices.

It may say "Do not do XYZ and instead do ABC" and that is all.

@SichangHe
Copy link

May be related:

Android Studio Build Analyzer report.

How do I follow the recommendation from Build Analyzer by editing my build.gradle:
:app:copyFlutterAssetsDebug This task frequently determines build duration because of dependencies between its inputs/outputs and other tasks. Duration: 6.9s / 43.5% Sub-project: :app Plugin: FlutterPlugin Type: org.gradle.api.tasks.Copy Task Execution Categories: Uncategorized Warnings Consider filing a bug to report this issue to the plugin developer. Generate report

Task Setup Issues

This task declares the same output directory as task ':app:mergeDebugAssets': build/app/intermediates/assets/debug As a result, these tasks are not able to take advantage of incremental build optimizations and might need to run with each subsequent build. Learn more

Recommendation: Edit the plugin(s) to ensure each task specifies a unique output directory.
Reason task ran Output property 'destinationDir' file build/app/intermediates/assets/debug/flutter_assets has been removed. Output property 'destinationDir' file build/app/intermediates/assets/debug/flutter_assets/AssetManifest.bin has been removed. Output property 'destinationDir' file build/app/intermediates/assets/debug/flutter_assets/AssetManifest.json has been removed.

:app:mergeDebugAssets This task frequently determines build duration because of dependencies between its inputs/outputs and other tasks. Duration: 5.6s / 35.0% Sub-project: :app Plugin: com.android.application Type: com.android.build.gradle.tasks.MergeSourceSetFolders Task Execution Categories: Uncategorized Warnings Consider filing a bug to report this issue to the plugin developer. Generate report

Task Setup Issues

This task declares the same output directory as task ':app:copyFlutterAssetsDebug': build/app/intermediates/assets/debug As a result, these tasks are not able to take advantage of incremental build optimizations and might need to run with each subsequent build. Learn more

Recommendation: Edit the plugin(s) to ensure each task specifies a unique output directory.

Adding this reduces my incremental build time by 6sec:

afterEvaluate {
    // Help cache :copyFlutterAssetsDebug.
    cleanMergeDebugAssets.enabled = false
}

auto-submit bot pushed a commit that referenced this issue Jan 18, 2024
Move static methods together.
Fix property uses of duplicate strings.
Add types wherever obvious
Fix format depth
Add whitespace to top and bottom of classes
Ignore line length for file
Ignore prefer single quote for file
Ignore correction for getFoo used instead of foo

Loosely related to /issues/123934
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P2 Important issues not at the top of the work list platform-android Android applications specifically t: gradle "flutter build" and "flutter run" on Android team-android Owned by Android platform team tool Affects the "flutter" command-line tool. See also t: labels. triaged-android Triaged by Android platform team
Projects
None yet
Development

No branches or pull requests

5 participants