Skip to content

AndroidX detection uses a raw substring match on gradle.properties, producing false positives/negatives #188306

Open

Description

@qeepcologne

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=true

Gradle 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 useAndroidX to true, 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

  1. In an app's android/gradle.properties, omit android.useAndroidX=true (relying on the AGP default), or write it with spaces around =.
  2. Run flutter build apk.
  3. Observe the spurious "isn't using AndroidX" warning. Re-add an exact android.useAndroidX=true substring — 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

  1. added
    platform-androidAndroid applications specifically
    toolAffects the "flutter" command-line tool. See also t: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    team-toolOwned by Flutter Tool team
    on Jun 22, 2026
  2. mbcorona commented on Jun 22, 2026

    @mbcorona
    Member

    Thanks for the detailed write-up and exact code references. Routing to team-tool.

  3. added
    team-androidOwned by Android platform team
    and removed
    team-toolOwned by Flutter Tool team
    on Jun 23, 2026
  4. added
    P2Important issues not at the top of the work list
    triaged-androidTriaged by Android platform team
    on Jun 23, 2026
  5. qeepcologne commented on Jun 30, 2026

    @qeepcologne
    Author

    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.

  6. theprantadutta commented on Sep 25, 2026

    @theprantadutta
    Contributor

    Picking up the part @qeepcologne flagged as still open after #188372 (which fixed the parsing): an absent android.useAndroidX is still treated as false.

    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.useAndroidX changed false → true from 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" as true would regress AGP 8 projects.

    That makes the fix narrow. The AGP version is already computed right next to the check in gradle.dart:

    final bool usesAndroidX = isAppUsingAndroidX(project.android.hostAppGradleRoot);
    final String? agpVersion = gradle.getAgpVersion(project.android.hostAppGradleRoot, globals.logger);

    Proposed:

    1. Have isAppUsingAndroidX distinguish "explicitly set" from "absent" — return bool? (or take the AGP version) instead of collapsing absent into false.
    2. When absent, use the AGP default: true for AGP ≥ 9.0, false below it, and false if the version can't be determined (today's behaviour, so nothing gets worse when detection fails).
    3. An explicit android.useAndroidX=false still wins on every AGP version.
    4. Tests in general.shard for 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 isAppUsingAndroidX returning bool and resolve the default at the call site.

  7. qeepcologne commented on Oct 30, 2026

    @qeepcologne
    Author

    Follow-up to #188372: the parsing half landed, but isAppUsingAndroidX still returns false for 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 own BooleanOption enum, with default true — same for android.enableJetifier. So in AGP 10 the property is gone, every project will omit it, and isAppUsingAndroidX will report app-not-using-android-x for all of them. (Setting it today is already a one-way street: AGP only warns when the value differs from the default, so =true is silent, and a removed option is a warning rather than an error — I checked with android.enableBuildCache.)

    On current master the value drives no behaviour at all:

    • gradle.dart:309 is 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:602 puts 'androidX' into the GeneratedPluginRegistrant.java template context, but the template never references it — the registrant is rendered from _androidPluginRegistryTemplateNewEmbedding unconditionally.
    • gradle_errors.dart:26 declares required bool usesAndroidX on the handler typedef; 25 handlers take it, none reads it.
    • There is no user-facing message left — no "isn't using AndroidX" text anywhere in lib/.

    Removal surface: isAppUsingAndroidX and its two call sites, the usesAndroidX parameter on the typedef and the 25 handlers, plus the matching test arguments (~50 references, 41 of them mechanical in gradle_errors_test.dart). FlutterProject.usesAndroidX is a different thing — it reads flutter: module: androidX: from pubspec.yaml for add-to-app scaffolding — and would stay.

  8. theprantadutta commented on Oct 30, 2026

    @theprantadutta
    Contributor

    @qeepcologne thanks, I checked this against current master and agree. The value only feeds the app-using-android-x / app-not-using-android-x analytics label (gradle.dart:309-329), the 'androidX' value at flutter_plugins.dart:602 is never read by the registrant template, and none of the 25 Gradle error handlers read usesAndroidX. 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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listhas reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyteam-androidOwned by Android platform teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-androidTriaged by Android platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions