Sitelet https://github.com/reidbaker-agent/flutter/pull/8
Skip to content

Unify add-to-app module wiring on the variant API and drop host-project cross-wiring - #8

Open
reidbaker-agent wants to merge 9 commits into
agp-apk-copy-versioncodefrom
agp-add-to-app
Open

reidbaker-agent wants to merge 9 commits into
agp-apk-copy-versioncodefrom
agp-add-to-app

Conversation

@reidbaker-agent

@reidbaker-agent reidbaker-agent commented Jul 22, 2026 •

Copy link
Copy Markdown
Owner

Phase 8 of 11 of the AGP public-API migration; stacked on #7.

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).

CI must run the FGP unit tests (the Kotlin suite in packages/flutter_tools/gradle could not run in the delivery sandbox: dl.google.com returns 403, so AGP artifacts do not resolve).

@reidbaker-agent
reidbaker-agent force-pushed the agp-apk-copy-versioncode branch from c051ed0 to 1d44353 Compare July 22, 2026 15:54
@reidbaker-agent
reidbaker-agent force-pushed the agp-apk-copy-versioncode branch from 1d44353 to f3d2a31 Compare July 28, 2026 13:36
@reidbaker-agent
reidbaker-agent force-pushed the agp-apk-copy-versioncode branch from f3d2a31 to 91f0814 Compare July 28, 2026 13:37
@reidbaker-agent
reidbaker-agent force-pushed the agp-apk-copy-versioncode branch from 91f0814 to 45e5dea Compare July 29, 2026 20:21
@reidbaker-agent
reidbaker-agent force-pushed the agp-apk-copy-versioncode branch from 45e5dea to 9ce1623 Compare July 29, 2026 20:43
@reidbaker-agent
reidbaker-agent force-pushed the agp-apk-copy-versioncode branch from 9ce1623 to e34a92a Compare July 30, 2026 21:59
@reidbaker-agent
reidbaker-agent force-pushed the agp-apk-copy-versioncode branch from e34a92a to b7a23f7 Compare July 31, 2026 16:16
…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.
@reidbaker
reidbaker force-pushed the agp-apk-copy-versioncode branch from b7a23f7 to 53bcc7f Compare July 31, 2026 18:07
…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).
pull Bot pushed a commit to Little-Star888/flutter that referenced this pull request Aug 12, 2026
…on documentation (flutter#190842)

There are 2 files in this pr. One is a document the ai used to keep
track of work. More importantly it acts kind of like issues so it
references the items in future prs. The second is user facing website
documentation. I do not know if we will use it verbatim but for the set
of prs lets treat that md doc as human understandable documentation that
we must understand before landing the next pr.

Reviewers: When the pr is out of draft and your comments are fully
addressed please prioritize this pr over other work. The review bar is
higher, the number of reviews has more people and the work for the next
pr is already done.
 - @reidbaker 
---
Standard review context for this pr stack

This is PR is part of an 11 pr stack to migrate the "newdsl"
`gradle-api` specifically in agp 9.1.0.
The complete stack has pass pre submits, post submits and customer
tests.
https://flutter-dashboard.appspot.com/#/build?repo=flutter&branch=experimental/agp-gradle-api

All of the code was LLM authored. A mix of manual prompting, automatic
prompting, several models and adversarial review. The combined sessions
are enough that I cannot include relevant prompts like I have been doing
on other prs.

If you want to review the pr stack you can find it here. These prs will
be abandoned/closed as prs land into flutter/flutter.
1. reidbaker-agent#1 (branch:
agp-api-doc)
2. reidbaker-agent#2 (branch:
agp-internal-utils)
3. reidbaker-agent#3 (branch:
agp-buildmode-deps)
4. reidbaker-agent#4 (branch:
agp-plugin-buildtypes)
5. reidbaker-agent#5 (branch:
agp-ndk-fallback)
6. reidbaker-agent#6 (branch:
agp-assets-onvariants)
7. reidbaker-agent#7 (branch:
agp-apk-copy-versioncode)
8. reidbaker-agent#8 (branch:
agp-add-to-app)
9. reidbaker-agent#9 (branch:
agp-aar-script)
10. reidbaker-agent#10 (branch:
agp-newdsl-flip)
11. reidbaker-agent#11 (branch:
agp-gradle-api)

