React-native-notifications: Pending notifications only retrieve the data of the oldest notification (Android)

Created on 19 May 2017  路  7Comments  路  Source: wix/react-native-notifications

When the app has several notifications in the drawer, and you press any notification, the PendingNotifications promise result contains only the data from the oldest notification, not the one that was pressed to bring the app to the foreground.

Most helpful comment

I have the same issue. After digging around, I found that every notifications are reusing the same PendingIntent. That is why they pass the same data stored with intent.putExtra().

This solution solves the problem: https://stackoverflow.com/questions/7370324/notification-passes-old-intent-extras

For a quick fix, edit NotificationIntentAdapter.java from this

public static PendingIntent createPendingNotificationIntent(Context appContext, Intent intent, PushNotificationProps notification) {
    intent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle());
    return PendingIntent.getService(appContext, PENDING_INTENT_CODE, intent, PendingIntent.FLAG_ONE_SHOT);
}

to this

public static PendingIntent createPendingNotificationIntent(Context appContext, Intent intent, PushNotificationProps notification) {
    intent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle());
    int uniqueInt = (int) (System.currentTimeMillis() & 0xfffffff);
    return PendingIntent.getService(appContext, uniqueInt, intent, PendingIntent.FLAG_ONE_SHOT);
}

The concept is to pass a different "requestCode" for each notification.

With this, when having multiple notifications, PendingNotifications promise result will give the data for the notification that you pressed.

All 7 comments

I have the same issue. After digging around, I found that every notifications are reusing the same PendingIntent. That is why they pass the same data stored with intent.putExtra().

This solution solves the problem: https://stackoverflow.com/questions/7370324/notification-passes-old-intent-extras

For a quick fix, edit NotificationIntentAdapter.java from this

public static PendingIntent createPendingNotificationIntent(Context appContext, Intent intent, PushNotificationProps notification) {
    intent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle());
    return PendingIntent.getService(appContext, PENDING_INTENT_CODE, intent, PendingIntent.FLAG_ONE_SHOT);
}

to this

public static PendingIntent createPendingNotificationIntent(Context appContext, Intent intent, PushNotificationProps notification) {
    intent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle());
    int uniqueInt = (int) (System.currentTimeMillis() & 0xfffffff);
    return PendingIntent.getService(appContext, uniqueInt, intent, PendingIntent.FLAG_ONE_SHOT);
}

The concept is to pass a different "requestCode" for each notification.

With this, when having multiple notifications, PendingNotifications promise result will give the data for the notification that you pressed.

@re7eal Thanks for the insightful response! Is there any way to achieve this within the JS code, or is the only alternative to override the class within the android/ folder of the project, to avoid issues with updates to the node_modules content?

@swellingt0n You cannot fix the issue within JS code. Fortunately, you can override the PushNotification java class.

Follow these steps: https://github.com/wix/react-native-notifications/wiki/Android:-Layout-Customization

In MyPushNotification class, override getCTAPendingIntent() method.

public class MyPushNotification extends PushNotification {

    public MyPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) {
        super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper);
    }

    @Override
    protected PendingIntent getCTAPendingIntent() {
        final Intent cta = new Intent(mContext, ProxyService.class);
        return CustomNotificationIntentAdapter.createPendingNotificationIntent(mContext, cta, mNotificationProps);
    }
}

CustomNotificationIntentAdapter class (copy over from the original NotificationIntentAdapter.java and modify createPendingNotificationIntent())

public class CustomNotificationIntentAdapter {
    private static final String PUSH_NOTIFICATION_EXTRA_NAME = "pushNotification";

    public static PendingIntent createPendingNotificationIntent(Context appContext, Intent intent, PushNotificationProps notification) {
        intent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle());
        int uniqueInt = (int) (System.currentTimeMillis() & 0xfffffff);
        return PendingIntent.getService(appContext, uniqueInt, intent, PendingIntent.FLAG_ONE_SHOT);
    }
}

@re7eal Thank you, closing this for now.

Wanted to leave an update for anyone with this issue, finally got around to implementing @re7eal 's solution and it worked perfectly.

Thanks, @re7eal perfect solution!

You may want to read the first paragraphs of the following page before implementing this.

https://developer.android.com/reference/android/app/PendingIntent

From this page "A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent#filterEquals(Intent). If you use two Intent objects that are equivalent as per Intent#filterEquals(Intent), then you will get the same PendingIntent for both of them."

Also "A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it."

My interpretation of this is that your android application is holding onto every "unique" pending intent combination you ever created without cancelling it. This is true even if your applications process is killed and restarted. It may be the case that android has some way of killing the older pending intents after some period of time. I do not know if it does or does not.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fosteruk picture fosteruk  路  5Comments

WhereBeTheDan picture WhereBeTheDan  路  5Comments

veedeo picture veedeo  路  6Comments

Bilal-Abdeen picture Bilal-Abdeen  路  4Comments

puremana picture puremana  路  5Comments