react-native-notifications: Android 11 and above crashing on notification open

The app crashes while opening the notification and shows the following message java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.clone()' on a null object reference

currently using version 4.2.3

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 8
  • Comments: 32

Commits related to this issue

Most upvoted comments

After some monitoring I have to retract my earlier statement that this was fixed, I encounter crashes with the similar stack trace as @hankhester reported here.

So, @DanielEliraz just to prevent these unhandled crashes, would it be possible to patch the`notifiyOpenedToJS method to include a try…catch statement? From: https://github.com/wix/react-native-notifications/blob/a18a593e3a62f7a0d1e8f6bfae354f4af2b4c669/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java#L208-L213

to

    private void notifyOpenedToJS() {
        Bundle response = new Bundle();
        try {
            response.putBundle("notification", mNotificationProps.asBundle());
        } catch (NullPointerException e) {
            Log.e(LOGTAG, "notifyOpenedToJS: Null pointer exception");
        }

Just like you did in #835? https://github.com/wix/react-native-notifications/blob/f7928d4e7134410e798a15fa827b9d7b047e24f5/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java#L81

@DanielEliraz This problem persists for me in 4.2.4 with Android 12 and target SDK 31. I recommend keeping the issue open until this package works with > 30.

Using patch-package you can apply this patch… it seems to have worked for me: https://gist.github.com/pepf/742d4772545400919aece5649402b9e7

Logs when reproducing: Screenshot 2022-06-10 at 11 17 17

lowered the targetSkdVersion to 30 and it worked

diff --git a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java
index eadf41e..5903e02 100644
--- a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java
+++ b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/RNNotificationsPackage.java
@@ -17,7 +17,6 @@ import com.wix.reactnativenotifications.core.InitialNotificationHolder;
 import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
 import com.wix.reactnativenotifications.core.notification.IPushNotification;
 import com.wix.reactnativenotifications.core.notification.PushNotification;
-import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
 import com.wix.reactnativenotifications.core.notificationdrawer.IPushNotificationsDrawer;
 import com.wix.reactnativenotifications.core.notificationdrawer.PushNotificationsDrawer;
 
@@ -96,9 +95,7 @@ public class RNNotificationsPackage implements ReactPackage, AppLifecycleFacade.
         Intent intent = activity.getIntent();
         if (NotificationIntentAdapter.canHandleIntent(intent)) {
             Context appContext = mApplication.getApplicationContext();
-            Bundle notificationData = NotificationIntentAdapter.cannotHandleTrampolineActivity(appContext) ?
-                    NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent) : intent.getExtras();
-            final IPushNotification pushNotification = PushNotification.get(appContext, notificationData);
+            final IPushNotification pushNotification = PushNotification.get(appContext, intent.getExtras());
             if (pushNotification != null) {
                 pushNotification.onOpened();
             }

this is enough to target SDK 31 without any crashes

Checked latest version on an android (12) emulator with targetSdkVersion = 31 set the app build. No crash! 🙏

Upon inspecting the adb logs, opening a push notification as a cold boot (no activity) triggers the exception: Screenshot 2022-04-24 at 19 57 27

Opening a push notification when the activity is already running this exception is not triggered.

Okay, this took way too long, but I got things working with targetSdkVersion 31. I’m also on RN 68.2. There are a few places things could be going wrong for everyone.

First, you need to run this patch: https://github.com/wix/react-native-notifications/issues/874#issuecomment-1233798966 You can also combine the patch in this thread (https://github.com/wix/react-native-notifications/issues/835#issuecomment-1152155685) to handle any exceptions, but they shouldn’t happen if you get everything working.

Next, you need to make sure your AndroidManifest.xml handles both deeplinks and universal links if you plan on using both. The structure was changed in Android 12 due to security stuff and now you need separate intents for each type of link (example:// and https://www.example.com). Here’s an example from my app. The two schemes I use are deep links: https://www.pebbleclimbing.com and app links: pebble://

    <activity android:name=".MainActivity"
      android:label="@string/app_name"
      android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
      android:launchMode="singleTask"
      android:screenOrientation="portrait"
      android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
      android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- Accepts URIs that begin with "http://www.pebbleclimbing.com/” -->
        <data android:scheme="https"
              android:host="www.pebbleclimbing.com"
              android:pathPrefix="/" />
        <!-- note that the leading "/" is required for pathPrefix-->
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- Accepts URIs that begin with "pebble:// -->
        <data android:scheme="pebble" />
    </intent-filter>
    </activity>

Next, when setting stuff up, you need to create a channel on app startup. See here in the docs: https://wix.github.io/react-native-notifications/api/android-api#setnotificationchannel

Now, if you want to have foreground notifications, you need to duplicate the incoming notification as a local notification outlined here: https://github.com/wix/react-native-notifications/issues/869#issuecomment-1157869452 But, this doesn’t work because we’re going to be sending a channel id with our remote notifications as well (remote notifications won’t open the app without it). So, instead of checking for lack of a channel id to see if you need to create a duplicated local notification, add some sort of boolean to the notification when duplicating it for the foreground notification. ex:

if (!notification?.payload?.is_local_foreground) {
            // notification.payload.android_channel_id = "pebble-channel-id"
            notification.payload.is_local_foreground = true
            let nId = Notifications.postLocalNotification(notification.payload)
            console.log(nId)
          }

Finally, when you send the notification from the server, you need to send the channel id with the data so that it will open your app. I’m using amazon pinpoint and my raw message data structure looks like the following, but yours might be different and need some alternate massaging. This structure is pretty important. If I added anything outside the data object, the notification would not open the app if it was in the background/killed :


{
  "GCMMessage": {
    "data": {
      "title": "Pebble test gym",
      "body": "This is the body of the message for Pebble test gym.",
      "url": "pebble://gyms/pebble-test",
      "android_channel_id": "pebble-channel-id"
    }
  }
}

Also, if your app is killed, you need to get the notification using getInitialNotification: https://wix.github.io/react-native-notifications/api/general-api/#getinitialnotification

Hopefully this helps y’all. This library does work for Android 13, but there are a lot of gotchas.

@DanielEliraz the issue still exist in v4.3.1 unfortunately. We were that unlucky project who sent ~1k push notifications to users and got ~200 crash reports same day

Android 11 and above | RN 0.68.2 | Logs

@MajkellVZ your patch worked for me!! ❤️ Android 11 and 13

Tried the solution provided by @Vednus and it doesn’t crash and I think that’s mostly because of #835 (comment) but now when opening the notification it doesn’t redirect to the desired screen.

Also experience this when the app is in the background or killed state.

Some members of my team are also experiencing this on 4.3.2, although it might be something device specific, as for others the bug has been fixed.

This patch seemed to work for those who are now having issues with 4.3.2: https://github.com/wix/react-native-notifications/issues/835#issuecomment-1152155685

Hmm, @DanielEliraz I’m still experiencing this on 4.3.1 when opening a push notification as a cold boot with targetSdkVersion = 31 and Android API level both 30 and 32. react-native v0.68.0

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.clone()' on a null object reference
        at com.wix.reactnativenotifications.core.notification.PushNotificationProps.asBundle(PushNotificationProps.java:26)
        at com.wix.reactnativenotifications.core.notification.PushNotification.notifyOpenedToJS(PushNotification.java:210)
        at com.wix.reactnativenotifications.core.notification.PushNotification.dispatchImmediately(PushNotification.java:127)
        at com.wix.reactnativenotifications.core.notification.PushNotification$1.onAppVisible(PushNotification.java:36)
        at com.wix.reactnativenotifications.core.ReactAppLifecycleFacade.switchToVisible(ReactAppLifecycleFacade.java:88)
        at com.wix.reactnativenotifications.core.ReactAppLifecycleFacade.access$000(ReactAppLifecycleFacade.java:14)
        at com.wix.reactnativenotifications.core.ReactAppLifecycleFacade$1.onHostResume(ReactAppLifecycleFacade.java:27)
        at com.facebook.react.bridge.ReactContext.onHostResume(ReactContext.java:263)
        at com.facebook.react.ReactInstanceManager.moveToResumedLifecycleState(ReactInstanceManager.java:784)
        at com.facebook.react.ReactInstanceManager.onHostResume(ReactInstanceManager.java:682)
        at com.facebook.react.ReactInstanceManager.onHostResume(ReactInstanceManager.java:632)
        at com.facebook.react.ReactDelegate.onHostResume(ReactDelegate.java:53)
        at com.facebook.react.ReactActivityDelegate.onResume(ReactActivityDelegate.java:100)
        at com.facebook.react.ReactActivity.onResume(ReactActivity.java:58)
        at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1456)
        at android.app.Activity.performResume(Activity.java:8129)
        at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4434)
        at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4476)
        at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:223)
        at android.app.ActivityThread.main(ActivityThread.java:7656)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

@taranda @pepf , can you please try it with version 4.3.1?

@MajkellVZ Need to find a way to solve it also in targetSkdVersion > 30. In my app I added the logic in the MainActivity but it seems hucky. But for now ReactNative’s targetSkdVersion is 30 so there is time to think

can you please share your solution without the need to lower the sdk to 30?