In "The Dreaded Missing Plugin Exception" I described one type of bug which causes the app to get stuck at a blank white screen during startup. However if there’s any other exception happening during the early initialization phase which trips Flutter then it’ll also result in the same white screen ANR (Application Not Responding), but I’ll talk about that later.
Several people asked, so first I’d want to provide a recipe which prevents Missing Plugin Exception and other related crashes which result from R8 being too eager to ‘whack’ classes and code.
Look up android /app /src /main /java /io /flutter /pluins /Generated Plugin Registrant .java . Focus on the only function registerWith . Iterate over all the lines of that function each one belongs to a plugin. Identify the class name of the plugin from that line. For example if the line is flutterEngine .getPlugins() .add(new com. pauldemarco. flutter_blue. FlutterBluePlugin()); then the class path will be "com. pauldemarco. flutter_blue". basically you need to leave off the last camel-case part from the path. Add a keep class rule for that class path into the Pro Guard configuration file. If you don’t have a ProGuard configuration file then create the file android /app /proguard-rules .pro and that will be your rule file. Add a keepclass member names rule for the same class path into the Pro Guard configuration file. After the iteration is done add rules for the Lifecycle Observer . Add some more extra rules. For example here is the line in the Generated Plugin Registrant .java :
flutterEngine . getPlugins (). add ( new com . pauldemarco . flutter_blue . FlutterBluePlugin ());
then it’ll mean these ProGuard rules:
-keep class com.pauldemarco.flutter_blue.** { *; }
-keepclassmembernames class com.pauldemarco.flutter_blue.* { *; }
For the most complete example here is my full Generated Plugin Registrant .java :
@Keep
public final class GeneratedPluginRegistrant {
public static void registerWith ( @NonNull FlutterEngine flutterEngine ) {
ShimPluginRegistry shimPluginRegistry = new ShimPluginRegistry ( flutterEngine );
flutterEngine . getPlugins (). add ( new io . flutter . plugins . deviceinfo . DeviceInfoPlugin ());
flutterEngine . getPlugins (). add ( new com . mr . flutter . plugin . filepicker . FilePickerPlugin ());
flutterEngine . getPlugins (). add ( new com . pauldemarco . flutter_blue . FlutterBluePlugin ());
flutterEngine . getPlugins (). add ( new io . flutter . plugins . flutter_plugin_android_lifecycle . FlutterAndroidLifecyclePlugin ());
flutterEngine . getPlugins (). add ( new dev . flutter . plugins . integration_test . IntegrationTestPlugin ());
flutterEngine . getPlugins (). add ( new io . flutter . plugins . pathprovider . PathProviderPlugin ());
flutterEngine . getPlugins (). add ( new io . flutter . plugins . sharedpreferences . SharedPreferencesPlugin ());
flutterEngine . getPlugins (). add ( new com . tekartik . sqflite . SqflitePlugin ());
flutterEngine . getPlugins (). add ( new name . avioli . unilinks . UniLinksPlugin ());
flutterEngine . getPlugins (). add ( new io . flutter . plugins . urllauncher . UrlLauncherPlugin ());
flutterEngine . getPlugins (). add ( new creativemaybeno . wakelock . WakelockPlugin ());
com . twwm . share_files_and_screenshot_widgets . ShareFilesAndScreenshotWidgetsPlugin . registerWith ( shimPluginRegistry . registrarFor ( "com.twwm.share_files_and_screenshot_widgets.ShareFilesAndScreenshotWidgetsPlugin" ));
}
}
My related ProGuard configuration file:
-verbose
-keep class androidx.lifecycle.** { *; }
-keepclassmembernames class androidx.lifecycle.* { *; }
-keepclassmembers class * implements androidx.lifecycle.LifecycleObserver {
<init>(...);
}
-keepclassmembers class * extends androidx.lifecycle.ViewModel {
<init>(...);
}
-keepclassmembers class androidx.lifecycle.Lifecycle$State { *; }
-keepclassmembers class androidx.lifecycle.Lifecycle$Event { *; }
-keepclassmembers class * {
@androidx.lifecycle.OnLifecycleEvent *;
}
# https://github.com/flutter/flutter/issues/78625#issuecomment-804164524
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
# This is from iterating over GeneratedPLuginRegistrant.java [
-keep class com.pauldemarco.flutter_blue.** { *; }
-keepclassmembernames class com.pauldemarco.flutter_blue.* { *; }
-keep class io.flutter.plugins.deviceinfo.** { *; }
-keepclassmembernames class io.flutter.plugins.deviceinfo.** { *; }
-keep class com.mr.flutter.plugin.filepicker.** { *; }
-keepclassmembernames class com.mr.flutter.plugin.filepicker.** { *; }
-keep class io.flutter.plugins.flutter_plugin_android_lifecycle.** { *; }
-keepclassmembernames class io.flutter.plugins.flutter_plugin_android_lifecycle.** { *; }
-keep class dev.flutter.plugins.integration_test.** { *; }
-keepclassmembernames class dev.flutter.plugins.integration_test.** { *; }
-keep class io.flutter.plugins.pathprovider.** { *; }
-keepclassmembernames class io.flutter.plugins.pathprovider.** { *; }
-keep class com.twwm.share_files_and_screenshot_widgets.** { *; }
-keepclassmembernames class com.twwm.share_files_and_screenshot_widgets.** { *; }
-keep class io.flutter.plugins.sharedpreferences.** { *; }
-keepclassmembernames class io.flutter.plugins.sharedpreferences.** { *; }
-keep class com.tekartik.sqflite.** { *; }
-keepclassmembernames class com.tekartik.sqflite.** { *; }
-keep class name.avioli.unilinks.** { *; }
-keepclassmembernames class name.avioli.unilinks.** { *; }
-keep class io.flutter.plugins.urllauncher.** { *; }
-keepclassmembernames class io.flutter.plugins.urllauncher.** { *; }
-keep class creativemaybeno.wakelock.** { *; }
-keepclassmembernames class creativemaybeno.wakelock.** { *; }
# ] This is from iterating over GeneratedPLuginRegistrant.java
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep class * extends com.google.protobuf.** { *; }
-keepclassmembernames class * extends com.google.protobuf.** { *; }
As you can see there’s quite a bit of extras there, but I rather go overkill than cause a release-only white screen ANR (Application Not Responding) again!
White Screen type ANR Lately I also experienced a white screen type ANR (Application Not Responding) with a Huawei Mi Max 3. In that case it seems that some permission causes trouble. It didn’t matter if the bluetooth was turned on or not, but the white screen only came during the first start after the installation. Here is a related call stack from a LogCat:
04-06 22:57:04.995 1930 2164 I ActivityManager: Force stopping dev.csaba.track_my_indoor_exercise appid=10503 user=0: deletePackageX
04-06 22:57:05.601 1930 2218 I ActivityManager: Force stopping dev.csaba.track_my_indoor_exercise appid=10503 user=0: pkg removed
04-06 22:57:05.608 1930 2218 E HistoricalRegistry: Interaction before persistence initialized
04-06 22:57:05.626 1930 1930 I RoleManagerService: Granting default permissions...for user0
04-06 22:57:05.645 1930 2164 W BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:dev.csaba.track_my_indoor_exercise flg=0x4000010 (has extras) } to com.lbe.security.miui/com.lbe.security.service.BootReceiver
04-06 22:57:05.645 1930 2164 W BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:dev.csaba.track_my_indoor_exercise flg=0x4000010 (has extras) } to com.eset.ems2.gp/com.eset.commoncore.core.broadcast.CoreReceiver
04-06 22:57:05.646 1930 2218 I ActivityManager: Force stopping dev.csaba.track_my_indoor_exercise appid=10503 user=0: pkg removed
04-06 22:57:05.692 1930 2218 E AppOps : checkOperation
04-06 22:57:05.692 1930 2218 E AppOps : java.lang.SecurityException: Specified package dev.csaba.track_my_indoor_exercise under uid 10503 but it is really -1
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.appop.AppOpsService.verifyAndGetIsPrivileged(Unknown Source:123)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.appop.AppOpsService.checkOperationUnchecked(Unknown Source:0)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.appop.AppOpsService.checkOperationUnchecked(Unknown Source:6)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.appop.AppOpsService.checkOperationImpl(Unknown Source:48)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.appop.AppOpsService.checkOperationInternal(Unknown Source:6)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.appop.AppOpsService.checkOperation(Unknown Source:1)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.AutoStartManagerService.canRestartServiceLocked(Unknown Source:21)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.AutoStartManagerService.canRestartServiceLocked(Unknown Source:1)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.AutoStartManagerService.signalStopProcessesLocked(Unknown Source:6)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.ProcessList.killPackageProcessesLocked(Unknown Source:194)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.ActivityManagerService.forceStopPackageLocked(Unknown Source:215)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.ActivityManagerService.broadcastIntentLocked(Unknown Source:1718)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.ActivityManagerService.broadcastIntentLocked(Unknown Source:40)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.am.ActivityManagerService.broadcastIntent(Unknown Source:81)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.pm.PackageManagerService.doSendBroadcast(Unknown Source:142)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.pm.PackageManagerService.lambda$sendPackageBroadcast$7$PackageManagerService(Unknown Source:34)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.pm.-$$Lambda$PackageManagerService$O5iApY07YeJyXA8KUFVcxpCf1NI.run(Unknown Source:18)
04-06 22:57:05.692 1930 2218 E AppOps : at android.os.Handler.handleCallback(Unknown Source:2)
04-06 22:57:05.692 1930 2218 E AppOps : at android.os.Handler.dispatchMessage(Unknown Source:4)
04-06 22:57:05.692 1930 2218 E AppOps : at android.os.Looper.loop(Unknown Source:242)
04-06 22:57:05.692 1930 2218 E AppOps : at android.os.HandlerThread.run(Unknown Source:28)
04-06 22:57:05.692 1930 2218 E AppOps : at com.android.server.ServiceThread.run(Unknown Source:12)
04-06 22:57:05.692 1930 2218 I AutoStartManagerService: MIUILOG- Reject RestartService packageName :dev.csaba.track_my_indoor_exercise uid : 10503
As we can see none of the call stack have any calls belonging to a code I could influence in any way (not even a plugin’s source I could fork and modify). I don’t have a definitive solution for this, but possibly I’ll try to use permission_handler or bluetooth_enable plugins to possibly get ahead of the race condition and secure a permission before the bug happens.
I can also see two NPEs (Null Pointer Exceptions) in the Play Store reports I haven’t ever been able to reproduce. They might be the reason for uninstalls.
Release-only NPE 1 java.lang.NullPointerException:
at com.pauldemarco.flutter_blue.FlutterBluePlugin$5.run (FlutterBluePlugin.java:10)
at android.app.Activity.runOnUiThread (Activity.java:7145)
at com.pauldemarco.flutter_blue.FlutterBluePlugin.invokeMethodUIThread (FlutterBluePlugin.java:7)
at com.pauldemarco.flutter_blue.FlutterBluePlugin.access$400 (FlutterBluePlugin.java)
at com.pauldemarco.flutter_blue.FlutterBluePlugin$2.onScanResult (FlutterBluePlugin.java:83)
at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run (BluetoothLeScanner.java:616)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:246)
at android.app.ActivityThread.main (ActivityThread.java:8506)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)
I’ll try to avoid this with a band-aid fix which aims for the effect because I’m not certain about the cause. There are some guesses and I opened up a PR (Pull Request) but I ended up forking the repository .
Release-only NPE 2 java.lang.NullPointerException:
at com.pauldemarco.flutter_blue.FlutterBluePlugin$5.run (FlutterBluePlugin.java:10)
at android.os.Handler.handleCallback (Handler.java:873)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:214)
at android.app.ActivityThread.main (ActivityThread.java:7050)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:965)
I don’t have a clue for now how to cure that.