iOS: Push notifications, UIApplicationStateInactiv

2019-04-28 14:35发布

问题:

According to the Apple Docs, in order to find out if a user tapped on your push notification you are supposed to check the applicationState in application:didReceiveRemoteNotification:

If the value is UIApplicationStateInactive, the user tapped the action button; if the value is UIApplicationStateActive, the application was frontmost when it received the notification.

I have found that this is not always true. For example:

Double-tap the home button to reveal the system tray and enter "fast app switching mode", your application slides up to reveal other running applications and your app is put into the inactive state (even though it's still mostyle visible). If you receive a push notification in this mode your app delegate will still receive the application:didReceiveRemoteNotification: and at this point your applicationState is UIApplicationStateActive. According to the docs you should treat it like the user tapped the alert... but in this case they didn't. Not only that, the user didn't even see the push notification (possibly because the top of your application is cut off in this mode).

Does anyone know of a way to detect being in 'fast app switching mode' or handle the notification correctly?

回答1:

I was able to fix it myself with some nifty checks...

Essentially the key to this whole thing is

-(void)applicationDidEnterBackground:(UIApplication *)application;

This method isn't called when you enter fast app switching (or control center) so you need to setup a check based on it.

@property                     BOOL isInBackground;
@property (nonatomic, retain) NSMutableArray *queuedNotifications;

And when you receive a notification...

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
 UIApplicationState appState = application.applicationState;
 // Check if we're in this special state. If so, queue the message up
 if (appState == UIApplicationStateInactive && !self.isInBackground) {
    // This is a special case in which we're in fast app switching or control center
    if (!self.queuedNotifications) {
        self.queuedNotifications = [NSMutableArray array];
    }

    // Queue this to show when we come back
    [self.queuedNotifications addObject:userInfo];
 }
}

And then when we come back...

- (void)applicationDidBecomeActive:(UIApplication *)application {
     application.applicationIconBadgeNumber = 0;


 if (!self.isInBackground) {
    // Show your notifications here

    // Then make sure to reset your array of queued notifications
    self.queuedNotifications = [NSMutableArray array];
 }
}

One more thing you may want to do is check for this special case of going to fast app switching and the user going somewhere else. I do this just before setting the isInBackground BOOL. I choose to send them as local notifications

-(void)applicationDidEnterBackground:(UIApplication *)application {

  for (NSDictionary *eachNotification in self.queuedNotifications) {
     UILocalNotification *notification = [self convertUserInfoToLocalNotification:eachNotification];
     [[UIApplication sharedApplication] scheduleLocalNotification:notification];
 }
 self.queuedNotifications = [NSMutableArray array];
 self.isInBackground = YES;
}