Skip to content

[shared_preferences] Keep Kotlin classes used through JNI in Android release builds - #13311

Merged
auto-submit[bot] merged 4 commits into
flutter:mainfrom
ybeshkarov:fix-release-r8-kotlin-keep-rules
Oct 21, 2026
Merged

auto-submit[bot] merged 4 commits into
flutter:mainfrom
ybeshkarov:fix-release-r8-kotlin-keep-rules

Conversation

@ybeshkarov

@ybeshkarov ybeshkarov commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

shared_preferences_android 2.5.0 calls its Kotlin code through JNI. The generated Dart bindings and package:jni look up some Kotlin standard library classes by name, but nothing keeps them, so R8 renames them in release builds. From mapping.txt of a release build with 2.5.0:

kotlin.Result -> l1.d:
kotlin.Result$Failure -> l1.c:
kotlin.Unit -> l1.g:
kotlin.coroutines.Continuation -> o1.d:
kotlin.coroutines.intrinsics.CoroutineSingletons -> p1.a:

The generated classes are kept by @Keep, but R8 rewrites their method descriptors with the renamed Continuation. So every call fails with a NoSuchMethodError, for example:

NoSuchMethodError: no non-static method "Lio/flutter/plugins/sharedpreferences/SharedPreferencesAsyncApiRegistrar;.getAll(Ljava/util/List;Lio/flutter/plugins/sharedpreferences/SharedPreferencesPigeonOptions;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;"

and SharedPreferences.getInstance(), SharedPreferencesAsync and SharedPreferencesWithCache.create() all throw. Debug and profile builds work.

This PR adds android/consumer-rules.pro with the six keep rules from Pigeon's native interop guide ("Step 5: Android Release Build Configuration (JNI)") and lists it in consumerProguardFiles, the same way packages/pigeon/platform_tests/test_plugin does. R8 then applies the rules to every app that uses the plugin. The six classes are the ones looked up by name: kotlin.coroutines.Continuation in the descriptors of the suspend methods and kotlin.Unit in messages*.g.dart, plus kotlin.Unit, kotlin.Result, kotlin.Result$Failure, kotlin.coroutines.Continuation, CoroutineSingletons and IntrinsicsKt in lib/src/kotlin.dart of jni 1.1.0. The other Kotlin types in the bindings (DefaultConstructorMarker, EnumEntries) only appear in synthetic constructors and getEntries, which the plugin never calls. A TODO in consumer-rules.pro and build.gradle.kts points to dart-lang/native#3732, so the rules can be removed once jni ships them.

Fixes flutter/flutter#194649

How I verified it: a fresh flutter create --platforms android app with shared_preferences: ^2.5.5 that calls SharedPreferencesWithCache.create() in main() and counts launches. I built it with flutter build apk --release --target-platform android-arm64 (Flutter 3.44.2, AGP 9.0.1, Gradle 9.1.0, R8 on by default) and ran it on an API 37 arm64 emulator.

  • With shared_preferences_android 2.5.0 from pub.dev, the app stays on the splash screen and logcat shows the NoSuchMethodError above from SharedPreferencesWithCache.create.
  • With a dependency_overrides path to this branch, configuration.txt of the build lists the rules from the plugin's consumer file, mapping.txt maps each class to itself (for example kotlin.coroutines.Continuation -> kotlin.coroutines.Continuation:), and the app starts. It logs launches=1, and launches=2 after a restart.
  • A second entry point that round-trips every value type, getKeys, getAll, remove and clear through SharedPreferencesAsync and the legacy SharedPreferences API fails for both APIs with 2.5.0 and passes for both with this branch.

I also ran flutter test in the package (39 tests pass) and validate --check-for-missing-changes, analyze, format, dart-test, publish-check and license-check of the repo tooling for the package. None of them reported an issue.

