Skip to content

Kgp warning - #3984

Closed
Crucialjun wants to merge 5 commits into
getsentry:mainfrom
Crucialjun:kgp_warning
Closed

Kgp warning#3984
Crucialjun wants to merge 5 commits into
getsentry:mainfrom
Crucialjun:kgp_warning

Conversation

@Crucialjun

Copy link
Copy Markdown

fix(flutter): Stop tripping Flutter's built-in Kotlin (KGP) warning on Android

📜 Description

Apps on recent Flutter versions that depend on sentry_flutter see this on every Android build:

WARNING: Your app uses the following plugins that apply Kotlin Gradle Plugin (KGP): sentry_flutter
Future versions of Flutter will fail to build if your app uses plugins that apply KGP.

This PR migrates packages/flutter/android to AGP 9's built-in Kotlin so the warning goes away, while keeping support for apps still on AGP < 9.

The key detail is how Flutter detects this. It does not inspect the build at runtime — it runs a regex over the plugin's build script source text (FlutterPluginUtils.getSubprojectPluginState), and says so explicitly:

This inspects build script files directly via regex rather than querying Gradle plugin state at runtime. Evaluating Kotlin Gradle Plugin dynamically at runtime to conditionally apply Kotlin Gradle Plugin during configuration leads to lifecycle and ordering issues (see gradle/gradle#36953).

That has a consequence worth calling out: a runtime guard is not enough. Any Groovy build file containing a line that starts with apply plugin: 'kotlin-android' is flagged, even when that line is unreachable. Flutter's Kotlin DSL regex, by contrast, only matches KGP inside a plugins {} block and deliberately ignores apply(plugin = ...) — which is exactly the conditional shape Flutter's own plugin author migration guide recommends for plugins that still support older AGP.

So packages/flutter/android/build.gradle is converted to build.gradle.kts:

val agpMajor = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.substringBefore('.').toInt()
val builtInKotlin = agpMajor >= 9 && project.findProperty("android.builtInKotlin") != "false"

if (!builtInKotlin) {
    apply(plugin = "org.jetbrains.kotlin.android")
}

android.builtInKotlin is honored alongside the AGP version, because that flag lets a consuming app opt back out of built-in Kotlin (Flutter's own migrator adds it).

Other changes in the Kotlin DSL port:

  • jvmTarget is set via KGP 2.x's compilerOptions DSL, with a reflection-based fallback to kotlinOptions for KGP 1.8.x (still shipped by Flutter 3.24-era apps and used by min_version_test). The fallback uses reflection specifically so it cannot fail to compile or throw against a KGP whose types differ from those the script was compiled against.
  • The explicit src/main/kotlin srcDir is dropped — both the standalone Kotlin plugin and AGP 9's built-in Kotlin register it by convention.
  • targetSdkVersion is dropped from the library's defaultConfig; it has no effect on an AAR and is deprecated for libraries.

Android toolchain updates

Plugin (packages/flutter/android):

Before After
Gradle 7.6.6 9.5.0
AGP 7.4.2 9.3.2
Kotlin 2.2.20 2.3.10
compileSdk / targetSdk 36 37

The example app is brought in line (Gradle 8.14.3 → 9.5.0, AGP 8.11.1 → 9.3.2, KGP 2.2.20 → 2.3.10, SDK 36 → 37). The KOTLIN_ANDROID_PLUGIN_VERSION / ANDROID_GRADLE_PLUGIN_VERSION env overrides are untouched, so the kotlin-version-compatibility matrix still drives both KGP versions.

AGP 9 needed five further fixes in the example, each a hard error rather than a warning:

  • android.enableR8=true removed from gradle.properties (removed in AGP 7; true was already the default, so this is behavior-neutral).
  • getDefaultProguardFile('proguard-android.txt')'proguard-android-optimize.txt'; AGP 9 rejects the non-optimizing file. This does enable R8 optimizations for the example's release build.
  • Kotlin language version default 1.82.3; KGP 2.3.10 dropped language version 1.8 outright.
  • android:extractNativeLibs="true" moved out of AndroidManifest.xml into packagingOptions.jniLibs.useLegacyPackaging = true. AGP 9 only accepts it from the build script; the behavior is preserved because sentry-native's crash handler relies on it.
  • io.sentry:sentry-native-ndk pinned to 0.16.2. AGP 9 resolves Prefab from the compile classpath, but the transitive copy is runtime-scoped in sentry-android-ndk's POM, so the previous versionless declaration resolved to sentry-native-ndk: with an empty version. Removing the direct declaration instead is not an option — find_package(sentry-native-ndk REQUIRED CONFIG) then fails.

The example's package_info_plus moves ^4.0.0^10.0.0: 4.2.0 hardcodes compileSdkVersion 33, which AGP 9's AAR metadata check rejects against modern AndroidX, and its own Kotlin source does not compile against API 34+. The SDK's own constraint is >=1.0.0, so only the example moves; min_version_test keeps its deliberate 8.3.1 pin.

JNI bindings regenerated for jni 1.x

jni 0.14.2 → ^1.0.3 and jnigen 0.14.2 → ^0.17.0, with binding.dart regenerated. jnigen 0.17 emits extension types instead of classes and turns Java getX()/setX()/isX() pairs into Dart properties, so all call sites were updated (opts.setDsn(x)opts.dsn = x, opts.isDebug()opts.isDebug). Other jni 1.x API changes handled: JList.array/JMap.hashJArrayList/JHashMap; JList/JMap/JSet no longer implement Dart's collection types, so []/.length/.map go through .asDart(); JByteArray.from.of; releaseOriginal: dropped from the boxed-primitive accessors.

💡 Motivation and Context

Flutter has announced that future versions will fail to build when an app depends on a plugin that applies KGP, so this is a forward-compatibility fix, not just noise reduction. Every app using sentry_flutter currently prints the warning on each Android build and is pointed at us to fix it.

The AGP 9 / Gradle 9.5 toolchain bump is a prerequisite: built-in Kotlin only exists on AGP 9+.

💚 How did you test it?

Verified locally on Windows with the example app (packages/flutter/example):

  • The warning is gone. Confirmed by a full flutter clean + flutter build apk --debug on the converted build.gradle.kts — zero occurrences of the KGP warning in the build log, where the same build on the previous Groovy file printed it.
  • Diagnosis confirmed independently: on the Groovy file, KGP was genuinely not applied to :sentry_flutter at runtime (AGP 9, built-in Kotlin active) and Flutter still warned — proving detection is source-text only. Collapsing the guard onto one line made the warning vanish with no behavioral change, isolating the regex as the sole cause.
  • flutter build apk --debug --target-platform=android-x64 — passes (clean and incremental).
  • flutter build apk --release --target-platform=android-arm64 — passes, exercising R8 with the changed ProGuard file (13.9 MB APK).
  • kotlin-version-compatibility low-end combo (KOTLIN_ANDROID_PLUGIN_VERSION=2.2.20, KOTLIN_LANGUAGE_VERSION=1.8) against AGP 9.3.2 — passes, so that workflow is not broken by the new defaults.
  • jvmTarget is genuinely applied: compiled SentryFlutterPlugin.class has class-file major version 52 (Java 8).
  • dart analyze clean across packages/flutter and packages/flutter/example (was 3175 issues mid-migration).
  • flutter test in packages/flutter: 1081 passing. The 5 failures in test/sentry_native/sentry_native_test.dart are cmake not being on PATH in my environment, unrelated to these changes.

Not verified locally — please confirm in CI: min_version_test (Gradle 8.2 / AGP 8.1.4 / Kotlin 1.8.0). It caps at JDK 20 and this machine only has JDK 21/25/26, so the kotlinOptions reflection fallback and the apply(plugin = ...) branch under AGP 8 were not exercised end-to-end. The AGP < 9 apply(plugin = ...) path was exercised on AGP 9 via android.builtInKotlin=false, and the KGP 2.x compilerOptions path was exercised on both KGP 2.2.20 and 2.3.10.

📝 Checklist

  • I reviewed submitted code
  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPii is enabled
  • I updated the docs if needed
  • All tests passing
  • Public API changes reviewed by another Mobile SDK team member or implemented according to the develop docs spec
  • No breaking changes

Notes on the unchecked boxes:

  • Tests: no new automated test covers the KGP warning; it is a build-log assertion rather than something the Dart test suite can reach. A CI grep for the warning string in the example's build output would lock this in — happy to add it if you want it.
  • Breaking changes: the minimum supported AGP for consumers is effectively raised by the plugin's own Gradle/AGP bump, and the example's package_info_plus major bump may warrant a changelog note. Both need a maintainer's call on the compatibility policy.
  • Public API: no Dart public API changes, but binding.dart is regenerated wholesale, so the Java-facing internal surface changed shape.

🔮 Next steps

  • Confirm min_version_test and the full kotlin-version-compatibility matrix pass in CI.
  • binding.dart carries four hand-edits that regeneration will silently drop. jnigen 0.17.0 emits a nullable getter beside a non-null setter wherever sentry-java annotates only the setter parameter @NotNull, which is a Dart compile-time error (// ignore does not help — confirmed with dart compile kernel). Four setters were widened to accept null: SentryAndroidOptions.beforeScreenshotCaptureCallback, SentryAndroidOptions.beforeViewHierarchyCaptureCallback, SentryOptions.gestureTargetLocators, SentryEvent.timestamp. Worth an upstream jnigen issue.
  • Flutter now warns that KGP 2.3.10 is below its upcoming minimum of 2.3.20 — a follow-up bump.
  • Flutter's Groovy vs Kotlin KGP regex asymmetry (a conditional apply is flagged in Groovy but not in Kotlin DSL) is arguably a Flutter bug and may be worth reporting upstream.
  • The example still pins NDK 27.2.12479018 while jni 1.x wants 28.2.13676358; Flutter warns but the build succeeds. Bumping it would also make the -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON r27 workaround redundant.

- Updated SentryNativeJava class to use new native methods for display refresh rate and replay ID.
- Refactored dartToJObject, dartToJList, dartToJStringList, and dartToJMap functions for improved type handling.
- Enhanced initSentryAndroid function to utilize new native methods for application context and options configuration.
- Updated session replay configuration to use new properties and methods.
- Changed jni and jnigen dependencies to newer versions in pubspec.yaml.
- Added exclusion patterns for analysis in isar and sqflite packages.
- Updated melos version in the root pubspec.yaml.
- Introduced gradle-daemon-jvm.properties for toolchain configuration.
- Fixed comment in utf8_json_test.dart for clarity.
Copilot AI lite review requested due to automatic review settings August 25, 2026 11:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a2e8d9e. Configure here.

}
}

val kotlinVersion = "2.3.10"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Buildscript pins break older AGP

High Severity

The plugin buildscript now hardcodes AGP 9.3.2 and KGP 2.3.10, and still applys that KGP whenever built-in Kotlin is off. AGP 9.3 requires Gradle 9.5, while min_version_test stays on Gradle 8.2 / AGP 8.1.4 / Kotlin 1.8.0. That path is the PR’s claimed AGP < 9 support, but it was not verified and is likely to fail or load mismatched Kotlin plugins for older consumers.

Additional Locations (2)
Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot (Root)

Reviewed by Cursor Bugbot for commit a2e8d9e. Configure here.

@buenaflor

Copy link
Copy Markdown
Contributor

KGP 9 support has already been merged, it will be part of the next release

@buenaflor buenaflor closed this Aug 26, 2026
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.

3 participants