Android: smoother boot (off-main-thread native work) + release pyjnius fix; bump to 4.1.0#217
Merged
Conversation
extractAsset/unzipAsset ran synchronously on the Android platform main thread, blocking Choreographer and starving Flutter's vsync — which froze on-screen animations (e.g. the boot spinner) during app unpacking on first launch. Run those two handlers on a background single-thread Executor and post the MethodChannel Result back on the main looper. loadLibrary stays on the main thread on purpose: pyjnius's JNI_OnLoad relies on running there, and loading it off-thread breaks pyjnius (verified).
In release builds the consuming app's R8 pass obfuscated/stripped the plugin's classes, breaking pyjnius: PythonActivity was renamed (e.g. to "C.f") and its static `mActivity` field dropped, so pyjnius failed with "type object 'C.f' has no attribute 'mActivity'". Debug builds (no minify) were unaffected. Ship consumer ProGuard rules (-keep com.flet.serious_python_android.**) and wire them via consumerProguardFiles, so they're merged into the consuming app's R8 pass automatically.
Now that release builds keep the pyjnius bootstrap classes (consumer ProGuard rules), loadLibrary can move off the main thread too — the earlier pyjnius breakage was R8 obfuscation, not the threading. System.loadLibrary resolves the .so via the caller class's loader (AndroidPlugin -> app loader) and JNI_OnLoad's FindClass uses that same loader regardless of thread; the worker's context ClassLoader is pinned to the app loader as well. Verified with pyjnius in release. This keeps the dlopen + JNI_OnLoad off Choreographer's thread, so the boot spinner stays smooth during native library loading.
Update .fvmrc to reference Flutter 3.44.3 (was 3.44.2). This patches the project SDK to the latest patch release to pick up bug fixes and minor improvements.
Android boot-time smoothness + release-mode pyjnius fix: - run extractAsset / unzipAsset / loadLibrary off the platform main thread so asset unpacking and native library loading no longer block Choreographer / vsync (boot animations stay smooth) - consumer ProGuard rules keeping the pyjnius bootstrap classes so release (minified) builds don't strip PythonActivity.mActivity Lockstep bump across all packages (pubspecs, darwin podspec, android gradle) plus changelogs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Android boot-time smoothness and a release-mode pyjnius fix, released as 4.1.0 (lockstep across all packages).
Smoother boot — run heavy native work off the platform main thread
The plugin's
extractAsset/unzipAsset/loadLibraryMethodChannelhandlers ran synchronously on the Android platform main thread, which is where Flutter'sChoreographerdelivers vsync. Blocking it starves the UI thread of frames, so on-screen animations (e.g. a boot/splash spinner) stutter:extractAsset/unzipAsset),loadLibrary.These handlers now run on a background
Executor, posting theResultback on the main looper, so the platform thread stays free for vsync.Fix pyjnius in release (minified) builds
In release builds the consuming app's R8 pass obfuscated/stripped the plugin classes pyjnius resolves by name at runtime —
PythonActivitywas renamed (e.g. toC.f) and its staticmActivityfield dropped — breaking pyjnius with:(Debug builds, which don't minify, were unaffected.) The plugin now ships consumer ProGuard rules (
-keep class com.flet.serious_python_android.** { *; }), automatically merged into the consuming app's R8 pass.Changes
serious_python_android: background-thread the three handlers; addconsumer-rules.pro+consumerProguardFiles.Notes
loadLibrarymoving off-thread is safe becauseSystem.loadLibraryresolves via the caller class's loader (AndroidPlugin→ app loader) andJNI_OnLoad'sFindClassuses that same loader regardless of thread; the worker's context ClassLoader is also pinned to the app loader. Verified with a pyjnius app in release.Py_Initialize+ imports already run on a separate native worker thread, so they're not addressed here (that's CPU contention, not a main-thread block).