You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/**
* In AGP 4.0, the Android linter task depends on the JAR tasks that generate `libapp.so`.
* When building APKs, this causes an issue where building release requires the debug JAR,
* but Gradle won't build debug.
*
* To workaround this issue, only configure the JAR task that is required given the task
* from the command line.
*
* The AGP team said that this issue is fixed in Gradle 7.0, which isn't released at the
* time of adding this code. Once released, this can be removed. However, after updating to
* AGP/Gradle 7.2.0/7.5, removing this hack still causes build failures. Futher
* investigation necessary to remove this.
*
* Tested cases:
* * `./gradlew assembleRelease`
* * `./gradlew app:assembleRelease.`
* * `./gradlew assemble{flavorName}Release`
* * `./gradlew app:assemble{flavorName}Release`
* * `./gradlew assemble.`
* * `./gradlew app:assemble.`
* * `./gradlew bundle.`
* * `./gradlew bundleRelease.`
* * `./gradlew app:bundleRelease.`
*
* Related issues:
* https://issuetracker.google.com/issues/158060799
* https://issuetracker.google.com/issues/158753935
*/
However, removing this hack on AGP 7.2.0 still causes build failures.
We've identified that the logic inside shouldConfigureFlutterTask (specifically the cliTasksNames.size != 1 check) forces the Flutter Gradle Plugin (FGP) to eagerly configure all variants when more than one task is passed on the command line.
This "hack" is intended to support specific build scenarios but causes a severe side-effect: it breaks the build by interacting badly with the Android Gradle Plugin's (AGP) default native build task "folding" feature, leading to our build incorrectly depending on tasks from unrelated flavors.
The Root Cause
The problem is an interaction between two behaviors:
FGP forces eager configuration of all flavors
The check if (cliTasksNames.size != 1 ...) in shouldConfigureFlutterTask evaluates to true for any multi-task command, such as:
./gradlew clean :app:assembleFlavorADebug
./gradlew help :app:assembleFlavorADebug
When this happens, FGP enters an "eager" mode and proceeds to configure all flavors (FlavorA, FlavorB, FlavorC, etc.), not just the requested FlavorA.
AGP's default native build task folding
Default AGP optimization known as native build task folding, which is unrelated to Flutter, reuses a single, common native build task (e.g., buildCMakeDebug) for all flavors that share an identical native build configuration.
The problem is a race condition that pollutes the build graph:
We run ./gradlew clean :app:assembleFlavorADebug (a multi-task command).
FGP's shouldConfigureFlutterTask forces the eager configuration of all flavors.
An unrelated flavor (e.g., FlavorB) happens to be configured first.
During FlavorB's configuration, it "pollutes" the common buildCMakeDebug task by adding a dependency to its specific configuration (e.g., :app:flavorBCompileClasspath).
Later, when AGP configures our intended FlavorA, it sees that its native configuration is identical to FlavorB's. It applies its default "folding" optimization and reuses the already-configured buildCMakeDebug task, which is now polluted.
Result: Our assembleFlavorADebug task now incorrectly depends on and executes build tasks from FlavorB.
We have managed to temporarily fix our build by following the workaround suggested in the AGP issue: we manually added unique, flavor-specific arguments to our native build configuration. This makes every flavor's native build unique, which prevents AGP from "folding" the tasks.
While this works, it is a cumbersome workaround for a problem rooted in FGP's configuration logic.
We request that the Flutter team please reconsider the necessity of the cliTasksNames.size != 1 hack. This logic breaks Gradle's configuration-on-demand principles and causes critical incompatibility with standard AGP features, leading to an incorrect and polluted build graph.
Activity
reidbaker commentedon Oct 13, 2025
This issue is still relevant but the file has changed.
flutter/packages/flutter_tools/gradle/src/main/kotlin/FlutterPluginUtils.kt
Line 238 in 0205d4e
Nobler commentedon Oct 20, 2025
FGP's multi-task eager configuration (shouldConfigureFlutterTask) causes cross-flavor dependency pollution with AGP native builds
Summary
We've identified that the logic inside shouldConfigureFlutterTask (specifically the cliTasksNames.size != 1 check) forces the Flutter Gradle Plugin (FGP) to eagerly configure all variants when more than one task is passed on the command line.
This "hack" is intended to support specific build scenarios but causes a severe side-effect: it breaks the build by interacting badly with the Android Gradle Plugin's (AGP) default native build task "folding" feature, leading to our build incorrectly depending on tasks from unrelated flavors.
The Root Cause
The problem is an interaction between two behaviors:
FGP forces eager configuration of all flavors
The check if (cliTasksNames.size != 1 ...) in shouldConfigureFlutterTask evaluates to true for any multi-task command, such as:
./gradlew clean :app:assembleFlavorADebug
./gradlew help :app:assembleFlavorADebug
When this happens, FGP enters an "eager" mode and proceeds to configure all flavors (FlavorA, FlavorB, FlavorC, etc.), not just the requested FlavorA.
AGP's default native build task folding
Default AGP optimization known as native build task folding, which is unrelated to Flutter, reuses a single, common native build task (e.g., buildCMakeDebug) for all flavors that share an identical native build configuration.
The problem is a race condition that pollutes the build graph:
We run ./gradlew clean :app:assembleFlavorADebug (a multi-task command).
FGP's shouldConfigureFlutterTask forces the eager configuration of all flavors.
An unrelated flavor (e.g., FlavorB) happens to be configured first.
During FlavorB's configuration, it "pollutes" the common buildCMakeDebug task by adding a dependency to its specific configuration (e.g., :app:flavorBCompileClasspath).
Later, when AGP configures our intended FlavorA, it sees that its native configuration is identical to FlavorB's. It applies its default "folding" optimization and reuses the already-configured buildCMakeDebug task, which is now polluted.
Result: Our assembleFlavorADebug task now incorrectly depends on and executes build tasks from FlavorB.
(More context on the AGP task folding behavior itself can be found here: https://issuetracker.google.com/issues/329132239)
Our Workaround and Request
We have managed to temporarily fix our build by following the workaround suggested in the AGP issue: we manually added unique, flavor-specific arguments to our native build configuration. This makes every flavor's native build unique, which prevents AGP from "folding" the tasks.
While this works, it is a cumbersome workaround for a problem rooted in FGP's configuration logic.
We request that the Flutter team please reconsider the necessity of the cliTasksNames.size != 1 hack. This logic breaks Gradle's configuration-on-demand principles and causes critical incompatibility with standard AGP features, leading to an incorrect and polluted build graph.
[AGP 9.1.0 Migration flutter#8] Unify add-to-app module wiring on the…
[AGP 9.1.0 Migration flutter#8] Unify add-to-app module wiring on the…