Detect whether React Native iOS app was opened via push notification

后端 未结 3 568
栀梦
栀梦 2020-12-13 07:41

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

相关标签:
3条回答
  • 2020-12-13 07:42

    There are two cases here that need to be detected in different ways:

    1. The app has been completely terminated (e.g. by restarting the phone, or by double-tapping home and swiping it off the list of apps running in the background) and is being launched by a user's tap on a push notification. This can be detected (and the notification's data acquired) via the React.PushNotificationIOS.getInitialNotification method.
    2. The app had been suspended and is being made active again by a user's tap on a push notification. Just like in a native app, you can tell that this is happening because iOS passes the tapped notification to your app when it is opening (even if it's an old notification) and causes your notification handler to fire while your app is in 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;
      }
    });
    
    0 讨论(0)
  • 2020-12-13 07:44

    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.

    0 讨论(0)
  • 2020-12-13 08:08

    For Local Notifications

    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

    0 讨论(0)
提交回复
热议问题