Follow up work is tracked in
flutter#190964

This work is urgent in the sense that we are worried that android will
publish agp 10 with no opt out but not so urgent that we are willing to
break flutter users because we didn't review or understand the code
because we were in a rush.

Breaking changes are expected as part of this work. There are patterns
the android team explicitly does not want apps to use and apis that have
no equivalent.

As part of the effort to ensure this work does not slip into ai slop,
prs from this stack will be reviewed by me (@reidbaker) before asking
for review. Then we will have 2 android expert reviewers also review the
every pr.

---
Agent authored pr description
This is PR 1 of 11 in the AGP 9.1.0 / public `gradle-api` migration
stack.

It adds the contributor-facing and website draft documentation for the
Flutter Gradle Plugin's migration to the Android Gradle Plugin public
Variant API, which unblocks building Flutter Android apps with AGP's
`newDsl=true` enabled.

Part of flutter#180137 and flutter#166550.

## 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 documentation (doc comments with `///`).
- [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.

---------

Co-authored-by: reidbaker-agent <reidbaker@google.com>
okorohelijah pushed a commit to okorohelijah/flutter that referenced this pull request Aug 17, 2026
…90957)

This is PR 2 of 11 in the AGP 9.1.0 / public `gradle-api`/ newdls
migration stack.

This PR extracts some common utilities used in the Flutter Gradle Plugin
to internal functions, to be used in upcoming PRs in this stack. It also
introduces a typesafe CompileSdkVersion that handles comparisons between
api versions and preview versions which are strings.

First attempt was here flutter#190949
this pr includes my feedback from that first review. The first attempt
did not follow the pattern of having the agent account open the pr
because of rebase shenanigans that ended up touching freeze.yml.

---
Standard review context for this pr stack

This is PR is part of an 11 pr stack to migrate the "newdsl"
`gradle-api` specifically in agp 9.1.0.
The complete stack has pass pre submits, post submits and customer
tests.
https://flutter-dashboard.appspot.com/#/build?repo=flutter&branch=experimental/agp-gradle-api

All of the code was LLM authored. A mix of manual prompting, automatic
prompting, several models and adversarial review. The combined sessions
are enough that I cannot include relevant prompts like I have been doing
on other prs.

If you want to review the pr stack you can find it here. These prs will
be abandoned/closed as prs land into flutter/flutter.
1. reidbaker-agent#1 (branch:
agp-api-doc)
2. reidbaker-agent#2 (branch:
agp-internal-utils)
3. reidbaker-agent#3 (branch:
agp-buildmode-deps)
4. reidbaker-agent#4 (branch:
agp-plugin-buildtypes)
5. reidbaker-agent#5 (branch:
agp-ndk-fallback)
6. reidbaker-agent#6 (branch:
agp-assets-onvariants)
7. reidbaker-agent#7 (branch:
agp-apk-copy-versioncode)
8. reidbaker-agent#8 (branch:
agp-add-to-app)
9. reidbaker-agent#9 (branch:
agp-aar-script)
10. reidbaker-agent#10 (branch:
agp-newdsl-flip)
11. reidbaker-agent#11 (branch:
agp-gradle-api)

This work is urgent in the sense that we are worried that android will
publish agp 10 with no opt out but not so urgent that we are willing to
break flutter users because we didn't review or understand the code
because we were in a rush.

Breaking changes are expected as part of this work. There are patterns
the android team explicitly does not want apps to use and apis that have
no equivalent.

As part of the effort to ensure this work does not slip into ai slop,
prs from this stack will be reviewed by me (@reidbaker) before asking
for review. Then we will have 2 android expert reviewers also review the
every pr.

--- 
Agent authored description. 
This is PR 2 of 11 in the AGP 9.1.0 / public `gradle-api` migration
stack.

This PR extracts some common utilities used in the Flutter Gradle Plugin
to internal functions, to be used in upcoming PRs in this stack.

