Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use try/catch #745

Closed
JCKodel opened this issue Aug 7, 2020 · 22 comments
Closed

Use try/catch #745

JCKodel opened this issue Aug 7, 2020 · 22 comments

Comments

@JCKodel
Copy link

JCKodel commented Aug 7, 2020

Describe the bug
I have an app with 3 million downloads and flutter_local_notifications are the #1 issues on Crashlytics (not because of this plugin, but because Android itself sucks).

What I do is to fill the plugin Java code with try/catches to ignore errors so the app won't crash (the users will not receive notifications, but at least they can use the app).

Here are some logs (those are just examples: almost every point in this plugin crashes, including boot_received):
image

Fatal Exception: java.lang.RuntimeException: Unable to start receiver com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver: java.lang.NullPointerException: Attempt to write to field 'long android.app.Notification.when' on a null object reference
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:3369)
       at android.app.ActivityThread.-wrap20(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1726)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1518)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
Caused by java.lang.NullPointerException: Attempt to write to field 'long android.app.Notification.when' on a null object reference
       at com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver.onReceive(ScheduledNotificationReceiver.java:32)
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:3362)
       at android.app.ActivityThread.-wrap20(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1726)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1518)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)

image

Fatal Exception: java.lang.RuntimeException: Unable to start receiver com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:3658)
       at android.app.ActivityThread.access$1400(ActivityThread.java:245)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1839)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:216)
       at android.app.ActivityThread.main(ActivityThread.java:7258)
       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:975)
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference
       at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.setupNotificationChannel(FlutterLocalNotificationsPlugin.java:634)
       at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:130)
       at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.showNotification(FlutterLocalNotificationsPlugin.java:688)
       at com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver.onReceive(ScheduledNotificationReceiver.java:45)
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:3649)
       at android.app.ActivityThread.access$1400(ActivityThread.java:245)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1839)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:216)
       at android.app.ActivityThread.main(ActivityThread.java:7258)
       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:975)

image

Fatal Exception: java.lang.RuntimeException: Unable to start receiver com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver: java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.dexterous.flutterlocalnotifications.models.NotificationDetails.channelId' on a null object reference
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:4012)
       at android.app.ActivityThread.access$1500(ActivityThread.java:232)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2025)
       at android.os.Handler.dispatchMessage(Handler.java:107)
       at android.os.Looper.loop(Looper.java:241)
       at android.app.ActivityThread.main(ActivityThread.java:7617)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
Caused by java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.dexterous.flutterlocalnotifications.models.NotificationDetails.channelId' on a null object reference
       at com.dexterous.flutterlocalnotifications.models.NotificationChannelDetails.fromNotificationDetails(NotificationChannelDetails.java:74)
       at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:138)
       at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.showNotification(FlutterLocalNotificationsPlugin.java:803)
       at com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver.onReceive(ScheduledNotificationReceiver.java:56)
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:4003)
       at android.app.ActivityThread.access$1500(ActivityThread.java:232)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2025)
       at android.os.Handler.dispatchMessage(Handler.java:107)
       at android.os.Looper.loop(Looper.java:241)
       at android.app.ActivityThread.main(ActivityThread.java:7617)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

Try/catch can work and has been suggested before but it only hides the issue that makes it harder to find out wheb there's an issue for the plugin to fix.

Unless you can provide details on reproducing these issues, from what I've been reading, cases like these are due to not having configured everything properly at some point during the development of an app. This tends to be due to not having done the release build configuration

@JCKodel
Copy link
Author

JCKodel commented Aug 7, 2020

@MaikuB: As I said, I have 3 million downloads. Notice that the most severe log shows errors in only 3619 users.

It is NOT my code, nor it is yours. For some users, notifications just don't work. I have this issue since 2017 when my app was written in Xamarin Forms.

I never had any kind of problem in none of my devices (I keep 5 devices, including ancient Motorola G from 2013 and iPhone 5S).