Test exemption: I'd like to request one. The change is build configuration that only affects R8 in an app's release build, and as far as I can tell no CI target runs a release build of a plugin. drive-examples, the native integration tests and Firebase Test Lab use debug builds, and android_build_all_packages builds the all_packages app in release but doesn't run it. If there is a place where a release-mode test would fit, I'm happy to add one.

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2

…builds

shared_preferences_android 2.5.0 calls its Kotlin code through JNI. The
generated Dart bindings and package:jni look up several Kotlin standard
library classes by name, such as kotlin.coroutines.Continuation. R8 renames
them in release builds, so every call fails with a NoSuchMethodError and
SharedPreferences.getInstance() and SharedPreferencesWithCache.create()
throw at startup.

Adds consumer R8 rules that keep those classes, as Pigeon's native interop
guide describes for plugins, until package:jni ships them
(dart-lang/native#3732).
@google-cla

google-cla Bot commented Oct 17, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@ybeshkarov
ybeshkarov marked this pull request as ready for review October 17, 2026 20:28
@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If both you and the PR author believe this PR qualifies for a test exemption, escalate to the tech lead for the changed area to review and apply the test-exempt label. All reviewers should feel empowered to ask for tests before escalating.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request updates the shared_preferences_android package to version 2.5.1. It introduces a consumer-rules.pro file with Proguard/R8 keep rules for specific Kotlin classes, including kotlin.Unit, kotlin.Result, and coroutine-related classes, to prevent them from being stripped or renamed in release builds. It also configures build.gradle.kts to apply these consumer Proguard files, and updates pubspec.yaml and CHANGELOG.md accordingly. There are no review comments, and I have no feedback to provide.

toazd added a commit to toazd/selah that referenced this pull request Oct 18, 2026
…n integrated into the package yet (flutter/packages#13311). Without this patch, the R8 obfuscates methods and the app throws "NoSuchMethod" errors on startup which hang the app because the calls are awaited (even if it did bypass the wait, the shared preferences wouldn't work correctly anyway).
aautonomicc added a commit to aautonomicc/Watch-It that referenced this pull request Oct 19, 2026
… JNI Kotlin classes, verifier refuses renamed ones

alpha.125's pub wave took shared_preferences_android to 2.5.0, whose Pigeon
JNI bindings resolve kotlin.coroutines.Continuation/Unit/Result by name. R8
renamed them in the release APK, the first prefs read before runApp threw
NoSuchMethodError, and the app never left the Android splash.

- pubspec: shared_preferences_android '>=2.4.28 <2.5.0' (pre-JNI impl)
- android/app/proguard-rules.pro keeps the six JNI-resolved classes
- verify_android_apk.py: inspect_dex_keeps refuses an APK where any of
  the three was renamed (+3 tests); receipt gains kept_jni_classes
- CLAUDE.md: root cause + verification record

Upstream: flutter/flutter#194649, flutter/packages#13311.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
…in-keep-rules

# Conflicts:
#	packages/shared_preferences/shared_preferences_android/CHANGELOG.md

@mboetger mboetger 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.

LGTM aside from todo update

@mboetger
mboetger requested a review from camsim99 October 20, 2026 16:59
@ybeshkarov
ybeshkarov requested a review from mboetger October 20, 2026 18:07
@tarrinneal tarrinneal added the CICD Run CI/CD label Oct 20, 2026

@tarrinneal tarrinneal 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.

Thank you for throwing this together so quickly

@tarrinneal tarrinneal added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 20, 2026
@auto-submit auto-submit Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 20, 2026
@auto-submit

auto-submit Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

autosubmit label was removed for flutter/packages/13311, because - This pull request has the missing-tests label and does not have the test-exempt label. Please add tests or obtain a test exemption from a tech lead before re-applying the autosubmit label.

@ybeshkarov

ybeshkarov commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor Author

@tarrinneal, @mboetger thanks for the approval! Looks like the bot pulled autosubmit over missing-tests. Could you ask a tech lead for test-exempt? The reasoning is in the description: the rules only matter in release builds, and CI never runs a plugin in release. If you'd rather have a test, just point me to a spot and I'll add one.

@mboetger mboetger added test-exempt Exempt from tests. Overrides `missing-tests` label autosubmit Merge PR when tree becomes green via auto submit App labels Oct 20, 2026
@auto-submit
auto-submit Bot merged commit 1383427 into flutter:main Oct 21, 2026
13 checks passed
@ybeshkarov

Copy link
Copy Markdown
Contributor Author

@tarrinneal @mboetger thanks for merging! The release run for the merge commit failed at "Wait for test check-in", since the LUCI check it waits for didn't show up within 60 seconds (https://github.com/flutter/packages/actions/runs/39526055358). So 2.5.2 isn't on pub.dev yet. Could one of you re-run it once post-submit has run?

ValentinVignal pushed a commit to ValentinVignal/flutter that referenced this pull request Oct 21, 2026
flutter/packages@618afba...1383427

2026-10-21 [email protected] [shared_preferences] Keep Kotlin
classes used through JNI in Android release builds
(flutter/packages#13311)
2026-10-20 [email protected] [webview_flutter_wkwebview] Roll back iOS
and macOS versions (flutter/packages#13354)
2026-10-20 [email protected] [camera]fix
resolution test failure due to hardware restriction
(flutter/packages#13356)
2026-10-20 [email protected] [google_maps_flutter_web] Fail fast and
deduplicate map setup in integration tests (flutter/packages#13092)
2026-10-20 [email protected] [camera_avfoundation] Fix Swift analyzer
issues in tests (flutter/packages#13340)
2026-10-20 [email protected] Sync release-material_ui-1.8.0 to
main (flutter/packages#13346)
2026-10-20 [email protected] [material_ui] add a `barFocusNode` to
`SearchAnchor.bar` (ref: flutter#186073)
(flutter/packages#12863)
2026-10-20 [email protected] [in_app_purchase_storekit] Expose
sk2Transaction on SK2PurchaseDetails (flutter/packages#13341)
2026-10-20 [email protected] Sync release-cupertino_ui-1.1.4 to
main (flutter/packages#13350)
2026-10-20 [email protected] [google_maps_flutter_web] Don't hang
`onMapCreated` when tiles fail to load (flutter/packages#13059)
2026-10-20 [email protected] [material_ui]
Unskip web tests that pass on CanvasKit and Skwasm:
adaptive_text_selection_toolbar_test, material_button_test,
outlined_button_test, text_button_test (flutter/packages#13335)
2026-10-20 [email protected] Sync release-go_router-18.1.1 to
main (flutter/packages#13347)
2026-10-20 [email protected] [camera] Add zero-shutter-lag support
to camera_android_camerax and camera_avfoundation
(flutter/packages#13199)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected] on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
MateoTVara added a commit to MateoTVara/sched_scan that referenced this pull request Oct 21, 2026
2.5.0 (resolved into the lockfile on 2026-10-17) moved to Pigeon JNI
interop, and R8 renames the kotlin.coroutines classes it calls, so
SharedPreferences.getInstance() in main() throws NoSuchMethodError
before runApp() ever renders — the release APK hangs on the splash
screen while debug builds work (flutter/flutter#194649, upstream fix
flutter/packages#13311). Pin until a fixed version ships, then drop
the constraint. The jni FFI plugin leaves the generated plugin lists
with the older version.
LongCatIsLooong pushed a commit to LongCatIsLooong/flutter that referenced this pull request Oct 22, 2026
flutter/packages@618afba...1383427

2026-10-21 [email protected] [shared_preferences] Keep Kotlin
classes used through JNI in Android release builds
(flutter/packages#13311)
2026-10-20 [email protected] [webview_flutter_wkwebview] Roll back iOS
and macOS versions (flutter/packages#13354)
2026-10-20 [email protected] [camera]fix
resolution test failure due to hardware restriction
(flutter/packages#13356)
2026-10-20 [email protected] [google_maps_flutter_web] Fail fast and
deduplicate map setup in integration tests (flutter/packages#13092)
2026-10-20 [email protected] [camera_avfoundation] Fix Swift analyzer
issues in tests (flutter/packages#13340)
2026-10-20 [email protected] Sync release-material_ui-1.8.0 to
main (flutter/packages#13346)
2026-10-20 [email protected] [material_ui] add a `barFocusNode` to
`SearchAnchor.bar` (ref: flutter#186073)
(flutter/packages#12863)
2026-10-20 [email protected] [in_app_purchase_storekit] Expose
sk2Transaction on SK2PurchaseDetails (flutter/packages#13341)
2026-10-20 [email protected] Sync release-cupertino_ui-1.1.4 to
main (flutter/packages#13350)
2026-10-20 [email protected] [google_maps_flutter_web] Don't hang
`onMapCreated` when tiles fail to load (flutter/packages#13059)
2026-10-20 [email protected] [material_ui]
Unskip web tests that pass on CanvasKit and Skwasm:
adaptive_text_selection_toolbar_test, material_button_test,
outlined_button_test, text_button_test (flutter/packages#13335)
2026-10-20 [email protected] Sync release-go_router-18.1.1 to
main (flutter/packages#13347)
2026-10-20 [email protected] [camera] Add zero-shutter-lag support
to camera_android_camerax and camera_avfoundation
(flutter/packages#13199)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected] on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
@ybeshkarov
ybeshkarov deleted the fix-release-r8-kotlin-keep-rules branch October 22, 2026 14:32
suryaKommana2662 pushed a commit to suryaKommana2662/flutter that referenced this pull request Oct 29, 2026
flutter/packages@618afba...1383427

2026-10-21 [email protected] [shared_preferences] Keep Kotlin
classes used through JNI in Android release builds
(flutter/packages#13311)
2026-10-20 [email protected] [webview_flutter_wkwebview] Roll back iOS
and macOS versions (flutter/packages#13354)
2026-10-20 [email protected] [camera]fix
resolution test failure due to hardware restriction
(flutter/packages#13356)
2026-10-20 [email protected] [google_maps_flutter_web] Fail fast and
deduplicate map setup in integration tests (flutter/packages#13092)
2026-10-20 [email protected] [camera_avfoundation] Fix Swift analyzer
issues in tests (flutter/packages#13340)
2026-10-20 [email protected] Sync release-material_ui-1.8.0 to
main (flutter/packages#13346)
2026-10-20 [email protected] [material_ui] add a `barFocusNode` to
`SearchAnchor.bar` (ref: flutter#186073)
(flutter/packages#12863)
2026-10-20 [email protected] [in_app_purchase_storekit] Expose
sk2Transaction on SK2PurchaseDetails (flutter/packages#13341)
2026-10-20 [email protected] Sync release-cupertino_ui-1.1.4 to
main (flutter/packages#13350)
2026-10-20 [email protected] [google_maps_flutter_web] Don't hang
`onMapCreated` when tiles fail to load (flutter/packages#13059)
2026-10-20 [email protected] [material_ui]
Unskip web tests that pass on CanvasKit and Skwasm:
adaptive_text_selection_toolbar_test, material_button_test,
outlined_button_test, text_button_test (flutter/packages#13335)
2026-10-20 [email protected] Sync release-go_router-18.1.1 to
main (flutter/packages#13347)
2026-10-20 [email protected] [camera] Add zero-shutter-lag support
to camera_android_camerax and camera_avfoundation
(flutter/packages#13199)

If this roll has caused a breakage, revert this CL and set the roller
to dry run mode using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC [email protected] on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD missing-tests p: shared_preferences platform-android test-exempt Exempt from tests. Overrides `missing-tests` label

Projects

None yet

3 participants