Repository navigation
Description
Found while investigating #193195.
Summary
Flutter's Gradle plugin enables R8 for Android release builds by default. R8 renames or removes classes that pigeon's JNI native interop looks up by name, so most native interop calls fail in a default release build. Debug and profile builds aren't affected, which makes this easy to miss until shipping.
Steps to reproduce
- Generate a pigeon file with
kotlin_use_jni(for example pigeon's ownpigeons/native_interop_tests.dart). - Build the app in release mode with default settings (
flutter build apk --releaseorflutter run --release). - Call native interop methods that take or return a data class or an enum, are
@async, throw an error, or go through a FlutterApi.
Expected results
All calls behave as in debug builds.
Actual results
In a release build of pigeon's test plugin, 15 of 25 probe calls fail with ClassNotFoundException.
- Pass:
getInstance,noop, and echoes ofint,double,bool,String,Uint8List,List,List<int>andMap. - Fail: everything that touches an enum, a data class, an async method, an error, or the FlutterApi.
- 14 of the 15 failures name the generated error class instead of the class that actually went missing. The generated error handling looks the error class up by name too, and that lookup fails first, which hides the original failure.
Cause
mapping.txt from the release build shows R8:
- renamed the data classes and enums (for example
NativeInteropAllTypes→eg); - removed the FlutterApi interface and its Registrar;
- inlined the generated error class away;
- renamed
kotlin.Unit,kotlin.Result,kotlin.Result$Failure,kotlin.coroutines.Continuationandkotlin.coroutines.intrinsics.CoroutineSingletons, whichpackage:jniand the generated Dart look up by name.
Only @Keep classes survived intact. The generated Kotlin has exactly three @Keep annotations: the HostApi interface (L1005), its Registrar (L1625) and getInstance (L1642). package:jni's consumer rules keep only its own package.
Re-running with the generated classes kept, plus six Kotlin classes (the five above and kotlin.coroutines.intrinsics.IntrinsicsKt), made all 25 calls pass. A macOS release build using FFI also passed all 25.
Workaround
Add keep rules to the plugin's consumer ProGuard file (wired up with consumerProguardFiles in the plugin's build.gradle), so that apps pick them up automatically. Replace the first rule with the package of your generated Kotlin file, or list the generated classes one by one:
# Classes generated by pigeon with kotlin_use_jni.
-keep class com.example.my_plugin.** { *; }
# Kotlin classes that package:jni and the generated Dart look up by name.
-keep class kotlin.Unit { *; }
-keep class kotlin.Result { *; }
-keep class kotlin.Result$Failure { *; }
-keep class kotlin.coroutines.Continuation { *; }
-keep class kotlin.coroutines.intrinsics.CoroutineSingletons { *; }
-keep class kotlin.coroutines.intrinsics.IntrinsicsKt { *; }
Proposed fix
- Pigeon: add
@Keepto every generated type that JNI reaches by name: data classes, enums, the FlutterApi interface and its Registrar, and the error class. A partial fix that keeps only the error class is in progress. It makes the real failures visible, but doesn't fix them on its own. package:jni: ship consumer rules for the Kotlin classes it looks up by name. This needs an upstream issue in dart-lang/native. Until it lands, pigeon's docs should list the rules above.- CI: run pigeon's native interop integration tests against a minified release build, so regressions show up before release.
Environment
pigeon 29.0.6, package:jni 1.1.0, jnigen 1.0.1, Flutter 3.49.0-1.0.pre-194, JDK 17, arm64 Android emulator (Pixel 9 Pro image).
Activity
tarrinneal commentedon Oct 6, 2026
related dart-lang/native#3732
[pigeon] Fix native interop (JNI) calls in minified Android release b…
github-actions commentedon Oct 21, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.