## 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 documentation (doc comments with `///`).
- [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.

---------

Co-authored-by: reidbaker-agent <reidbaker@google.com>
Co-authored-by: Reid Baker <1063596+reidbaker@users.noreply.github.com>
pull Bot pushed a commit to TheRakeshPurohit/flutter that referenced this pull request Aug 24, 2026
…dependencies through the new DSL (flutter#191218)

This is PR 3 of 11 in the AGP 9.1.0 / public `gradle-api`/ newdsl
migration stack.

* It migrates many (but not all) usages of getLegacyAndroidExtension. 
* Introduces consistency in renaming of imports. 
* Adds a test to ensure we are not adding internal apis (thanks
@mboetger from pr1)
* builds the ability to run our gradle tests with multiple AGP versions
(see packages/flutter_tools/gradle/build.gradle.kts)

Between PR 3 and PR 8, an Add-to-app host app embedding a Flutter module
with a custom build type (for example "staging") gets release engine
artifacts. That means hot reload, debugger attach, and DevTools do not
operate in that build.
We can't move the work in PR 8 up but I would not want to cut a release
between this pr and 8 landing. If we keep reviewing one pr a day then
that is not a risk.

Apps impacted by this change can use matchingFallbacks to avoid this
problem (see code below).

In pr 8 we change when we look for "isDebuggable" to much later in the
gradle lifeycle when all the variants have been created which then lets
us use a new api to understand if the variant is intended to be
debuggable.

Kotlin 
```kotlin
// host app build.gradle.kts
android {
    buildTypes {
        create("staging") {
            isDebuggable = true
            applicationIdSuffix = ".staging"
            matchingFallbacks += "debug" /// This line. 
        }
    }
}
```
Groovy 
```groovy
// host app build.gradle
android {
    buildTypes {
        staging {
            debuggable true
            applicationIdSuffix ".staging"
            matchingFallbacks = ['debug'] /// This line. 
        }
    }
}
```

Depends on flutter#190957 (PR 2).
- @reidbaker 


---
Standard review context for this pr stack

This is PR is part of an 11 pr stack to migrate the "newdsl"
`gradle-api` specifically in agp 9.1.0.
The complete stack has passed presubmits, postsubmits, and customer
tests:
https://flutter-dashboard.appspot.com/#/build?repo=flutter&branch=experimental/agp-gradle-api

All of the code was LLM authored. A mix of manual prompting, automatic
prompting, several models and adversarial review. The combined sessions
are enough that I cannot include relevant prompts like I have been doing
on other prs.

If you want to review the pr stack you can find it here. These prs will
be abandoned/closed as prs land into flutter/flutter.
1. reidbaker-agent#1 (branch:
agp-api-doc)
2. reidbaker-agent#2 (branch:
agp-internal-utils)
3. reidbaker-agent#3 (branch:
agp-buildmode-deps)
4. reidbaker-agent#4 (branch:
agp-plugin-buildtypes)
5. reidbaker-agent#5 (branch:
agp-ndk-fallback)
6. reidbaker-agent#6 (branch:
agp-assets-onvariants)
7. reidbaker-agent#7 (branch:
agp-apk-copy-versioncode)
8. reidbaker-agent#8 (branch:
agp-add-to-app)
9. reidbaker-agent#9 (branch:
agp-aar-script)
10. reidbaker-agent#10 (branch:
agp-newdsl-flip)
11. reidbaker-agent#11 (branch:
agp-gradle-api)

This work is urgent in the sense that we are worried that android will
publish agp 10 with no opt out but not so urgent that we are willing to
break flutter users because we didn't review or understand the code
because we were in a rush.

Breaking changes are expected as part of this work. There are patterns
the android team explicitly does not want apps to use and apis that have
no equivalent.

As part of the effort to ensure this work does not slip into ai slop,
prs from this stack will be reviewed by me (@reidbaker) before asking
for review. Then we will have 2 android expert reviewers also review
every pr.

--- 
Agent authored description. 
This is PR 3 of 11 in the AGP 9.1.0 / public `gradle-api` migration
stack (flutter#180137, flutter#166550).

### Key Changes
- **DSL Build Mode Overloads**: Adds `buildModeFor` overloads accepting
`ApplicationBuildType`, `DynamicFeatureBuildType`, and
`LibraryBuildType` DSL types alongside the `(buildTypeName,
isDebuggable)` core overload.
- **Robust CompileSdkVersion Domain Model**: Extracts
`CompileSdkVersion` with constructor invariant validation (`init {
require(...) }`) enforcing mutual exclusivity between `apiLevel` and
`previewCodename`.
- **Namespaced Multi-AGP Build Property**: Namespaces the AGP version
property in `packages/flutter_tools/gradle/build.gradle.kts` as
`flutter.internal.agpVersion` (defaulting to `8.11.1`) to prevent user
app properties from leaking into the included build during app
compilation.
- **Standardized Type Aliasing**: Applies non-temporal type aliasing
(`import com.android.build.api.dsl.BuildType as DslBuildType`) across
`FlutterPlugin.kt` and `PluginHandler.kt`.
- **Public DSL Extension Access**: Updates `addFlutterDependencies` and
`PluginHandler` to iterate `AgpCommonExtensionWrapper.buildTypes`.
- **Build & Bytecode Validation**: Adds the
`:validateNoCommonExtensionInBytecode` task in `build.gradle.kts` to
prevent compiled main classes from referencing binary-incompatible
`CommonExtension`, and adds `BytecodeValidatorTest.kt` verifying the
binary pattern-matching and class scanning logic.
- **Comprehensive Unit Tests**: Adds full 4-way dispatch test coverage
in `AgpCommonExtensionWrapperTest`, dependency wiring tests in
`FlutterPluginTest`, and decomposes `PluginHandlerTest` mock fixtures
into focused helpers with positive assertions.

### Add-to-App & DSL Scope Context
`LibraryBuildType` does not expose `isDebuggable` at DSL scope. In PR 3,
custom build types on library projects (e.g. host app 'staging') fall
back to `"release"` at DSL scope. In PR 8 ("Unify add-to-app module
wiring on the variant API"), module wiring will be unified on
`Component.debuggable` at variant scope.

## 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 documentation (doc comments with `///`).
- [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.

---------

Co-authored-by: reidbaker-agent <reidbaker@google.com>
Co-authored-by: Reid Baker <1063596+reidbaker@users.noreply.github.com>
NikhilKukreja26 pushed a commit to NikhilKukreja26/flutter that referenced this pull request Aug 28, 2026
…nitWith on public DSL (flutter#191606)

This is PR 4 of 11 in the AGP 9.1.0 / public `gradle-api` / newdsl
migration stack.

There are no breaking changes expected in this pr. Only internal logic
is impacted.

I will be honest I also found the tests hard to review. I had the agent
pull out shared mocking logic but I am not sure that actually made
review easier.

Depends on flutter#191218 (PR 3).
- @reidbaker

---
Standard review context for this pr stack

This is PR is part of an 11 pr stack to migrate the "newdsl"
`gradle-api` specifically in agp 9.1.0.

All of the code was LLM authored. A mix of manual prompting, automatic
prompting, several models and adversarial review. The combined sessions
are enough that I cannot include relevant prompts like I have been doing
on other prs.

If you want to review the pr stack you can find it here. These prs will
be abandoned/closed as prs land into flutter/flutter.
1. reidbaker-agent#1 (branch:
agp-api-doc)
2. reidbaker-agent#2 (branch:
agp-internal-utils)
3. reidbaker-agent#3 (branch:
agp-buildmode-deps)
4. reidbaker-agent#4 (branch:
agp-plugin-buildtypes)
5. reidbaker-agent#5 (branch:
agp-ndk-fallback)
6. reidbaker-agent#6 (branch:
agp-assets-onvariants)
7. reidbaker-agent#7 (branch:
agp-apk-copy-versioncode)
8. reidbaker-agent#8 (branch:
agp-add-to-app)
9. reidbaker-agent#9 (branch:
agp-aar-script)
10. reidbaker-agent#10 (branch:
agp-newdsl-flip)
11. reidbaker-agent#11 (branch:
agp-gradle-api)

This work is urgent in the sense that we are worried that android will
publish agp 10 with no opt out but not so urgent that we are willing to
break flutter users because we didn't review or understand the code
because we were in a rush.

Breaking changes are expected as part of this work. There are patterns
the android team explicitly does not want apps to use and apis that have
no equivalent.

As part of the effort to ensure this work does not slip into ai slop,
prs from this stack will be reviewed by me (@reidbaker) before asking
for review. Then we will have 2 android expert reviewers also review
every pr.