There is nothing I can provide for you (since I can't get access to those users), and I know it is not my fault nor your, so, yes, ignore those errors make sense (specially in places where there is no Dart code running, such as in receiving notifications or boot restore on Android).

I don't know if this is possible in Java/Objective-C, but, in C#, we could ignore errors in release using this not so beautiful hack:

#if RELEASE
try {
#endif
  do some code here
#if RELEASE
} catch (Exception ex) {
  Log the exception here
}
#endif

@JCKodel
Copy link
Author

JCKodel commented Aug 7, 2020

image

This Google Play report shows how Android notifications are problematic. In the last 60 days, the most problematic issue was another plugin that handles notifications as well. Works for 75% of the users, 25% crashes. =\ And the code is simple as:

https://github.com/ChangJoo-Park/flutter_foreground_service_plugin/blob/5379926969ba5f5e170c9f4e8e98bad2803534e5/android/src/main/java/changjoopark/com/flutter_foreground_plugin/FlutterForegroundService.java#L23

image

What can we do if intent.getAction() just randomly crashes in 25% of the devices? =(

@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

As I said, I have 3 million downloads. Notice that the most severe log shows errors in only 3619 users.

I don't know what you were trying to convey by mentioning the number of downloads though. Originally you mentioned this and then attached some graphs so I'm not sure what I'm meant to infer from this

It is NOT my code, nor it is yours. For some users, notifications just don't work. I have this issue since 2017 when my app was written in Xamarin Forms.

One thing though is that at one point, one of the Flutter SDK releases turned on switched over R8, minification etc so it would've been easy to just upgrade the Flutter SDK without realising extra setup was needed for this plugin. More steps needed to be done for the release build configuration compared to the earlier versions of the plugin as well.

I'm curious about the issue you had on Xamarin.Forms. Was it exactly the same issue as I use to build apps using Xamarin.Forms.

I never had any kind of problem in none of my devices (I keep 5 devices, including ancient Motorola G from 2013 and iPhone 5S).

I assume the testing was done using release builds?

You may be well be right that it's due to Android given there are a lot of companies that put their own customisations. Some don't even support background operations. I've had reports of a null intent for the AppAuth wrapper plugin I maintain too and can't make sense of it either MaikuB/flutter_appauth#128 (comment)

@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

By the way, what version of the plugin is your app using? The first crash looks quite odd...

Edit: would also like to know what's the earliest version of the plugin that you've used in this app

@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

If it's possible for you to reference a fork of the plugin on your app, I'd be interested to see if it's possible to get the values of the string at this line

String notificationDetailsJson = intent.getStringExtra(FlutterLocalNotificationsPlugin.NOTIFICATION_DETAILS);

I've seen someone say without any further explanation or evidence that the string could just be {}

Edit: if you can use a fork that can capture more info and publish an app update out, then I reckon this is the best opportunity to figure out what the problem is in case there's an issue that can be resolved be rewriting some of the code within that receiver that only occurs in some scenarios

@JCKodel
Copy link
Author

JCKodel commented Aug 7, 2020

I don't know what you were trying to convey by mentioning the number of downloads though. Originally you mentioned this and then attached some graphs so I'm not sure what I'm meant to infer from this

This: the number of users is far superior than the number of users with crashes.

One thing though is that at one point, one of the Flutter SDK releases turned on switched over R8, minification etc so it would've been easy to just upgrade the Flutter SDK without realising extra setup was needed for this plugin. More steps needed to be done for the release build configuration compared to the earlier versions of the plugin as well.

Ok, but this would crash for 100% of users, right?

I'm curious about the issue you had on Xamarin.Forms. Was it exactly the same issue as I use to build apps using Xamarin.Forms.

Scheduled notifications didn't work, again, for just some users. I don't know if it is the exactly same problem, but the behavior is the same: the notifications works for almost all users, except for a few. There are no correlations of OS version, phone manufacturer, etc.

I assume the testing was done using release builds?

Yes, I always run all features of my app in release mode in all those devices before submiting them to the stores.

You may be well be right that it's due to Android given there are a lot of companies that put their own customisations.

Agree, but this would not make some devices to work and others don't, considering they are the same (for example, in the first report, there are 83% of 3619 users in Samsung models. 12% of those are from Galaxy J5 Prime in the last 90 days. I guess this is about 434 devices, according to Crashlytics. But, in the same period, I had 43439 Galaxy J5 Prime users using the app. I can only assume that, given the same model, a small % of it just crashes. And is hard for me to know which one of them are.

I always tought this would have something to do with memory pressure, but Crashlytics has some info about that and I'm seeing RAM free as 377Mb, 392Mb, 460Mb even 1.34Gb of free RAM on a Samsung Galaxy S10e.

I had this one user that contact us through a support ticket telling she had a brand new LG K9 with 1 week of use. In her old Samsung J4, notifications worked. In this new phone, no notifications. I have one person that have the exactly same model, I borrowed her phone and it worked. =\

That's why so hard to give you useful information or replication procedures.

@JCKodel
Copy link
Author

JCKodel commented Aug 7, 2020

If it's possible for you to reference a fork of the plugin on your app, I'd be interested to see if it's possible to get the values of the string at this line

String notificationDetailsJson = intent.getStringExtra(FlutterLocalNotificationsPlugin.NOTIFICATION_DETAILS);

I've seen someone say without any further explanation or evidence that the string could just be {}

Edit: if you can use a fork that can capture more info and publish an app update out, then I reckon this is the best opportunity to figure out what the problem is in case there's an issue that can be resolved be rewriting some of the code within that receiver that only occurs in some scenarios

According to the adapted source code I have and Google Play Console logs, this lines gives me a:

java.lang.RuntimeException:
at android.app.ActivityThread.handleReceiver (ActivityThread.java:3619)
at android.app.ActivityThread.access$1300 (ActivityThread.java:237)
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1803)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loop (Looper.java:214)
at android.app.ActivityThread.main (ActivityThread.java:7091)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:975)
Caused by: java.lang.NullPointerException:
at com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver.onReceive (ScheduledNotificationReceiver.java:32)
at android.app.ActivityThread.handleReceiver (ActivityThread.java:3610)

