Repository navigation
Description
Summary
isAppUsingAndroidX() (gradle.dart:1090) decides whether a project uses AndroidX with a raw substring search over the entire gradle.properties file:
return properties.readAsStringSync().contains('android.useAndroidX=true');This is not a property parse, so the result doesn't reflect the effective Gradle property value. It both false-positives and false-negatives, and the only way to silence a spurious warning is a hacky comment.
False positive
A commented-out line still matches, because the substring is present:
#android.useAndroidX=trueGradle ignores that line, but Flutter reports AndroidX as enabled. Same for the string appearing in any comment or unrelated context.
False negative
android.useAndroidX = true(spaces around=, valid for Gradle) does not match.- AGP 7+ defaults
useAndroidXtotrue, and AGP 8 makes non-AndroidX effectively unsupported. A project that omits the line is correctly on AndroidX, yet Flutter prints⚠ Your app isn't using AndroidX(gradle.dart:295–311) and points to the migration guide.
Steps to reproduce
- In an app's
android/gradle.properties, omitandroid.useAndroidX=true(relying on the AGP default), or write it with spaces around=. - Run
flutter build apk. - Observe the spurious "isn't using AndroidX" warning. Re-add an exact
android.useAndroidX=truesubstring — even commented out — and it disappears.
Expected behavior
Detect AndroidX from the effective Gradle property (parse gradle.properties, honoring whitespace and comments), or — given AGP 8 no longer supports non-AndroidX — drop the check entirely. The existing // TODO(egarciad) above the function already references the (now-closed) #40800 for unifying this detection.
Environment
Flutter 3.44.2 stable; the code is unchanged on master.
Activity
mbcorona commentedon Jun 22, 2026
Thanks for the detailed write-up and exact code references. Routing to team-tool.
qeepcologne commentedon Jun 30, 2026
This fixes the parsing. But when the property is absent entirely, it still returns false → Flutter still emits the ⚠ Your app isn't using AndroidX warning. The issue's second concern — that AGP 7+/8+ defaults to AndroidX so an omitted property should be treated as valid — is left untouched.
Parse AndroidX property in gradle.properties (flutter#188372)
theprantadutta commentedon Sep 25, 2026
Picking up the part @qeepcologne flagged as still open after #188372 (which fixed the parsing): an absent
android.useAndroidXis still treated asfalse.One correction to the premise, because it changes what the fix should be. Per the AGP 9.0 release notes ("Behavior changes"), the default for
android.useAndroidXchangedfalse→truefrom AGP 8.13 to AGP 9.0. So on AGP 7.x/8.x an omitted property really does mean AndroidX is off, and today's behaviour is correct there. It's only wrong on AGP 9.0+. Blindly treating "absent" astruewould regress AGP 8 projects.That makes the fix narrow. The AGP version is already computed right next to the check in
gradle.dart:Proposed:
isAppUsingAndroidXdistinguish "explicitly set" from "absent" — returnbool?(or take the AGP version) instead of collapsing absent intofalse.truefor AGP ≥ 9.0,falsebelow it, andfalseif the version can't be determined (today's behaviour, so nothing gets worse when detection fails).android.useAndroidX=falsestill wins on every AGP version.general.shardfor the explicit true/false cases, absent + AGP 8.x, absent + AGP 9.x, and absent + unknown version.I'd like to take this if that shape sounds right to the Android team — happy to go with a different API if you'd rather keep
isAppUsingAndroidXreturningbooland resolve the default at the call site.qeepcologne commentedon Oct 30, 2026
Follow-up to #188372: the parsing half landed, but
isAppUsingAndroidXstill returnsfalsefor a project that omits the property (return usesAndroidX ?? false;,gradle.dart:1214). I'd suggest dropping the check entirely rather than adding an AGP-version-dependent default, because AGP is about to remove the property anyway.AGP 9.5.0 marks it
ApiStage.Deprecated(DeprecationTarget.VERSION_10_0)in its ownBooleanOptionenum, with defaulttrue— same forandroid.enableJetifier. So in AGP 10 the property is gone, every project will omit it, andisAppUsingAndroidXwill reportapp-not-using-android-xfor all of them. (Setting it today is already a one-way street: AGP only warns when the value differs from the default, so=trueis silent, and a removed option is a warning rather than an error — I checked withandroid.enableBuildCache.)On current master the value drives no behaviour at all:
gradle.dart:309is the only call in the build path; its sole consumer is the analytics label at:325(app-using-android-x/app-not-using-android-x).flutter_plugins.dart:602puts'androidX'into theGeneratedPluginRegistrant.javatemplate context, but the template never references it — the registrant is rendered from_androidPluginRegistryTemplateNewEmbeddingunconditionally.gradle_errors.dart:26declaresrequired bool usesAndroidXon the handler typedef; 25 handlers take it, none reads it.lib/.Removal surface:
isAppUsingAndroidXand its two call sites, theusesAndroidXparameter on the typedef and the 25 handlers, plus the matching test arguments (~50 references, 41 of them mechanical ingradle_errors_test.dart).FlutterProject.usesAndroidXis a different thing — it readsflutter: module: androidX:frompubspec.yamlfor add-to-app scaffolding — and would stay.theprantadutta commentedon Oct 30, 2026
@qeepcologne thanks, I checked this against current master and agree. The value only feeds the
app-using-android-x/app-not-using-android-xanalytics label (gradle.dart:309-329), the'androidX'value atflutter_plugins.dart:602is never read by the registrant template, and none of the 25 Gradle error handlers readusesAndroidX. So removing the check is simpler than the AGP-gated default I proposed above, and it won't go stale when AGP drops the property. The one open question for the Android team is whether they still want that analytics label. If removal sounds right, I'm happy to put up the PR, or to leave it to you if you're planning one.