3

I'm trying to detect whether my react-native app was launched by the user tapping a push-notification banner (see this excellent SO answer on the topic).

I've implemented the pattern Mark describes, and have discovered that the "notification" objects being provided by PushNotificationIOS.getInitialNotification are really bizarre, at least in cases when there isn't a notification to retrieve. Detecting this case has been a PITA, and I'm actually quite confused.

From what I can tell, PushNotificationIOS.getInitialNotification returns a promise; this promise is supposed to resolve with either null or an actual notification object -- null when there is no notification waiting for the user. This is the scenario I'm trying to detect and support.

Here's why it's such a pain to detect; the following tests were all run when there is no notification to find:

// tell me about the object
JSON.stringify(notification);
//=> {}

// what keys does it have?
Object.keys(notification);
//=> [ '_data', '_badgeCount', '_sound', '_alert' ]

So it stringifies to empty, but it has four keys? K...

// tell me about the data, then
JSON.stringify(notification._data);
//=> undefined
// wtf?

These bizarre facts frustrate both my understanding and my ability to distinguish between cases where there's an actual notification to react to vs. cases where the mailbox is empty. Based on these facts, I assumed I could test for the members I want, but even the most careful probing produces false positives 100% of the time:

PushNotificationIOS.getInitialNotification()
.then((notification) => {

    // usually there is no notification; don't act in those scenarios
    if(!notification || notification === null || !notification.hasOwnProperty('_data')) {
        return;
    }

    // is a real notification; grab the data and act.

    let payload = notification._data.appName; // TODO: use correct accessor method, probably note.data() -- which doesn't exist
    Store.dispatch(Actions.receivePushNotification(payload, true /* true = app was awaked by note */))
});

Every time I run this code, it fails to trigger the escape hatch and throws on let payload because undefined is not an object (evaluating 'notification._data.appName').

Can someone explain what's going on here? Is PushNotificationIOS.getInitialNotification broken or deprecated? How in JS is it possible to have a key that evaluates to undefined? How can I detect this scenario?

Experienced javascripter, pretty puzzled here. Thanks for any help.

BTW: using react-native v0.29.0

Community
  • 1
  • 1
Tom
  • 8,509
  • 7
  • 49
  • 78

1 Answers1

2

The notification is an instance of PushNotification, not a plain object, that's why it stringifies to an empty object since no custom toString was implemented for it.

It sounds like a bug to me (which should be reported if not already) that the object is created when no notification is available.

Anyway, to workaround this issue, your check should actually be:

if(!notification || !notification.getData()) {
        return;
}

Update: Issue has been fixed in 0.31 - see Github issue for more details.

Mike Grabowski
  • 1,955
  • 16
  • 17
  • Thanks for the explanation! I'm curious how you know that there's no `toString` for `PushNotification`. – Tom Jan 19 '17 at 16:30