diff --git a/src/serious_python_android/CHANGELOG.md b/src/serious_python_android/CHANGELOG.md index 54eafbf5..c8c6a99c 100644 --- a/src/serious_python_android/CHANGELOG.md +++ b/src/serious_python_android/CHANGELOG.md @@ -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. diff --git a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java index bb9c636b..238401af 100644 --- a/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java +++ b/src/serious_python_android/android/src/main/java/com/flet/serious_python_android/AndroidPlugin.java @@ -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);