Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/serious_python_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Unreleased

* Fix app crashing on launch on Android 8.1 and below (API < 28). The `getAppVersion` method-channel handler, called on every startup, used `PackageInfo.getLongVersionCode()` (API 28+) unconditionally. R8 outlines this call into a synthetic class that it can merge with other API 28+ outlines — notably Flutter 3.41's `ImageDecoder`-based image decoder — and invoking that merged class on API < 28 fails verification with `NoClassDefFoundError: android.graphics.ImageDecoder$OnHeaderDecodedListener`. The call is now guarded with a `Build.VERSION.SDK_INT` check, falling back to the deprecated `versionCode` int field on older devices.

## 4.1.0

* Run the `extractAsset` / `unzipAsset` / `loadLibrary` method-channel handlers on a background `Executor` (posting the `Result` back on the main looper) instead of inline on the platform main thread. The first-launch asset unpack and the pyjnius native-library load no longer block Android's `Choreographer`, so Flutter's vsync isn't starved and on-screen animations (e.g. a boot/splash spinner) stay smooth while the app starts.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,16 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
android.content.pm.PackageManager pm = context.getPackageManager();
android.content.pm.PackageInfo info = pm.getPackageInfo(packageName, 0);
String versionName = info.versionName;
long versionCode = info.getLongVersionCode();
// PackageInfo.getLongVersionCode() is API 28+. Calling it unconditionally
// makes the Android Gradle plugin (R8) outline the call into a synthetic
// class that it may merge with other API 28+ outlines (e.g. Flutter's
// ImageDecoder-based image decoder). Invoking that merged class on
// API < 28 fails verification with NoClassDefFoundError and crashes the
// app on launch, because getAppVersion runs on every startup. Guard the
// call so older devices use the deprecated int field instead.
long versionCode = (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P)
? info.getLongVersionCode()
: (long) info.versionCode;
result.success(versionName + "+" + versionCode);
} catch (Exception e) {
result.error("Error", e.getMessage(), null);
Expand Down
Loading