Azure / azure-notificationhubs-android

Android SDK and Samples for Azure Notification Hubs
Apache License 2.0
33 stars 62 forks source link

[BUG] onMessageReceived throwing NPE #286

Open pizerg opened 1 year ago

pizerg commented 1 year ago

Describe the bug NPE exception is sometimes thrown when onMessageReceived is invoked. The error was captured a couple of times via Crashlytics so cannot provide the exact state of the device at the time but mostly sure app was in background (98% of captured cases) and got a push notification.

Exception or Stack Trace

Fatal Exception: java.lang.NullPointerException: Attempt to invoke interface method 'void com.microsoft.windowsazure.messaging.notificationhubs.NotificationListener.onPushNotificationReceived(android.content.Context, com.google.firebase.messaging.RemoteMessage)' on a null object reference
       at com.microsoft.windowsazure.messaging.notificationhubs.FirebaseReceiver.onMessageReceived(FirebaseReceiver.java:52)
       at com.google.firebase.messaging.FirebaseMessagingService.dispatchMessage(FirebaseMessagingService.java:235)
       at com.google.firebase.messaging.FirebaseMessagingService.passMessageIntentToSdk(FirebaseMessagingService.java:185)
       at com.google.firebase.messaging.FirebaseMessagingService.handleMessageIntent(FirebaseMessagingService.java:172)
       at com.google.firebase.messaging.FirebaseMessagingService.handleIntent(FirebaseMessagingService.java:161)
       at com.google.firebase.messaging.EnhancedIntentService.lambda$processIntent$0$com-google-firebase-messaging-EnhancedIntentService(EnhancedIntentService.java:78)
       at com.google.firebase.messaging.EnhancedIntentService$$ExternalSyntheticLambda0.run(:6)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at com.google.android.gms.common.util.concurrent.zza.run(com.google.android.gms:play-services-basement@@18.1.0:2)
       at java.lang.Thread.run(Thread.java:920)

To Reproduce Steps to reproduce the behavior:

Configure and register with valid credentials + TAG(s) Receive a push notification (most likely with app on the background / killed)

Code Snippet During main activity onCreate method:

NotificationHub.setListener(NotificationDisplayer())

NotificationHub.start(
    this.application,
    BuildConfig.NOTIFICATION_HUB_NAME,
    BuildConfig.NOTIFICATION_HUB_CS
)

NotificationDisplayer just set the channels, etc to be able to show the notification.

And once the user is signed in the following is invoked:

NotificationHub.addTag("[TAG_HERE]")

Expected behavior No exceptions are thrown and events are handled seamlessly.

Setup (please complete the following information):

Information Checklist

Klewerro commented 1 year ago

I have very similar or even the same issue. After starting the application, I'm waiting several seconds to authenticate user (check token using MSAL), then I'm calling:

NotificationHub.start(
            this.application,
            hubName,
            connectionString
        )
        NotificationHub.clearTags()
        NotificationHub.addTag(userId)
        NotificationHub.setListener(notificationViewModel)

Expection found in Firebase logs:

Fatal Exception: java.lang.NullPointerException: Attempt to invoke interface method 'void d8.q.b(android.content.Context, s7.m)' on a null object reference
       at com.microsoft.windowsazure.messaging.notificationhubs.FirebaseReceiver.onMessageReceived(FirebaseReceiver.java:52)
       at com.google.firebase.messaging.FirebaseMessagingService.dispatchMessage(com.google.firebase:firebase-messaging@@21.0.1:13)
       at com.google.firebase.messaging.FirebaseMessagingService.passMessageIntentToSdk(com.google.firebase:firebase-messaging@@21.0.1:8)
       at com.google.firebase.messaging.FirebaseMessagingService.handleMessageIntent(com.google.firebase:firebase-messaging@@21.0.1:3)
       at com.google.firebase.messaging.FirebaseMessagingService.handleIntent(com.google.firebase:firebase-messaging@@21.0.1:3)
       at com.google.firebase.messaging.EnhancedIntentService.lambda$processIntent$0$EnhancedIntentService(EnhancedIntentService.java:11)
       at com.google.firebase.messaging.EnhancedIntentService$$Lambda$0.run(com.google.firebase:firebase-messaging@@21.0.1:11)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
       at com.google.android.gms.common.util.concurrent.zza.run(zza.java:6)
       at java.lang.Thread.run(Thread.java:1012)

Mostly it's happening after 0.5-2 seconds after start of MainActifity. On Firebase Crashlytics I am getting thousands of crash events, saying "This crash event happened in the first second of the user's session."

OS (determined from Firebaes): All supported Android versions, from 8 to 13 Version of the Library used: 1.1.6

I don't know what's happening there, maybe it's some kind of race condition - library trying to upack notification before NotificationHub.start() was called?

pizerg commented 1 year ago

@Klewerro since this repo doesn't seem to be actively maintained we finally coded a workaround that might also work for you. It's definitely not the most clean and elegant solution though.

Essentially you just need to override the library's message receiver, to do so:

Create a new class that extends FirebaseMessagingService, you'll have to force the package name to be "package com.microsoft.windowsazure.messaging.notificationhubs" in order to be able to use some of the library's private package methods, it should look similar to this (you can find NotificationDisplayer in this repo's examples):

class MyFirebaseReceiver @JvmOverloads constructor(
    private val mHub: NotificationHub = NotificationHub.getInstance(),
    private val notificationDisplayer: NotificationDisplayer = NotificationDisplayer()
) : FirebaseMessagingService() {

    override fun onCreate() {
        super.onCreate()

        mHub.registerApplication(this.application)
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        notificationDisplayer.onPushNotificationReceived(this.applicationContext, remoteMessage)
    }

    override fun onNewToken(s: String) {
       mHub.instancePushChannel = s
    }
}

And add the following to your Android Manifest:

<service android:name="com.microsoft.windowsazure.messaging.notificationhubs.MyFirebaseReceiver" android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
        <action android:name="com.google.firebase.messaging.NEW_TOKEN" />
    </intent-filter>
</service>

With this you should be able to stop getting the annoying NPE.

Klewerro commented 1 year ago

What is the NotificationDisplayer? I cannot find it anywhere? Also registerApplication and I cannot call it :( Did you used com.microsoft.azure:notification-hubs-android-sdk-fcm or non -fcm library version?

pizerg commented 1 year ago

@Klewerro

What is the NotificationDisplayer? I cannot find it anywhere? Also registerApplication and I cannot call it :( Did you used com.microsoft.azure:notification-hubs-android-sdk-fcm or non -fcm library version?

You can find NotificationDisplayer here in the repo just modify it to meet your needs.

To be able to call registerApplication you'll need to use "package com.microsoft.windowsazure.messaging.notificationhubs" as the package name for MyFirebaseReceiver