Skip to content

Update to Android Gradle Plugin 9.0.1#481

Open
inktomi wants to merge 7 commits intorunningcode:masterfrom
inktomi:agp-9.0.1
Open

Update to Android Gradle Plugin 9.0.1#481
inktomi wants to merge 7 commits intorunningcode:masterfrom
inktomi:agp-9.0.1

Conversation

@inktomi
Copy link
Contributor

@inktomi inktomi commented Mar 2, 2026

Summary

Update to Android Gradle Plugin 9.0.1, resolving the "Could not find AppExtension error when newDsl=true" issue (the default in AGP 9.0).

This PR contains only AGP 9 functional migration changes. Code formatting/cleanup changes are in #482.

Changes

  • Migrate from legacy variant API (AppExtension, TestedExtension, BaseVariant) to new variant API (ApplicationExtension, ApplicationAndroidComponentsExtension, Variant)
  • Replace testVariants.configureEach with onVariants callbacks for APK path detection
  • Add VariantApkInfo data class to capture variant info during configuration phase
  • Update Gradle wrapper from 8.14.3 to 9.1.0 (minimum required by AGP 9.0)
  • Update Kotlin language/API version from 1.7 to 2.0
  • Remove kotlin-android plugin from sample projects (built-in in AGP 9.0)
  • Add <T : Any> type bounds for Kotlin 2.0 compatibility
  • Change task classes from open to abstract (AGP 9 requirement)
  • Update minimum Gradle version from 7.3 to 9.1
  • Applied Android Studio JVM migration (foojay toolchain resolution plugin)

Closes #478

Test plan

  • ./gradlew :fladle-plugin:check — all tests pass, lint clean
  • ./gradlew assembleDebug assembleDebugAndroidTest printYml — sample projects build with correct YAML output
  • ./gradlew :sample-flavors-kotlin:printYml — flavor-specific APK paths resolve correctly
  • ./gradlew printYml --configuration-cache — configuration cache works

@inktomi
Copy link
Contributor Author

inktomi commented Mar 2, 2026

The workflow passes on my local fork: https://github.com/inktomi/fladle/actions/runs/22598741034/job/65475320428

@inktomi
Copy link
Contributor Author

inktomi commented Mar 3, 2026

As part two of this, I'm working on reworking the fulladle plugin to support config caching. I will open that PR once this is reviewed, or ideally approved - I didn't want to work on it using old gradle APIs. I am introducing a new Settings plugin that people will have to apply so that we can get information about the modules without breaking caches - we can discuss more on that PR when the time comes.

Copy link

@emartynov emartynov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super!

I would really ask you to split this into two PRs:

  1. AGP 9 support
  2. Code cleanup and improvements

Also not sure about hard cut of the lower supported version 9.1.0. I would probably at least support anything 9.x. And not sure about folks that are still on AGP 8.x.

@inktomi
Copy link
Contributor Author

inktomi commented Mar 4, 2026 via email

inktomi added 2 commits March 4, 2026 12:35
- Migrate from legacy variant API (AppExtension, TestedExtension, BaseVariant)
  to new variant API (ApplicationExtension, ApplicationAndroidComponentsExtension, Variant)
- Replace testVariants.configureEach with onVariants callbacks for APK path detection
- Add VariantApkInfo data class to capture variant info during configuration
- Update Gradle wrapper from 8.14.3 to 9.1.0 (minimum required by AGP 9.0)
- Update Kotlin language/API version from 1.7 to 2.0
- Remove kotlin-android plugin from sample projects (built-in in AGP 9.0)
- Add <T : Any> type bounds for Kotlin 2.0 compatibility
- Change task classes from open to abstract (AGP 9 requirement)
- Update minimum Gradle version from 7.3 to 9.1

Fixes runningcode#478
@inktomi
Copy link
Contributor Author

inktomi commented Mar 4, 2026

The build fails on my fork - https://github.com/inktomi/fladle/actions/runs/22688439185

But it's because of issues that would be fixed by running the formatters - that's on the other branch now.

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9.1 is the min compatible version for AGP 9.0.1

https://developer.android.com/build/releases/about-agp#updating-gradle

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad - I was mixing AGP version with Gradle version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The min gradle version is also changed; it was good to call out for visibility! AGP doesn't give much flexibility here.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Did you update the wrapper task as well to go along with this change? run ./gradlew wrapper twice to make sure.

See the "tip" here about running it "again": https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:upgrading_wrapper

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running it the second time now. Good catch.


tasks.wrapper.configure {
gradleVersion = '8.14.3'
gradleVersion = '9.1.0'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with the settings for the overall project, this is the minimum required version for AGP 9.0.1

@inktomi inktomi requested a review from emartynov March 4, 2026 21:27
@emartynov
Copy link

Looks like some merge conflicts.

But the rest (Even some changes looks like not related) the change is LGTM.

@runningcode how does it look for you?

@runningcode
Copy link
Owner

Thank you so much for this work! It looks great.

Looks like there's a small lint error on CI.
Could you please also add an entry to the docs/changelog.md ?

* Minimum required JVM version is now 17.
* Minimum supported Gradle version is now 7.3.
* Minimum supported Gradle version is now 9.1 (the minimum supported version for AGP 9.0.1).
* Fixed support for Android Gradle Plugin version 9.0.1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will go in the next release, could you put it in the unreleased section?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hah wooop! Sorry! Will fix this right now.

@inktomi inktomi requested a review from runningcode March 5, 2026 16:28
Copy link
Owner

@runningcode runningcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I gave it a thorough look and added some comments!

base.flankCoordinates.finalizeValueOnRead()
base.serviceAccountCredentials.finalizeValueOnRead()

// Register onVariants callbacks before afterEvaluate for APK path detection
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious is there a reason for the order change here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is part of the 9.0.1 upgrade - we used testVariants.configureEach before which was a lazy API that worked fine inside afterEvaluate. The new version must be registered during the configuration phase, before variants are finalized and so if we kept it using afterEvaluate it could be executed too late in the lifecycle which could make the callback flaky. The change in the execution order prevents that.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it. 👍

val useOrchestrator =
androidExtension.testOptions.getExecutionEnum() == TestOptions.Execution.ANDROIDX_TEST_ORCHESTRATOR ||
androidExtension.testOptions.getExecutionEnum() == TestOptions.Execution.ANDROID_TEST_ORCHESTRATOR
execution == "ANDROIDX_TEST_ORCHESTRATOR" ||
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to use the constants here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TestOptions actually goes away with the upgrade, so we can't use it anymore. I replaced them with string comparison since the enum was removed from the public API.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah makes sense!

execution == "ANDROID_TEST_ORCHESTRATOR"
if (useOrchestrator) {
log("Automatically detected the use of Android Test Orchestrator")
config.useOrchestrator.set(true)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:O was this a bug earlier?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it was sort of a bug! Consider this:

  • testOptions.execution = AGP's setting (in the android {} block)
  • config.useOrchestrator = Fladle's setting (in the fladle {} block)

The auto-detection reads from AGP's testOptions and writes to Fladle's config.useOrchestrator. Both happen in afterEvaluate, but the auto-detection runs last, so it wins.

An example: a user sets useOrchestrator = true in their Fladle config, but does not configure testOptions.execution for orchestrator in AGP. The old code reads AGP's testOptions → sees no orchestrator → calls config.useOrchestrator.set(false) → stomps on the user's explicit Fladle setting.

Setting it to true explicitly like this preserves their config when it's not also configured in fladle.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for fixing this!

extensions.create("fulladleModuleConfig", FulladleModuleExtension::class.java)

// Register onVariants callbacks to capture APK info during configuration
pluginManager.withPlugin("com.android.application") {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this code be moved or shared with the FladlePluginDelegate ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, we're doing different things here:

FladlePluginDelegate reads variant info to set debugApk/instrumentationApk on the Fladle extension directly. FulladlePlugin collects variant info into VariantApkInfo objects on FulladleModuleExtension.variantApks for later processing in configureModule(). The outputs and data flows are different between the two, so we can't directly share the code.

I'm also working on migrating FulladlePlugin into a settings plugin to allow compatibility with the configuration cache. This code will have to move then, because the root-level settings plugin won't have access to the variants anymore - there will be a secondary settings-applied convention plugin that gets applied to each module which gathers that data internally.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Oh that migration to a settings plugin really makes sense!

Copy link
Owner

@runningcode runningcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
Looks like github actions are having issues right now https://www.githubstatus.com/

I'll merge this when the action runs and passes

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.

Add support for AGP 9.0.0

3 participants