---
Agent authored description.
This is PR 4 of 11 in the AGP 9.1.0 / public `gradle-api` migration
stack (flutter#180137, flutter#166550).

### Key Changes
- **Public DSL `initWith` Copy**: Replaces the legacy
`getLegacyAndroidExtension` build-type copy in `PluginHandler` with
`initWith` on the public DSL (`AgpCommonExtensionWrapper.buildTypes`).
Missing build types on the plugin project are created with
`initWith(appBuildType)`, and `isDebuggable` is copied when both sides
are `ApplicationBuildType`.
- **Zero AGP Internals in Production Sources**: Removes the last
remaining `com.android.build.gradle.internal` imports from production
code (`src/main`).
- **Internal AGP Import Guard**: Adds `InternalAgpApiImportTest` to
continuously enforce that production sources do not introduce
`com.android.build.gradle.internal.*` imports.
- **Decomposed & Robust Unit Tests**: Replaces legacy mock-only tests in
`PluginHandlerTest` with tests that execute `configurePlugins` and
verify `initWith` copying for both library and application plugin
projects, mapping custom debuggable build types to debug engine
artifacts, and verifying that pre-existing plugin build types are
skipped.
- **Migration Documentation Update**: Adds details for the P3 pre-spike
and `finalizeDsl` fallback in
`Migrating-Flutter-Gradle-Plugin-to-AGP-public-API.md`.

## 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 documentation (doc comments with `///`).
- [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.
bkonyi pushed a commit to bkonyi/flutter that referenced this pull request Sep 4, 2026
… NDK fallback to public DSL (flutter#192116)

This is PR 5 of 11 in the AGP 9.1.0 / public `gradle-api` / newdsl
migration stack.

Add externalNativeBuild to the shared type. Extracted some shared
mocking logic to a utility.
No external visible changes expected. 
Also improved the README.md so that the test file for multiple agp
versions was a markdown link.

- @reidbaker

---
Standard review context for this pr stack

This is PR is part of an 11 pr stack to migrate the "newdsl"
`gradle-api` specifically in agp 9.1.0.

All of the code was LLM authored. A mix of manual prompting, automatic
prompting, several models and adversarial review. The combined sessions
are enough that I cannot include relevant prompts like I have been doing
on other prs.

If you want to review the pr stack you can find it here. These prs will
be abandoned/closed as prs land into flutter/flutter.
1. reidbaker-agent#1 (branch:
agp-api-doc)
2. reidbaker-agent#2 (branch:
agp-internal-utils)
3. reidbaker-agent#3 (branch:
agp-buildmode-deps)
4. reidbaker-agent#4 (branch:
agp-plugin-buildtypes)
5. reidbaker-agent#5 (branch:
agp-ndk-fallback)
6. reidbaker-agent#6 (branch:
agp-assets-onvariants)
7. reidbaker-agent#7 (branch:
agp-apk-copy-versioncode)
8. reidbaker-agent#8 (branch:
agp-add-to-app)
9. reidbaker-agent#9 (branch:
agp-aar-script)
10. reidbaker-agent#10 (branch:
agp-newdsl-flip)
11. reidbaker-agent#11 (branch:
agp-gradle-api)

This work is urgent in the sense that we are worried that android will
publish agp 10 with no opt out but not so urgent that we are willing to
break flutter users because we didn't review or understand the code
because we were in a rush.

Breaking changes are expected as part of this work. There are patterns
the android team explicitly does not want apps to use and apis that have
no equivalent.

As part of the effort to ensure this work does not slip into ai slop,
prs from this stack will be reviewed by me (@reidbaker) before asking
for review. Then we will have 2 android expert reviewers also review
every pr.