@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

Ok, but this would crash for 100% of users, right?

From what I've heard, it's inconsistent, so I would guess not

That's why so hard to give you useful information or replication procedures.

See my previous message on if it's possible for you to use a fork with more logging. This would greatly help in tracking down the issue. The first crash in your original message looks very odd and the only way I can see that happening is if the JSON didn't get saved properly. Ignoring if there's an issue with intents here, the likely cause of this is due to missing configuration for the Proguard rules file at some in time during development. some of them relate to the GSON library that relates to handling JSON on Android.

Would be good to know what versions of the plugin you used during the lifetime of your application as well

@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

According to the adapted source code I have and Google Play Console logs, this lines gives me a:

I've seen some crash logs where the line numbers don't match the code properly. Not sure why, perhaps due to minification being enabled.

Also, another thing I'd like to know is what's in your Proguard rules file for your application

@JCKodel
Copy link
Author

JCKodel commented Aug 7, 2020

See my previous message on if it's possible for you to use a fork with more logging.

The problem is my Java knowledge resumes to be able to add a try/catch =P I can't even configure VSCode to use Java 11 without messing the Flutter compilation =(

I tried to implement ACRA, but failed (can't compile it).

The crashes I have is before the try/catch (as some users didn't updated their apps, some Google reports are fresh)

the likely cause of this is due to missing configuration for the Proguard rules file at some in time during development

I don't know exactly how Proguard and R8 works, but I did my best to disable them (before, Google Play reports were useless, because they didn't had any source information on the stacktrace). Don't know if this information is relevant.

Would be good to know what versions of the plugin you used during the lifetime of your application as well

In the last month, the latest (I've downloaded the .zip from pub.dev (1.4.4+2) and used dependency_overrides to make it load from disk instead of pub.)

@JCKodel
Copy link
Author

JCKodel commented Aug 7, 2020

proguard-rules.pro

## Flutter wrapper
-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.**  { *; }
-dontwarn io.flutter.embedding.**

## Gson rules
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
  @com.google.gson.annotations.SerializedName <fields>;
}

## flutter_local_notification plugin rules
-keep class com.dexterous.** { *; }

In the past there was some minification = off on build.gradle, but since I've updated to Flutter 1.19, those configs are no longer there.

I can't even say if proguard.pro is being loaded (there is no references in any files).

@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

The problem is my Java knowledge resumes to be able to add a try/catch =P I can't even configure VSCode to use Java 11 without messing the Flutter compilation =(

As an example, if you have Crashlytics then you could look at code to adding logging. If you're unable to assist in investigating further then I'm afraid that at this stage this issue will persist and you'll need to keep your adapted code with the try catch blocks. Adding try/catch fixes the symptoms but properly fixing this issue should address the cause as close possible. The first crash indicates that there's a path in the code that I would not have expected at all.

I can't even say if proguard.pro is being loaded (there is no references in any files).

It's typically referenced in your app's build.gradle file e.g.

@MaikuB
Copy link
Owner

MaikuB commented Aug 7, 2020

As an alternative, if you're willing to remove the try/catch blocks in your code, I'd be interested to know if the following changes to the receiver would fix some of the issues you're having

public void onReceive(final Context context, Intent intent) {
        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

        boolean repeat = intent.getBooleanExtra(FlutterLocalNotificationsPlugin.REPEAT, false);
        Notification notification = intent.getParcelableExtra(FlutterLocalNotificationsPlugin.NOTIFICATION);
        // TODO: remove this branching logic as it's legacy code to fix an issue where notifications weren't reporting the correct time
        if(notification != null) {
            notification.when = System.currentTimeMillis();
            int notificationId = intent.getIntExtra(FlutterLocalNotificationsPlugin.NOTIFICATION_ID,
                    0);
            notificationManager.notify(notificationId, notification);
            if (repeat) {
                return;
            }
            FlutterLocalNotificationsPlugin.removeNotificationFromCache(notificationId, context);
        } else {
            Gson gson = FlutterLocalNotificationsPlugin.buildGson();
            Type type = new TypeToken<NotificationDetails>() {
            }.getType();
            String notificationDetailsJson = intent.getStringExtra(FlutterLocalNotificationsPlugin.NOTIFICATION_DETAILS);
            NotificationDetails notificationDetails  = gson.fromJson(notificationDetailsJson, type);
            FlutterLocalNotificationsPlugin.showNotification(context, notificationDetails);
            if (repeat) {
                return;
            }
            FlutterLocalNotificationsPlugin.removeNotificationFromCache(notificationDetails.id, context);
        }

    }

Not something I've tried yet but the idea is to not using the JSON

@MaikuB
Copy link
Owner

MaikuB commented Aug 29, 2020

Did you end up trying the above changes?

@MaikuB
Copy link
Owner

MaikuB commented Oct 19, 2020

Closing due to lack of updates. Note that I have encountered one app that had an error relating to an icon and this was due to calling initialize without awaiting. I don't know if this the case for your app but worth checking

@MaikuB MaikuB closed this as completed Oct 19, 2020
@ericaig
Copy link

ericaig commented Jul 28, 2021

Hi @MaikuB , I'm having the same issue and this is the error stack

D/ActivityThread(16695): BDC-Calling onReceive: intent=Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000010 pkg=com.my.pkgId cmp=com.my.pkgId/io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingReceiver (has extras) }, receiver=io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingReceiver@4385181
D/FLTFireMsgReceiver(16695): broadcast received for message
D/ActivityThread(16695): BDC-Calling onReceive: intent=Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000010 pkg=com.my.pkgId cmp=com.my.pkgId/com.google.firebase.iid.FirebaseInstanceIdReceiver (has extras) }, receiver=com.google.firebase.iid.FirebaseInstanceIdReceiver@f963226
V/ActivityThread(16695): SVC-Creating service CreateServiceData{token=android.os.BinderProxy@3234ab2 className=io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService packageName=com.my.pkgId intent=null}
D/ActivityThread(16695): SVC-Calling onStartCommand: io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService@e753a03, flags=0, startId=1
I/flutter (16695): onMessage title: Hello, body: World, data: {}
V/ActivityThread(16695): SVC-Destroying service io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService@e753a03
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): Failed to handle method call
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): java.lang.NullPointerException: Attempt to read from field 'java.lang.Boolean com.dexterous.flutterlocalnotifications.models.styles.DefaultStyleInformation.htmlFormatTitle' on a null object reference
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:169)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.showNotification(FlutterLocalNotificationsPlugin.java:791)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.show(FlutterLocalNotificationsPlugin.java:1054)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:947)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:818)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at android.os.MessageQueue.next(MessageQueue.java:328)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at android.os.Looper.loop(Looper.java:148)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at android.app.ActivityThread.main(ActivityThread.java:6247)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
E/MethodChannel#dexterous.com/flutter/local_notifications(16695): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
I/flutter (16695): PlatformException(error, Attempt to read from field 'java.lang.Boolean com.dexterous.flutterlocalnotifications.models.styles.DefaultStyleInformation.htmlFormatTitle' on a null object reference, null, java.lang.NullPointerException: Attempt to read from field 'java.lang.Boolean com.dexterous.flutterlocalnotifications.models.styles.DefaultStyleInformation.htmlFormatTitle' on a null object reference
I/flutter (16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.createNotification(FlutterLocalNotificationsPlugin.java:169)
I/flutter (16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.showNotification(FlutterLocalNotificationsPlugin.java:791)
I/flutter (16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.show(FlutterLocalNotificationsPlugin.java:1054)
I/flutter (16695): 	at com.dexterous.flutterlocalnotifications.FlutterLocalNotificationsPlugin.onMethodCall(FlutterLocalNotificationsPlugin.java:947)
I/flutter (16695): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.jav

As I'm sure you already know, this only affects Android devices. And it happens whenever the app I'm developing is currently open (foreground) and then a notification arrives. If it's in background, it works well. In this case, this is what's shown in terminal:

D/ActivityThread(16695): BDC-Calling onReceive: intent=Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000010 pkg=com.my.pkgId cmp=com.my.pkgId/io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingReceiver (has extras) }, receiver=io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingReceiver@9a3060c
D/FLTFireMsgReceiver(16695): broadcast received for message
V/ActivityThread(16695): SVC-Creating service CreateServiceData{token=android.os.BinderProxy@f896b55 className=io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingBackgroundService packageName=com.my.pkgId intent=null}
D/ActivityThread(16695): SVC-Calling onStartCommand: io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingBackgroundService@4f4c96a, flags=0, startId=1
D/ActivityThread(16695): BDC-Calling onReceive: intent=Intent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000010 pkg=com.my.pkgId cmp=com.my.pkgId/com.google.firebase.iid.FirebaseInstanceIdReceiver (has extras) }, receiver=com.google.firebase.iid.FirebaseInstanceIdReceiver@68076f8
V/ActivityThread(16695): SVC-Creating service CreateServiceData{token=android.os.BinderProxy@9c20aa4 className=io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService packageName=com.my.pkgId intent=null}
D/ActivityThread(16695): SVC-Calling onStartCommand: io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService@5b4b00d, flags=0, startId=1
V/ActivityThread(16695): SVC-Destroying service io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService@5b4b00d
D/SQLiteDatabase(16695): beginTransaction()
D/SQLiteDatabase(16695): endTransaction()

I'm gonna try and implement this code and see if it works. Whatever the case, I'll give you feedbacks.

By the way, I'm using flutter_local_notifications: ^5.0.0

Thanks for the plugin though. Working great so far. Just only this minor hiccup

@ericaig
Copy link

ericaig commented Jul 29, 2021

Well I tried using the code you provided and that didn't work. I decided to use the latest version (which was 6.1.0 at that particular time even though v7.* was later released the same day). I tried that as well and it didn't work.

So I ended up using Flutter's WidgetsBindingObserver to check if the app is in foreground or not. If it is, I don't show the notification. For now, I only use this package if the app is in background :(

I'm doing something like this atm

  Future<void> _presentLocalNotification(
    int id,
    PushNotification _notification,
  ) async {
    try {
      // TODO: do something if app received notification and it's active. Store to local, show using dialog, or something else
      if (_lifeCycleWatcherCtrl.isActive)
        return print("Can't show local notification as device is active");

      await _flutterLocalNotificationsPlugin.show(
        id,
        _notification.title,
        _notification.body,
        NotificationDetails(),
      );
    } catch (e, s) {
      logError(e, s);
    }
  }

@MaikuB
Copy link
Owner

MaikuB commented Jul 29, 2021

Unless a minimal app that can reproduce the issue and steps to reproduce are provided, it's not possible for me to look into this further. The changes I suggested above are based on what another person in the community mentioned without presenting any evidence. It was also based on how those who had used a very old plugin may have had corrupted data.

It's odd that you're seeing that particular crash as the htmlFormatTitle property is non-nullable from the Dart side. Not sure how your app has been able to pass a null value unless it use to explicitly do so before null-safety migration was done or perhaps the release build configuration hasn't been done

@noinskit
Copy link
Contributor

FYI it's still happening in 10.0.0-dev.20 with a similar stack trace:

Caused by java.lang.NullPointerException: Attempt to write to field 'long android.app.Notification.when' on a null object reference
       at com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver.onReceive(ScheduledNotificationReceiver.java:32)
       at android.app.ActivityThread.handleReceiver(ActivityThread.java:4462)
       at android.app.ActivityThread.access$2700(ActivityThread.java:308)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2325)
       at android.os.Handler.dispatchMessage(Handler.java:110)
       at android.os.Looper.loop(Looper.java:219)
       at android.app.ActivityThread.main(ActivityThread.java:8347)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

I do not have a minimal repro app. I only know these from production error reports.

@MaikuB
Copy link
Owner

MaikuB commented Aug 28, 2022

@noinskit looking at the stack trace, this would mean the app with this trace is using a version of the plugin before 9.1.3. Do you happen to have version control on your app to know what's the earliest version of the plugin your app had used? Asking because the logic that is being triggered is fallback logic for apps using plugin versions older than 0.3.4 given the JSON.

Other potential reason I can think of is what I explained in previous posts where apps using the plugin didn't properly configure the Proguard rules. There isn't anything that can't be done to fix that. If the plugin was to add a null check, it could end up swallowing this error that would help point to a misconfiguration

@noinskit
Copy link
Contributor

@MaikuB you're right, my bad. It was an ancient version of my app and I misread its version in the prod error report. Sorry!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants