Skip to content

fix(screen_state): restore compatibility with AGP < 9 and Dart 3.10.0#1301

Open
Zeroupper wants to merge 1 commit into
masterfrom
fix/screen-state-agp8-sdk-bound
Open

fix(screen_state): restore compatibility with AGP < 9 and Dart 3.10.0#1301
Zeroupper wants to merge 1 commit into
masterfrom
fix/screen-state-agp8-sdk-bound

Conversation

@Zeroupper

Copy link
Copy Markdown

Problem

screen_state 5.0.1 (#regenerated from the Flutter 3.44 plugin template) broke two things for consuming apps:

  1. Apps on AGP < 9 fail to build. The new build.gradle.kts pins AGP 9.0.1/Kotlin 2.3.20 on the buildscript classpath and relies on AGP 9 built-in Kotlin (kotlin {} with no Kotlin plugin applied). Any app whose android/ project uses AGP 8.x gets script compilation errors (srcDirs ... deprecated, Unresolved reference: kotlin).
  2. Dart SDK bound ^3.12.2 blocks Flutter 3.44.0/3.44.1 users. The patch-level pin is a template stamp, not a real requirement.

Fix

  • Apply the Kotlin Gradle plugin conditionally when the host app's AGP is < 9, exactly as documented in the built-in Kotlin migration guide for plugin authors, and remove the pinned buildscript toolchain so the consuming app supplies AGP/Kotlin.
  • Relax the SDK bound to >=3.12.0 <4.0.0 (also in the example app).
  • Convert ScreenReceiver.javaScreenReceiver.kt. The Java file lived in src/main/kotlin and was only compiled because of the old sourceSets override; without that override apps crash at runtime with NoClassDefFoundError: dk.cachet.screen_state.ScreenReceiver when the stream is first listened to.

Verification

  • Clean flutter build apk --debug of a consuming app on Flutter 3.38.1 / AGP 8.11.1 and of the bundled example on Flutter 3.44.0 / AGP 9.0.1.
  • dexdump confirms class definitions for both ScreenStatePlugin and ScreenReceiver in both APKs.
  • Runtime-tested via CARP Mobile Sensing's example app (screen probe) on a physical device (SM-S926B, Android 16).

The 5.0.1 release regenerated the Android build script from the
Flutter 3.44 plugin template, which pins AGP 9.0.1/Kotlin 2.3.20 on
the buildscript classpath and assumes AGP 9 built-in Kotlin. This
broke the Android build for every consuming app on AGP 8.x.

- Apply the Kotlin Gradle plugin conditionally (AGP < 9) per the
  Flutter built-in Kotlin migration guide, and drop the pinned
  buildscript toolchain so the consuming app supplies it.
- Relax the Dart SDK lower bound from ^3.12.2 to >=3.12.0; the
  patch-level pin was a template stamp and blocked Flutter 3.44.0.
- Convert ScreenReceiver.java (living in src/main/kotlin) to Kotlin.
  It was only compiled thanks to a sourceSets override; without it
  apps crash with NoClassDefFoundError at runtime.

Verified: clean debug builds and dex contents on Flutter 3.38.1
(AGP 8.11) and Flutter 3.44.0 (AGP 9.0.1) host apps.
@Zeroupper
Zeroupper requested a review from iarata July 14, 2026 12:17
@iarata

iarata commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@Zeroupper can't you update your project's AGP to 9 or higher? soon the < 9 AGP will be deprecated and we have to re-update it again. it would make sense to update your projects AGP. Also why did you remove the buildscript?

@Zeroupper

Copy link
Copy Markdown
Author

@Zeroupper can't you update your project's AGP to 9 or higher? soon the < 9 AGP will be deprecated and we have to re-update it again. it would make sense to update your projects AGP. Also why did you remove the buildscript?

The buildscript {} block is Gradle's old way of saying "here are the jars needed to run this build script" — it downloads the listed plugins (AGP 9.0.1, Kotlin 2.3.20) and puts them on the script's classpath before the script executes.

The reason it had to go is where this script actually runs. A Flutter plugin's android/ project is never built by itself — Flutter injects it as a subproject into each consuming app's Gradle build, and the app's settings.gradle.kts already decides which AGP and Kotlin versions the whole build uses. So the block does one of two things, both bad:

  1. In an app on AGP 8.x (your CAMS example): the app's build runs AGP 8.11, but the block shoves AGP 9.0.1 jars onto this one script's classpath. The script then gets compiled against AGP 9's API while the plugin actually applied is AGP 8.11. That mismatch produced your exact original errors — 'srcDirs' is deprecated. Use 'directories' is an AGP 9-only error-level deprecation, and the DSL confusion around kotlin {} came from the same split-brain classpath. This wasn't a bystander; it was the cause.
  2. In an app on AGP 9 (matching versions): it's redundant. The plugins { id("com.android.library") } block resolves from the host build anyway; the pinned classpath contributes nothing.

The one scenario where a buildscript block earns its keep is a standalone build of the plugin's android/ folder — its own ./gradlew, its own toolchain. That scenario doesn't exist for screen_state: no wrapper, a one-line settings.gradle.kts, no CI job. It's embedded-only, and embedded means the host provides the toolchain.

--- That's on why the buildscipt got removed. 2nd part of the problem is that I don't think it's a good idea to be overrestrictive on AGP version. I added conditional AGP support for 8 based on the documentation. My goal was to not overrestrict dart version if there is an option.

@Zeroupper

Zeroupper commented Jul 14, 2026

Copy link
Copy Markdown
Author

The whole issue started from being unable to run CAMS/example with Flutter 3.44.0.

@Zeroupper Zeroupper changed the title fix(screen_state): restore compatibility with AGP < 9 and Dart 3.12.0 fix(screen_state): restore compatibility with AGP < 9 and Dart 3.10.0 Jul 14, 2026
@iarata

iarata commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@Zeroupper well then can't you update the cams example to be compatible with the new version? instead of downgrading things it depends on

@Zeroupper

Zeroupper commented Jul 15, 2026

Copy link
Copy Markdown
Author

@Zeroupper well then can't you update the cams example to be compatible with the new version? instead of downgrading things it depends on

I didn't downgrade anything, I only added support for older versions. You can't expect everyone to be on the latest dart sdk version, at least support the version that can still run your dependencies.

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