---
Agent authored description.
This is PR 5 of 11 in the AGP 9.1.0 / public `gradle-api` migration
stack (flutter#180137, flutter#166550).

### Key Changes
- **Public DSL Wrapper `externalNativeBuild`**: Exposes `val
externalNativeBuild: ExternalNativeBuild` in
`AgpCommonExtensionWrapper.kt` dispatching across
`ApplicationExtension`, `LibraryExtension`, `DynamicFeatureExtension`,
and `TestExtension` without referencing `CommonExtension` (bypassing AGP
binary incompatibility).
- **Zero Legacy `BaseExtension` in Production Sources**: Deletes
`getLegacyAndroidExtension(project: Project): BaseExtension` and removes
the `com.android.build.gradle.BaseExtension` import from
`FlutterPluginUtils.kt`.
- **Public DSL NDK Fallback Configuration**: Migrates `forceNdkDownload`
and `configureSyntheticExternalNativeBuildFallback` in
`FlutterPluginUtils.kt` to `getAndroidExtension(gradleProject)` using
`externalNativeBuild.cmake` / `externalNativeBuild.ndkBuild`. Sets
`cmake.path = File(...)`, `cmake.buildStagingDirectory = ...`, and
`buildType.externalNativeBuild.cmake.arguments += ...` through the
public DSL while preserving the upstream PR flutter#187201 `ndkBuild.path`
check.
- **Unit Test Public DSL Mocking & Cleanup**: Migrates unit tests in
`FlutterPluginUtilsTest.kt` to mock public DSL types
(`ApplicationExtension`, `Cmake`, `NdkBuild`), asserts CMake arguments
by list content, deletes obsolete tests asserting
`ApplicationExtension`-vs-`BaseExtension` `ndkVersion` preference, and
removes unused `import io.mockk.called` as well as all legacy
`com.android.build.gradle.internal.*` imports.

## 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 documentation (doc comments with `///`).
- [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.
@reidbaker-agent

Copy link
Copy Markdown
Owner Author

Stack Audit Findings & Guidance for Updating Agent

Context: This pull request (Phase 8 of the AGP 9.1.0 migration) was audited as part of review on flutter/flutter#192488 (Phase 6).
Action Required: Re-author / rebase this branch from a recent cut of the upstream flutter/flutter master branch + the updated Phase 6 (flutter/flutter#192488) and Phase 7 (#7).

Issues to resolve when re-authoring this PR:

  1. Eliminate String-Based Compile Task Lookup in CopyFlutterJniLibsTask (Mis-architected wiring):

    • Evidence: FlutterPlugin.kt:319-340. The task lookup still relies on:
      dependsOn(projectToAddTasksTo.tasks.matching { it.name == compileTaskName })
      intermediateDir.set(
          projectToAddTasksTo.layout.dir(
              projectToAddTasksTo.provider {
                  val compileTask = projectToAddTasksTo.tasks.findByName(compileTaskName) as? FlutterTask
                  compileTask?.outputDirectory
              }
          )
      )
    • Why it's a problem: In Phase 6, looking up the compile task by name was a necessary compromise because add-to-app module compile tasks were registered in legacy libraryVariants. In Phase 8, however, both app and module compile tasks are registered in the same onVariants callback (compileTaskProvider at L359). String-based lookup is no longer needed. Furthermore, tasks.matching { ... } causes Gradle to eagerly realize and configure every registered task in the container.
    • Direction: Wire CopyFlutterJniLibsTask directly from compileTaskProvider (e.g. intermediateDir.set(compileTaskProvider.map { it.outputDirectory })), matching the pattern used for assets in Phase 6.
  2. Avoid Control-Flow via Mid-Block return@onVariants:

    • Evidence: FlutterPlugin.kt:396-401 has if (!isAppProject) { return@onVariants } in the middle of the onVariants lambda.
    • Why it's a problem: Deciding whether task registration applies to modules based solely on whether it precedes or follows a mid-block return is error-prone. Any shared wiring added at the bottom of the lambda will silently skip modules. It also compressed compilation, asset delivery, and APK copying into a single ~100-line inline block, undoing the clean separation of concerns established in Phase 6.
    • Direction: Modularize variant configuration into explicit helper functions (e.g. configureAppVariantOutputs and configureModuleVariantOutputs) rather than early returns.
  3. Remove Redundant dependsOn:

    • Evidence: In copyFlutterAssets registration, both dependsOn(compileTaskProvider) and intermediateDir.set(compileTaskProvider.map { ... }) are present.
    • Direction: Drop the explicit dependsOn(compileTaskProvider); the Gradle Provider mapping already establishes the task dependency edge.
  4. Cleanup Dead Overload and Cross-Project Property Read:

    • Evidence: FlutterPluginUtils.shouldConfigureFlutterTask(Project, Task) has no production callers. Remove it.
    • Evidence: FlutterPlugin.kt:474 reads projectToAddTasksTo.rootProject.hasProperty("flutter.hostAppProjectName"). Reading rootProject breaks Gradle Isolated Projects. Use projectToAddTasksTo.providers.gradleProperty(...) instead. Also update dev/integration_tests/pure_android_host_apps/android_custom_host_app/gradle.properties to stop setting this deprecated property so the fixture doesn't emit deprecation warnings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants