Repository navigation
[Gradle] Run DependencyVersionChecker before accessing Android DSL extensions in FlutterPlugin.apply - #194918
Conversation
…in FlutterPlugin.apply After PR flutter#193813 bumped the compile-time AGP version in packages/flutter_tools/gradle/build.gradle.kts to 9.1.1, bytecode generated for FlutterPlugin.configureAbiWithoutSplits invokes ApplicationExtension.getDefaultConfig() with its AGP 9 return type signature. Because FlutterPlugin.apply invoked addFlutterTasks before DependencyVersionChecker.checkDependencyVersions, projects on AGP 8.x crashed with NoSuchMethodError before reaching the dependency version check. Move the DependencyVersionChecker block before addFlutterTasks and update the supported AGP matrix rule in packages/flutter_tools/gradle/AGENTS.md.
There was a problem hiding this comment.
Code Review
This pull request moves the dependency version checking logic in FlutterPlugin to run earlier in the plugin application process, ensuring that unsupported AGP versions fail with a diagnostic error before accessing Android DSL extensions. It also updates the documentation in AGENTS.md and adds a corresponding unit test. The review feedback suggests simplifying the Gradle property lookups for usesUnsupportedDependencyVersions and skipDependencyChecks to avoid potential ClassCastException and improve code readability.
| if (!project.hasProperty("usesUnsupportedDependencyVersions") || | ||
| !(project.properties["usesUnsupportedDependencyVersions"] as Boolean) | ||
| ) { |
There was a problem hiding this comment.
Using as Boolean on a Gradle property lookup is unsafe because properties passed via the command line or gradle.properties are often parsed as String (e.g., "true"), which will cause a ClassCastException at runtime.
We can safely parse the property to a boolean using toString().toBoolean() and simplify the logic.
| if (!project.hasProperty("usesUnsupportedDependencyVersions") || | |
| !(project.properties["usesUnsupportedDependencyVersions"] as Boolean) | |
| ) { | |
| val usesUnsupported = | |
| project.properties["usesUnsupportedDependencyVersions"]?.toString()?.toBoolean() == true | |
| if (!usesUnsupported) { |
References
- Suggest simplification and refactoring to enhance readability and maintainability, and optimize for readability. (link)
| val shouldSkipDependencyChecks: Boolean = | ||
| project.hasProperty("skipDependencyChecks") && | ||
| ( | ||
| project.properties["skipDependencyChecks"].toString().toBoolean() | ||
| ) |
There was a problem hiding this comment.
This property lookup can be simplified and made more idiomatic by using safe navigation and avoiding the explicit hasProperty check. This also reduces nesting and improves readability.
| val shouldSkipDependencyChecks: Boolean = | |
| project.hasProperty("skipDependencyChecks") && | |
| ( | |
| project.properties["skipDependencyChecks"].toString().toBoolean() | |
| ) | |
| val shouldSkipDependencyChecks = | |
| project.properties["skipDependencyChecks"]?.toString()?.toBoolean() == true |
References
- Suggest simplification and refactoring to enhance readability and maintainability, and optimize for readability. (link)
| every { mockComponentsExtension.pluginVersion } returns unsupportedAgpVersion | ||
| val extensionContainer = project.extensions | ||
| every { extensionContainer.getByType(ApplicationExtension::class.java) } throws | ||
| AssertionError("ApplicationExtension was accessed before DependencyVersionChecker rejected the AGP version") |
There was a problem hiding this comment.
This feels a little too specific. I think we want to test hat DependencyVersionChecker runs before the code that relies on minimum version enforcement.
There was a problem hiding this comment.
Updated in 85bd1984939: moved the DependencyVersionChecker.checkDependencyVersions(project) block to the start of FlutterPlugin.apply and replaced the test with FlutterPlugin apply checks dependency versions before configuring project, which uses verifyOrder to verify that DependencyVersionChecker.checkDependencyVersions(project) runs before task registration, AndroidComponentsExtension callbacks (finalizeDsl, onVariants), and ApplicationExtension DSL configuration (defaultConfig, buildTypes).
… checkDependencyVersions execution order
0b5a8bf
|
auto label is removed for flutter/flutter/194918, Failed to enqueue flutter/flutter/194918 with HTTP 400: Something went wrong while executing your query on 2026-10-21T23:30:55Z. Please include |
…cyVersionChecker (flutter#195006) Follow-up to flutter#194918; split out so that PR stays small for cherry-picking. Removes the `usesUnsupportedDependencyVersions` (`OUT_OF_SUPPORT_RANGE_PROPERTY`) Gradle extra property from `DependencyVersionChecker`, as `FlutterPlugin.apply` catches `DependencyValidationException` directly and nothing else reads the property. Best the agent and my investigation work can find is that this was carry over from when this code was in a build.gradle.kts file and we didnt catch exceptions. I was found during manual review of flutter#194918 Part of flutter#166550. <details><summary>Agent authored details</summary> ### Review Link (Part B diff only) While [flutter#194918](flutter#194918) is open, view only this PR's changes at: https://github.com/flutter/flutter/pull/195006/files/5b5910facc17cd3d9ac87a594c187c6167f9ccc9..76d2f56c3e00ae37e016892bf7dcbe1c7fc8f675 ### Background `DependencyVersionChecker` set `project.extra[OUT_OF_SUPPORT_RANGE_PROPERTY] = true` (`"usesUnsupportedDependencyVersions"`) before throwing `DependencyValidationException` and inside the `minSdkCheck` task `doLast` action. That extra property originated when the dependency version checker was applied as a standalone `.kts` script (`dependency_version_checker.kts`) whose exception class could not be referenced directly by `FlutterPlugin`. Because `DependencyVersionChecker` and `DependencyValidationException` are compiled in the same Kotlin module as `FlutterPlugin` and [flutter#194918](flutter#194918) updated `FlutterPlugin.apply` to catch `DependencyValidationException` directly, the extra property has no remaining readers. ### Changes 1. **`DependencyVersionChecker.kt`**: - Removes `OUT_OF_SUPPORT_RANGE_PROPERTY` and its 3-line comment describing the Gradle extra property. - Removes all 7 `project.extra.set(OUT_OF_SUPPORT_RANGE_PROPERTY, ...)` calls (`checkDependencyVersions`, `configureMinSdkCheck`, `checkGradleVersion`, `checkJavaVersion`, `checkAGPVersion` (x2), and `checkKGPVersion`) and the `org.gradle.kotlin.dsl.extra` import. - In `configureMinSdkCheck`, captures `rootDirPath` (`project.rootDir.path`) and `minSdkVersion` outside `doLast` and passes the task's `logger` to `checkMinSdkVersion(minSdkVersion, rootDirPath, logger)` so the task action does not capture `Project` (`packages/flutter_tools/gradle/AGENTS.md` §4). - Updates the comment on `DependencyValidationException` to reference `DependencyVersionChecker` instead of `the dependency_version_checker.kts script`. 2. **`DependencyVersionCheckerTest.kt`**: - Removes the `OUT_OF_SUPPORT_RANGE_PROPERTY`, `ExtraPropertiesExtension`, and `org.gradle.internal.extensions.core.extra` imports and mock setup, keeping the `assertFailsWith<DependencyValidationException>` and logger verification assertions in each test. - Removed extra-property assertions (all redundant with `assertFailsWith<DependencyValidationException>` or logger assertions now that `OUT_OF_SUPPORT_RANGE_PROPERTY` is removed): 1. `Template versions are considered supported`: removed comment `// Verify that the project was not marked as being out of support range.` and `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, false) }`. 2. `AGP version in error range results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 3. `AGP version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 4. `AGP version with unsupported major version results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 5. `AGP version above unsupported major version results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 6. `AGP version below unsupported major version is considered supported`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 7. `KGP version in error range results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 8. `KGP version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 9. `AGP 9 built-in Kotlin skips KGP min version enforcement by default`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 10. `Java version in error range results in error logs`: removed `verify(exactly = 1) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 11. `Gradle version in error range results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 12. `Gradle version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 13. `min SDK version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 14. `min SDK version in error range results in DependencyValidationException`: removed `verify(exactly = 1) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 15. `checkMinSdkVersion throws error when in error range for min SDK version` and `checkMinSdkVersion logs warning when in warning range for min SDK version`: removed unused `mockExtraPropertiesExtension` local setup. 16. `MockProjectFactory.createMockProjectWithSpecifiedDependencyVersions`: removed `// Extra properties extension` comment and `mockProject.extra` stubbing; stubbed `mockTask.logger` on the registered task mock. </details> ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
…tensions in FlutterPlugin.apply (flutter#194918) ## Description Part of [flutter#180137](flutter#180137), [flutter#166550](flutter#166550). I broke the check in PR 7/11 ([flutter#193693](flutter#193693)) in the new DSL migration for users that were on AGP 8.11. This fixes the mistake and adds a test. This will likely need to be cherry picked. <details> <summary>Agent authored details</summary> ### Related PR - Follow-up PR: [flutter#195006](flutter#195006). Because `flutter#194918` is a cherry-pick candidate, it only replaces the `OUT_OF_SUPPORT_RANGE_PROPERTY` check in `FlutterPlugin.apply` with a typed `catch (e: DependencyValidationException)`. Removing `OUT_OF_SUPPORT_RANGE_PROPERTY` itself—which touches 7 property setters, a task action, and 14 test assertions across `DependencyVersionChecker.kt` and `DependencyVersionCheckerTest.kt`—is split into [flutter#195006](flutter#195006) so this cherry-pick stays minimal. ### Background When [flutter#193813](flutter#193813) (`ce6e766ad1c`) raised the minimum supported AGP version in `DependencyVersionChecker` to `9.1.1` and bumped the compile-time `agpVersion` in `packages/flutter_tools/gradle/build.gradle.kts` from `8.11.1` to `9.1.1`, the Kotlin compiler began emitting AGP 9 binary method signatures for calls against `ApplicationExtension` (such as `ApplicationExtension.getDefaultConfig()Lcom/android/build/api/dsl/ApplicationDefaultConfig;`, whereas in AGP 8.x `CommonExtension.getDefaultConfig()` returned `DefaultConfig` without a covariant bridge on `ApplicationExtension`). Because `FlutterPlugin.apply` invoked `addFlutterTasks(project)` (which calls `configureAbis` -> `configureAbiWithoutSplits` -> `extension.defaultConfig.ndk` and `DslVersionCodes.from(appExtension)` introduced in [flutter#193693](flutter#193693) / [flutter#192488](flutter#192488)) before running `DependencyVersionChecker.checkDependencyVersions(project)`, building an AGP 8.x project crashed during `addFlutterTasks` with: ```text java.lang.NoSuchMethodError: 'com.android.build.api.dsl.ApplicationDefaultConfig com.android.build.api.dsl.ApplicationExtension.getDefaultConfig()' ``` before reaching `DependencyVersionChecker.checkDependencyVersions(project)`, preventing the user from seeing the actionable minimum AGP version error message and upgrade guidance. ### Changes 1. **`FlutterPlugin.kt`**: - Moves `FlutterPluginUtils.detectApplyingKotlinGradlePlugin(project)` and the `shouldSkipDependencyChecks` / `DependencyVersionChecker.checkDependencyVersions(project)` block to the beginning of `FlutterPlugin.apply(project)` (immediately after `this.project = project`), before `addFlutterTasks(project)` and all `ApplicationExtension` / Android DSL accesses. - Replaces the `OUT_OF_SUPPORT_RANGE_PROPERTY` extra-property check in `FlutterPlugin.apply` with a typed `catch (e: DependencyValidationException)` that rethrows `DependencyValidationException` directly and logs any other `Exception`, removing the comment that described `OUT_OF_SUPPORT_RANGE_PROPERTY`. 2. **`FlutterPluginTest.kt`**: - Adds `FlutterPlugin apply checks dependency versions before configuring project`, verifying via `verifyOrder` that `FlutterPluginUtils.detectApplyingKotlinGradlePlugin(project)` and `DependencyVersionChecker.checkDependencyVersions(project)` run before task registration, `AndroidComponentsExtension` callbacks (`finalizeDsl`, `onVariants`), and `ApplicationExtension` DSL configuration (`defaultConfig`, `buildTypes`). - Adds `FlutterPlugin apply rethrows DependencyValidationException and logs other exceptions`, verifying both exception branches without relying on the extra property, and stubs supported Gradle and AGP versions in `setupTestProjectEnvironment` / `setupMockComponentsExtension`. 3. **`packages/flutter_tools/gradle/AGENTS.md`**: - Updates the `Matrix Verification` bullet on line 40 to reference the supported AGP and Gradle versions defined in `DependencyVersionChecker.kt`. ### Verification - **Unit test negative/positive verification**: - Moving `DependencyVersionChecker` after `addFlutterTasks` or moving `detectApplyingKotlinGradlePlugin` after `DependencyVersionChecker` fails `FlutterPlugin apply checks dependency versions before configuring project`. - Reverting the typed `catch (e: DependencyValidationException)` to the property check fails `FlutterPlugin apply rethrows DependencyValidationException and logs other exceptions`. - `./gradlew test` with the fix applied: all tests pass. - **End-to-end reproduction with AGP 8.11.1 and Gradle 9.3.1**: - Before fix: failed at `FlutterPlugin.configureAbiWithoutSplits` with `java.lang.NoSuchMethodError: 'com.android.build.api.dsl.ApplicationDefaultConfig com.android.build.api.dsl.ApplicationExtension.getDefaultConfig()'`. - After fix: fails cleanly with `Error: Your project's Android Gradle Plugin version (Android Gradle Plugin version 8.11.1) is lower than Flutter's minimum supported version of Android Gradle Plugin version 9.1.1. Please upgrade your Android Gradle Plugin version.` - **Formatting**: - `ktlint 1.5.0` with `--editorconfig=dev/bots/test/analyze-test-input/.editorconfig --baseline=dev/bots/test/analyze-test-input/ktlint-baseline.xml` passed with zero findings. </details> --- ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
…cyVersionChecker (flutter#195006) Follow-up to flutter#194918; split out so that PR stays small for cherry-picking. Removes the `usesUnsupportedDependencyVersions` (`OUT_OF_SUPPORT_RANGE_PROPERTY`) Gradle extra property from `DependencyVersionChecker`, as `FlutterPlugin.apply` catches `DependencyValidationException` directly and nothing else reads the property. Best the agent and my investigation work can find is that this was carry over from when this code was in a build.gradle.kts file and we didnt catch exceptions. I was found during manual review of flutter#194918 Part of flutter#166550. <details><summary>Agent authored details</summary> ### Review Link (Part B diff only) While [flutter#194918](flutter#194918) is open, view only this PR's changes at: https://github.com/flutter/flutter/pull/195006/files/5b5910facc17cd3d9ac87a594c187c6167f9ccc9..76d2f56c3e00ae37e016892bf7dcbe1c7fc8f675 ### Background `DependencyVersionChecker` set `project.extra[OUT_OF_SUPPORT_RANGE_PROPERTY] = true` (`"usesUnsupportedDependencyVersions"`) before throwing `DependencyValidationException` and inside the `minSdkCheck` task `doLast` action. That extra property originated when the dependency version checker was applied as a standalone `.kts` script (`dependency_version_checker.kts`) whose exception class could not be referenced directly by `FlutterPlugin`. Because `DependencyVersionChecker` and `DependencyValidationException` are compiled in the same Kotlin module as `FlutterPlugin` and [flutter#194918](flutter#194918) updated `FlutterPlugin.apply` to catch `DependencyValidationException` directly, the extra property has no remaining readers. ### Changes 1. **`DependencyVersionChecker.kt`**: - Removes `OUT_OF_SUPPORT_RANGE_PROPERTY` and its 3-line comment describing the Gradle extra property. - Removes all 7 `project.extra.set(OUT_OF_SUPPORT_RANGE_PROPERTY, ...)` calls (`checkDependencyVersions`, `configureMinSdkCheck`, `checkGradleVersion`, `checkJavaVersion`, `checkAGPVersion` (x2), and `checkKGPVersion`) and the `org.gradle.kotlin.dsl.extra` import. - In `configureMinSdkCheck`, captures `rootDirPath` (`project.rootDir.path`) and `minSdkVersion` outside `doLast` and passes the task's `logger` to `checkMinSdkVersion(minSdkVersion, rootDirPath, logger)` so the task action does not capture `Project` (`packages/flutter_tools/gradle/AGENTS.md` §4). - Updates the comment on `DependencyValidationException` to reference `DependencyVersionChecker` instead of `the dependency_version_checker.kts script`. 2. **`DependencyVersionCheckerTest.kt`**: - Removes the `OUT_OF_SUPPORT_RANGE_PROPERTY`, `ExtraPropertiesExtension`, and `org.gradle.internal.extensions.core.extra` imports and mock setup, keeping the `assertFailsWith<DependencyValidationException>` and logger verification assertions in each test. - Removed extra-property assertions (all redundant with `assertFailsWith<DependencyValidationException>` or logger assertions now that `OUT_OF_SUPPORT_RANGE_PROPERTY` is removed): 1. `Template versions are considered supported`: removed comment `// Verify that the project was not marked as being out of support range.` and `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, false) }`. 2. `AGP version in error range results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 3. `AGP version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 4. `AGP version with unsupported major version results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 5. `AGP version above unsupported major version results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 6. `AGP version below unsupported major version is considered supported`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 7. `KGP version in error range results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 8. `KGP version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 9. `AGP 9 built-in Kotlin skips KGP min version enforcement by default`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 10. `Java version in error range results in error logs`: removed `verify(exactly = 1) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 11. `Gradle version in error range results in DependencyValidationException`: removed `verify { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 12. `Gradle version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 13. `min SDK version in warn range results in warning logs`: removed `verify(exactly = 0) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 14. `min SDK version in error range results in DependencyValidationException`: removed `verify(exactly = 1) { mockExtraPropertiesExtension.set(OUT_OF_SUPPORT_RANGE_PROPERTY, true) }`. 15. `checkMinSdkVersion throws error when in error range for min SDK version` and `checkMinSdkVersion logs warning when in warning range for min SDK version`: removed unused `mockExtraPropertiesExtension` local setup. 16. `MockProjectFactory.createMockProjectWithSpecifiedDependencyVersions`: removed `// Extra properties extension` comment and `mockProject.extra` stubbing; stubbed `mockTask.logger` on the registered task mock. </details> ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant in-code documentation (doc comments with `///`). - [x] If this PR introduces a new feature or capability, I created and linked a website documentation issue or PR in [flutter/website] (or verified none is needed). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/CONTRIBUTING.ai.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [flutter/website]: https://github.com/flutter/website [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Description
Part of #180137, #166550.
I broke the check in PR 7/11 (#193693) in the new DSL migration for users that were on AGP 8.11. This fixes the mistake and adds a test. This will likely need to be cherry picked.
Agent authored details
Related PR
#194918is a cherry-pick candidate, it only replaces theOUT_OF_SUPPORT_RANGE_PROPERTYcheck inFlutterPlugin.applywith a typedcatch (e: DependencyValidationException). RemovingOUT_OF_SUPPORT_RANGE_PROPERTYitself—which touches 7 property setters, a task action, and 14 test assertions acrossDependencyVersionChecker.ktandDependencyVersionCheckerTest.kt—is split into #195006 so this cherry-pick stays minimal.Background
When #193813 (
ce6e766ad1c) raised the minimum supported AGP version inDependencyVersionCheckerto9.1.1and bumped the compile-timeagpVersioninpackages/flutter_tools/gradle/build.gradle.ktsfrom8.11.1to9.1.1, the Kotlin compiler began emitting AGP 9 binary method signatures for calls againstApplicationExtension(such asApplicationExtension.getDefaultConfig()Lcom/android/build/api/dsl/ApplicationDefaultConfig;, whereas in AGP 8.xCommonExtension.getDefaultConfig()returnedDefaultConfigwithout a covariant bridge onApplicationExtension).Because
FlutterPlugin.applyinvokedaddFlutterTasks(project)(which callsconfigureAbis->configureAbiWithoutSplits->extension.defaultConfig.ndkandDslVersionCodes.from(appExtension)introduced in #193693 / #192488) before runningDependencyVersionChecker.checkDependencyVersions(project), building an AGP 8.x project crashed duringaddFlutterTaskswith:before reaching
DependencyVersionChecker.checkDependencyVersions(project), preventing the user from seeing the actionable minimum AGP version error message and upgrade guidance.Changes
FlutterPlugin.kt:FlutterPluginUtils.detectApplyingKotlinGradlePlugin(project)and theshouldSkipDependencyChecks/DependencyVersionChecker.checkDependencyVersions(project)block to the beginning ofFlutterPlugin.apply(project)(immediately afterthis.project = project), beforeaddFlutterTasks(project)and allApplicationExtension/ Android DSL accesses.OUT_OF_SUPPORT_RANGE_PROPERTYextra-property check inFlutterPlugin.applywith a typedcatch (e: DependencyValidationException)that rethrowsDependencyValidationExceptiondirectly and logs any otherException, removing the comment that describedOUT_OF_SUPPORT_RANGE_PROPERTY.FlutterPluginTest.kt:FlutterPlugin apply checks dependency versions before configuring project, verifying viaverifyOrderthatFlutterPluginUtils.detectApplyingKotlinGradlePlugin(project)andDependencyVersionChecker.checkDependencyVersions(project)run before task registration,AndroidComponentsExtensioncallbacks (finalizeDsl,onVariants), andApplicationExtensionDSL configuration (defaultConfig,buildTypes).FlutterPlugin apply rethrows DependencyValidationException and logs other exceptions, verifying both exception branches without relying on the extra property, and stubs supported Gradle and AGP versions insetupTestProjectEnvironment/setupMockComponentsExtension.packages/flutter_tools/gradle/AGENTS.md:Matrix Verificationbullet on line 40 to reference the supported AGP and Gradle versions defined inDependencyVersionChecker.kt.Verification
DependencyVersionCheckerafteraddFlutterTasksor movingdetectApplyingKotlinGradlePluginafterDependencyVersionCheckerfailsFlutterPlugin apply checks dependency versions before configuring project.catch (e: DependencyValidationException)to the property check failsFlutterPlugin apply rethrows DependencyValidationException and logs other exceptions../gradlew testwith the fix applied: all tests pass.FlutterPlugin.configureAbiWithoutSplitswithjava.lang.NoSuchMethodError: 'com.android.build.api.dsl.ApplicationDefaultConfig com.android.build.api.dsl.ApplicationExtension.getDefaultConfig()'.Error: Your project's Android Gradle Plugin version (Android Gradle Plugin version 8.11.1) is lower than Flutter's minimum supported version of Android Gradle Plugin version 9.1.1. Please upgrade your Android Gradle Plugin version.ktlint 1.5.0with--editorconfig=dev/bots/test/analyze-test-input/.editorconfig --baseline=dev/bots/test/analyze-test-input/ktlint-baseline.xmlpassed with zero findings.Pre-launch Checklist
///).