Repository navigation
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request migrates the Flutter Gradle Plugin to the public Android Gradle Plugin (AGP) API surface, removing dependencies on AGP internals and legacy DSL/Variant APIs. It introduces dedicated lazy tasks for asset and APK copying, cleans up the android.newDsl=false opt-out from templates and existing projects via a new migration, and updates error handling to guide users through migrating legacy build scripts. Feedback on the changes suggests using dependsOn instead of finalizedBy to attach the APK copying task to the assemble task, preventing secondary failures from obscuring compilation errors on failed builds.
| val assembleTaskName = "assemble$capitalizeVariantName" | ||
| projectToAddTasksTo.tasks | ||
| .matching { it.name == assembleTaskName } | ||
| .configureEach { finalizedBy(copyFlutterApksTaskProvider) } |
There was a problem hiding this comment.
Using finalizedBy to attach CopyFlutterApksTask to the assemble task can lead to confusing build failure outputs. In Gradle, finalizer tasks run even if the finalized task fails. If the build fails during compilation or packaging, the APK and its metadata won't be generated. When CopyFlutterApksTask runs as a finalizer, it will fail with a GradleException ('Flutter could not read the built APK metadata...'), which then obscures the actual compilation or packaging error at the end of the build log.
Suggest using dependsOn instead of finalizedBy. This ensures the copy task is only executed if the build successfully reaches the assembly stage, preventing misleading secondary failures.
| val assembleTaskName = "assemble$capitalizeVariantName" | |
| projectToAddTasksTo.tasks | |
| .matching { it.name == assembleTaskName } | |
| .configureEach { finalizedBy(copyFlutterApksTaskProvider) } | |
| val assembleTaskName = "assemble$capitalizeVariantName" | |
| projectToAddTasksTo.tasks | |
| .matching { it.name == assembleTaskName } | |
| .configureEach { dependsOn(copyFlutterApksTaskProvider) } |
a0ab835 to
4f20a40
Compare
|
Prompt used for updating this pr. |
4f20a40 to
ef2c92a
Compare
ef2c92a to
154cdcd
Compare
…page draft) Phase P0 of the Flutter Gradle Plugin migration to the AGP public API surface (flutter#180137, flutter#166550): the contributor migration record (replacement map, decision records, phase map, revert-window table) and the draft of the user-facing breaking-change page to be published to docs.flutter.dev before the newDsl flip reaches beta. Revert-safe: always.
…k/ndk reads to the public DSL Phase P1 of the AGP public-API migration (flutter#180137, flutter#166550): - VersionFetcher no longer calls the internal com.android.build.gradle.internal.utils.getKotlinAndroidPluginVersion. getKGPVersion now relies on the existing public fallback chain (kotlin_version property -> KotlinAndroidPluginWrapper.pluginVersion -> reflection) and documents that null is the expected result when KGP is absent (e.g. under AGP built-in Kotlin). DependencyVersionChecker already treats null as "KGP not required". - AgpCommonExtensionWrapper gains compileSdkPreview. - getCompileSdkFromProject now reads compileSdk/compileSdkPreview from the new DSL via the wrapper and returns a structured CompileSdkVersion instead of parsing the legacy "android-NN" string. The PluginHandler compileSdk mismatch warning uses CompileSdkVersion.isHigherThan, which defines the preview semantics the old string comparison got wrong (resolves the PluginHandler TODO): preview > numeric, distinct preview codenames incomparable (no warning), numeric compared numerically. Warning message text is unchanged. - getConfiguredNdkVersion reads through the wrapper instead of the legacy BaseExtension fallback. - Deletes the setAgpKotlinVersionToNull test helper (existed only to stub the internal AGP call) and updates unit tests accordingly; adds tests for both preview-vs-numeric directions and the codename reset case. Verification note: the FGP unit test suite could not be executed in this sandbox (the network policy blocks dl.google.com, so AGP artifacts do not resolve); run 'gradle test' in packages/flutter_tools/gradle in CI. Revert-safe until P2 lands.
154cdcd to
a8575b4
Compare
334c423 to
81f5052
Compare
…gh the new DSL Phase P2 of the AGP public-API migration (flutter#180137, flutter#166550): - buildModeFor gains a (buildTypeName, isDebuggable) core overload and a new-DSL BuildType overload. Application and dynamic-feature build types use their public isDebuggable flag; library build types have no public debuggable signal at DSL scope, so the conventional "debug" name is used for them. The legacy com.android.builder.model.BuildType overload remains for the variant-scope call sites that migrate in later phases. - addFlutterDependencies (engine/embedding deps) now takes a new-DSL BuildType, and FlutterPlugin registers it via the wrapper's buildTypes container instead of the legacy BaseExtension. - PluginHandler's three dependency-wiring loops (per-build-type Api wiring, embedding deps, plugin-to-plugin deps) iterate the wrapper container. The build-type copy block still uses the legacy container and internal.dsl.BuildType; that is phase P3. - build.gradle.kts accepts -PagpVersion= so CI can compile and test the plugin against the AGP 9 line in addition to the default (the public DSL is not binary-compatible between AGP 8 and 9 everywhere), and a new validateNoCommonExtensionInBytecode task fails the build if any compiled main class references CommonExtension (the known-broken type that AgpCommonExtensionWrapper exists to avoid). - android_run_flutter_gradle_plugin_tests_test.dart gains a second test running the suite with -PagpVersion=<templateAndroidGradlePluginVersion>. - PluginHandlerTest no longer depends on exhausted-iterator mock behavior; the wrapper container returns a fresh iterator per call. Verification note: FGP unit tests could not be executed in this sandbox (network policy blocks dl.google.com); run 'gradle test' and 'gradle -PagpVersion=9.1.0 test' in packages/flutter_tools/gradle in CI. Revert-safe until P3 lands.
Phase P3 of the AGP public-API migration (flutter#180137, flutter#166550): - PluginHandler no longer imports com.android.build.gradle.internal.dsl.BuildType. The build-type copy block that shared live legacy BuildType instances (addAll) for app-type plugin projects and hand-copied two properties for library plugin projects is replaced by a single initWith-based copy on the new-DSL containers: missing build types are created on the plugin project with initWith(appBuildType) (which carries matchingFallbacks), and isDebuggable is additionally copied when both sides are application build types. Library build types cannot receive app-specific properties through the public DSL - this is a documented behavior change of the migration (BuildConfig.DEBUG / JNI debuggability of plugins built for custom debuggable build types). - Production sources are now free of com.android.build.gradle.internal imports; InternalAgpApiImportTest locks that in (test sources may still use internals until the gradle-api dependency swap). - PluginHandlerTest: the two mock-only copy tests (which never invoked configurePlugins) are replaced with tests that run configurePlugins and assert the initWith copy for both a library plugin project and an app plugin project, including the custom-debuggable-build-type -> debug engine artifact mapping. - The planned pre-spike (afterEvaluate DSL mutation under newDsl=true) could not run in this sandbox; recorded in the migration doc with the finalizeDsl fallback. android_plugin_example_app_build and a custom build-type scratch build must confirm in CI. Verification note: FGP unit tests could not be executed in this sandbox (network policy blocks dl.google.com); run 'gradle test' (both AGP axes) in packages/flutter_tools/gradle in CI. Revert-safe until P4 lands.
…public DSL Phase P4 of the AGP public-API migration (flutter#180137, flutter#166550): - AgpCommonExtensionWrapper gains externalNativeBuild, and both the already-configuring-a-native-build check in forceNdkDownload and the synthetic-cmake fallback now read/write cmake.path, cmake.buildStagingDirectory and the per-build-type externalNativeBuild.cmake.arguments through the public DSL (property assignment with File values instead of the legacy Any-taking CmakeOptions methods; arguments via the public MutableList). - getLegacyAndroidExtension and the BaseExtension import are deleted from FlutterPluginUtils; nothing in production sources references BaseExtension anymore. - forceNdkDownload tests move their mocks from BaseExtension/ internal CmakeOptions to the wrapper path (findByName("android") + public Cmake), assert cmake arguments by list content, and drop the defaultConfig-untouched assertions that only existed to guard the legacy extension. The two tests that asserted the old ApplicationExtension-vs-BaseExtension ndkVersion preference are deleted: getConfiguredNdkVersion has had a single source since P1. Also restores the findByType(ApplicationExtension) mocks (needed by isFlutterAppProject) that P1's test edit dropped in three tests. - FlutterPluginUtilsTest no longer imports internal.dsl.CmakeOptions or internal.dsl.DefaultConfig. Verification note: FGP unit tests could not be executed in this sandbox (network policy blocks dl.google.com); run 'gradle test' (both AGP axes) in packages/flutter_tools/gradle in CI, plus an NDK-absent scratch build exercising the synthetic-cmake fallback. Revert-safe until P5 lands.
… projects Phase P5, commit 1 of 2 (P5a), of the AGP public-API migration (flutter#180137, flutter#166550): - For application projects, compileFlutterBuild<Variant> (FlutterTask) is now registered inside the consolidated androidComponents.onVariants block as a lazy TaskProvider, configured entirely from the public variant API: minSdk from Variant.minSdk.apiLevel, flavor from Variant.flavorName, and the Flutter build mode from buildModeFor(variant.buildType, variant.debuggable) so custom debuggable build types keep mapping to debug engine artifacts. Registration is gated by shouldConfigureFlutterTask on the computed assemble task name (new name-based overload), mirroring the legacy callback's gating. - addFlutterDeps is split: addFlutterDepsForApp (per-ABI versionCode, legacy assets copy into the merged-assets dir, processResources hook) looks the compile task up by name instead of registering it; addFlutterDepsForModule keeps the full legacy path for add-to-app module projects until that path migrates. The always-null packageAssets/isUsedAsSubproject dead code and the duplicated processResources hook in the application variant callback are removed. No behavior change intended for what gets built; the assets delivery mechanism changes in the next commit (P5b). Verification note: FGP unit tests could not run in this sandbox (network policy blocks dl.google.com); run 'gradle test' (both AGP axes) in CI. Revert-safe (with P5b) until P6 lands.
…app path Phase P5, commit 2 of 2 (P5b), of the AGP public-API migration (flutter#180137, flutter#166550): - New CopyFlutterAssetsTask stages flutter_assets/** from the Flutter build output into its own output directory (modeled on CopyFlutterJniLibsTask, including the overlapping-outputs rationale), applying the user read+write file permissions the old Copy task set. - For application projects, copyFlutterAssets<Variant> is registered in the consolidated onVariants block as a lazy TaskProvider and wired via variant.sources.assets.addGeneratedSourceDirectory. AGP now merges Flutter's assets like any other assets source; collisions with user assets resolve by source-set priority instead of the old post-merge overwrite (documented behavior change). A missing assets source set fails loudly instead of silently building an APK without Flutter assets. - The legacy app-path assets copy (into mergeAssets.outputDir), its processResources/cleanMergeAssets task-graph surgery, and the manual compress<V>Assets dependsOn wiring are deleted for app projects; AGP owns those edges now. The application variant callback is reduced to the per-ABI versionCode override and the flutter-apk copy, both of which migrate in the next phase. The add-to-app module path is unchanged (still the full legacy copy) until it migrates. - copyFlutterAssets<Variant> changes type from org.gradle.api.tasks.Copy to CopyFlutterAssetsTask and is now registered lazily (documented breaking change for build scripts that referenced it by type). - Tests: new CopyFlutterAssetsTaskTest executes the task against real files (staging layout, permission bits, non-asset exclusion, stale output cleanup). The FlutterPluginTest filePermissions test built on capturing the legacy Copy registration is superseded by it. Verification (CI): gradle unit tests both AGP axes; integration builddir/obfuscate/jni/print_build_variants/deferred_components_assets; add-to-app source smoke + flutter build aar; asset-staleness rebuild check; config-cache per baseline. Revert-safe until P6 lands.
Phase P6 of the AGP public-API migration (flutter#180137, flutter#166550). The application path no longer uses the legacy variant API at all: - New CopyFlutterApksTask copies the variant's SingleArtifact.APK directory contents (via BuiltArtifactsLoader) into build/outputs/flutter-apk under the unchanged names app[-abi][-flavor]-<build-mode>.apk. It is attached as a finalizer of assemble<Variant> (matched by name, with a projectsEvaluated assertion that fails loudly if the assemble task was never created, instead of silently leaving flutter run/build without APKs). The task declares individual predictable @OutputFiles - computed from target platforms, flavor, and build mode - rather than the shared flutter-apk directory, so it is UP-TO-DATE-capable without overlapping outputs between variants; it replaces the old assemble.doLast copy. - Per-ABI versionCode for --split-per-abi builds is now a read-then-set on VariantOutput.versionCode inside onVariants (the output is seeded with AGP's merged value, which covers flavor-defined versionCodes), replacing versionCodeOverride on the legacy ApkVariantOutput. When the built APK's versionCode differs from what Flutter configured (e.g. an afterEvaluate mutation), CopyFlutterApksTask logs a warning pointing at androidComponents.onVariants. Note on onVariants FIFO callback ordering: Because FGP is applied at line 25 of build.gradle.kts, FGP's callback executes before app-level onVariants callbacks at line 70. Any custom app-level block reading output.versionCode.get() will observe the ABI-offset value. For standard apps, no change is needed; monotonic ABI ordering and Play Store uniqueness are preserved even if an app transforms versionCode. - The entire legacy applicationVariants.configureEach block and its helpers are deleted; AbstractAppExtension remains only in the add-to-app module path, which migrates next. Verification (CI): split-per-abi + apkanalyzer per-ABI versionCode assertions including the flavor-defined-versionCode case; flavor filename check; flutter run / hot restart / attach; Windows-runner smoke for the copy tasks; android_e2e_api_test; gradle unit tests on both AGP axes. Revert-safe until P7 lands (mutually tolerant with P7 until P10).
…ct cross-wiring Phase P7 of the AGP public-API migration (flutter#180137, flutter#166550), the last Kotlin consumer of the legacy variant API: - Add-to-app module (library) projects now use the same consolidated onVariants block as application projects: the Flutter compile task and CopyFlutterAssetsTask are registered lazily per library variant, and flutter_assets are wired through variant.sources.assets.addGeneratedSourceDirectory. The host application consumes them through AGP's normal library packaging and variant matching, with build modes resolved from the public Component.debuggable flag (so a custom debuggable host build type such as 'staging' still maps to the debug engine artifacts via the module's matched variant). Module variants skip the CLI task-name gating: which module variant a host build consumes is AGP's variant matching decision, and a module has at most three variants to configure lazily. - The host-project lookup, the appProject.afterEvaluate libraryVariants.all x applicationVariants.all cross-product, the explicit merge<HostVariant>Assets.dependsOn edge, and the addFlutterDepsForModule legacy fork from P5 are deleted. - flutter.hostAppProjectName is now a no-op: it only fed the host lookup. A warning explains that it has no effect and will be removed in a future Flutter release. - The legacy com.android.builder.model.BuildType buildModeFor overload lost its last caller and is deleted along with its duplicate tests (the P2 name/debuggable and DSL overload tests cover the semantics). FlutterPlugin.kt and FlutterPluginUtils.kt no longer import any legacy (non com.android.build.api) AGP types. Verification (CI): build_android_host_app_with_module_source, module_host_with_custom_build, module_custom_host_app_name scenarios; module-root flutter build apk; add-to-app newDsl=true test; gradle unit tests on both AGP axes. Revert-safe until P10 lands (mutually tolerant with P6).
Phase P8 of the AGP public-API migration (flutter#180137, flutter#166550): - The library-project check no longer probes for the legacy android.libraryVariants property (absent under the new DSL); it checks for the com.android.library plugin. Error message unchanged. - The plugin-to-module assembleAar task wiring enumerates published variants through the public software components (which the script already used for task creation) instead of libraryVariants. - The singleVariant dedup guard no longer reads the internal publishing.singleVariants collection. Flutter now marks projects it configured with an ext property and declares each variant's publishing in a try-catch: when the project's own build file already declared publishing for a variant, the user's declaration wins and a warning explains the situation and the fix. (Previously any user-declared variant silently disabled Flutter's publishing setup for ALL variants, which broke partially-declared projects at publication time with no explanation.) Verification (CI): flutter build aar with and without flavors for module and plugin projects; AAR-host add-to-app flow; a scratch module with a partial user singleVariant declaration; newDsl=true aar flow. Revert-safe even after P10, but not after P9.
…it away Phase P9 of the AGP public-API migration (flutter#180137, flutter#166550) - the breaking-change PR. The Flutter Gradle Plugin is public-API-only since P7/P8, so projects no longer need android.newDsl=false: - The app and module gradle.properties templates no longer ship the newDsl opt-out (android.builtInKotlin=false stays; it belongs to the separate built-in Kotlin migration). - DisableNewDslMigration is replaced by RemoveNewDslOptOutMigration, which removes exactly the line pairs Flutter wrote: one of the two known marker comments ('added by the Flutter template' / 'added automatically by Flutter migrator') immediately followed by android.newDsl=false. The removal is anchored on the android.newDsl property line, so the adjacent builtInKotlin marker/flag lines are never touched; hand-added opt-outs and developer-edited values are respected; the file the old migrator created with only the flag is emptied. A visible status message names the change and links the breaking-change page. - New legacyVariantApiUsageErrorHandler matches the Gradle failures users hit when their build scripts use the removed legacy variant API (unknown property/method applicationVariants, libraryVariants, testVariants, variantFilter) and prints problem, cause, fix (androidComponents.onVariants), the breaking-change page URL, and the android.newDsl=false escape hatch with its AGP 10 expiry. useNewAgpDslErrorHandler is retired: its signature was the FGP's own legacy DSL access failing under newDsl, which can no longer happen. - kNewDslBreakingChangeDocsUrl pins the docs.flutter.dev page location; the in-repo website-page draft records that the page must be published at that exact path before this reaches beta. - The migration doc records the stable-channel release-management step (guard or accept the add-migrator flip-flop during the overlap window). - Updated test_result_embedder.gradle.kts in dev/integration_tests/android_hardware_smoke_test to resolve adbExecutable via ApplicationAndroidComponentsExtension (sdkComponents.adb) with fallback to BaseExtension, preventing Extension of type 'BaseExtension' does not exist when RemoveNewDslOptOutMigration enables newDsl=true. Verified here: android_project_migration_test.dart (42/42) and gradle_errors_test.dart (56/56) pass with the repo Dart SDK; dart analyze clean on the changed files. CI preconditions before this ships: full newDsl=true matrix green (R6), website page live, top-25 pub.dev plugin scratch-app sweep under -Pandroid.newDsl=true, and GradleHandledError eventLabel hit-rate monitoring during the beta soak as the stable go/no-go signal. Cleanly revertible in isolation.
Phase P10, the final phase of the AGP public-API migration (flutter#180137, flutter#166550): - build.gradle.kts swaps both AGP dependencies from the full com.android.tools.build:gradle artifact to com.android.tools.build:gradle-api. Compilation is now the proof that the plugin uses zero AGP internals (AGP 10 removes access to them entirely), on top of the InternalAgpApiImportTest source check and the validateNoCommonExtensionInBytecode bytecode check, which stay as fast-feedback guards. - FlutterPluginTest is rewritten on public-API mocks only: the AbstractAppExtension multi-interface mock, BaseExtension, CommonExtension, internal.dsl.DefaultConfig, and the legacy sourceSets/AndroidSourceDirectorySet mocks are gone. No test source references a full-artifact-only or internal type anymore. - The --android-skip-build-dependency-validation help text now warns that skipping validation cannot make unsupported AGP versions work: builds below the supported minimum fail in Gradle regardless. - The android tooling README gains the AGP-bump checklist step to run the FGP test suite against the new version's public API artifact (-PagpVersion axis) and links the migration doc. Verification (CI): full matrix per the migration doc (gradle unit tests on both AGP axes - now both against gradle-api; scratch-app matrix; add-to-app source/AAR flows; config-cache baseline). Dart analyzer clean on the changed tool file. Cleanly revertible in isolation.
81f5052 to
e303b7a
Compare
Stack Audit Summary & Re-Authoring GuidanceFollowing the review on Phase 6 (flutter/flutter#192488), an architectural and correctness audit was conducted across the remaining downstream pull requests in the stack (Phases 7 through 11). Detailed findings, evidence, and re-authoring instructions have been posted directly to each downstream PR on the fork:
Re-Authoring Next StepsWhen updating the stacked PR chain, branches should be re-authored / rebased against a recent cut of upstream |
This was llm authored. I am opening the pull request to see what happens in the presubmit environment.
This contains breaking changes.
Pre-launch Checklist
///).