Detect if the app was launched/opened from a push notification describes how to detect whether a native iOS app was opened (that is, either launched or merely made active) v
There are two cases here that need to be detected in different ways:
UIApplicationStateInactive
state (or 'background'
state, as React Native's AppStateIOS class calls it).Code to handle both cases (you can put this in your index.ios.js
or somewhere else that's run on app launch):
import React from 'react';
import { PushNotificationIOS, AppState } from 'react-native';
function appOpenedByNotificationTap(notification) {
// This is your handler. The tapped notification gets passed in here.
// Do whatever you like with it.
console.log(notification);
}
PushNotificationIOS.getInitialNotification().then(function (notification) {
if (notification != null) {
appOpenedByNotificationTap(notification);
}
});
let backgroundNotification;
PushNotificationIOS.addEventListener('notification', function (notification) {
if (AppState.currentState === 'background') {
backgroundNotification = notification;
}
});
AppState.addEventListener('change', function (new_state) {
if (new_state === 'active' && backgroundNotification != null) {
appOpenedByNotificationTap(backgroundNotification);
backgroundNotification = null;
}
});
The solution I found for this is a bit hacky and relies on some potentially weird behavior I noticed regarding the order that event handlers fire. The app I have been working on needed the same functionality, to detect specifically when I open the app via a Push Notification.
What I found was that the handler for PushNotificationIOS
fires before the handler for AppStateIOS
What this meant was that, if I persisted the foreground/background state to memory/AsyncStorage, I could just check it like so in the PushNotification event handler: if (activity === 'background')
and if that was true then I knew that I had just opened the app from a Push Notification.
I'm always keeping the AppStateIOS
foreground/background activity in memory and on disk (using redux and redux-persist respectively) so I just check that whenever I need to know.
This may potentially be too hacky for your purposes, and that behavior might change in the future or it could be localized to just me. Try looking at that solution and see what you think.
getInitialNotification
does not work with Local Notifications.Unfortunately, as of 0.28 of React Native, using PushNotificationIOS.getInitialNotification()
always returns a null
value when being launched by a Local Push Notification.
Because of that, you need to catch the push notification as a launchOption
in your AppDelegate.m
and pass it into React Native as an appProperty
.
Here's all that you need to receive a Local Push Notification from a cold launch or from the background/inactive state.
AppDelegate.m
(Native iOS Code)
// Inside of your didFinishLaunchingWithOptions method...
// Create a Mutable Dictionary to hold the appProperties to pass to React Native.
NSMutableDictionary *appProperties = [NSMutableDictionary dictionary];
if (launchOptions != nil) {
// Get Local Notification used to launch application.
UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (notification) {
// Instead of passing the entire Notification, we'll pass the userInfo,
// where a Record ID could be stored, for example.
NSDictionary *notificationUserInfo = [notification userInfo];
[ appProperties setObject:notificationUserInfo forKey:@"initialNotificationUserInfo" ];
}
}
// Your RCTRootView stuff...
rootView.appProperties = appProperties;
index.ios.js
(React Native)
componentDidMount() {
if (this.props.initialNotificationUserInfo) {
console.log("Launched from Notification from Cold State");
// This is where you could get a Record ID from this.props.initialNotificationUserInfo
// and redirect to the appropriate page, for example.
}
PushNotificationIOS.addEventListener('localNotification', this._onLocalNotification);
}
componentWillUnmount() {
PushNotificationIOS.removeEventListener('localNotification', this._onLocalNotification);
}
_onLocalNotification( notification ) {
if (AppState.currentState != 'active') {
console.log("Launched from Notification from Background or Inactive state.");
}
else {
console.log("Not Launched from Notification");
}
}
Make sure to import PushNotificationIOS
and AppState
from react-native
.
I haven't tested this with Remote Push Notifications. Perhaps @MarkAmery's method works just fine with Remote Push Notifications but, unfortunately, as of current state of React Native, this is the only way I was able to get Local Push Notifications from a cold state working.
This is highly undocumented in React Native so I have created an issue on their GitHub repo to draw attention to it and hopefully rectify it. If you're dealing with this, go there and give it a thumbs up so it percolates to the top.
https://github.com/facebook/react-native/issues/8580