15

I have an app in which I'm trying to receive and handle SILENT push notifications.

I'm registering for APNs as follows:

UNUserNotificationCenter.currentNotificationCenter().delegate = self
UNUserNotificationCenter.currentNotificationCenter().requestAuthorizationWithOptions([.Badge, .Sound, .Alert]) {(granted, error) in
    if granted {
        application.registerForRemoteNotifications()
    }
}

Implemented:

func userNotificationCenter(center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {
    // Handle notification
}

func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
    // Handle notification
}

The app has UIBackgroundModes fetch and remote-notification

The APN content looks like:

{
    "aps":{
        "content-available":1,
        "badge":0
    },
    "action":"shareDelete",
    "shareId":633
}

When the app is in the foreground, userNotificationCenter(centre:withCompletionHandler:willPresentNotification) is fired when the notification is received, but when the app is backgrounded, nothing happens.

I can see the APN is received by changing the badge number, but nothing is triggered in app.

What am I missing?

(Also asked on Apple dev forums)

Ashley Mills
  • 50,474
  • 16
  • 129
  • 160
  • I am unaware of the reason for issue above, But if you are trying to handle SILENT notification you could have used "didReceiveRemoteNotification" delegate method & use "[[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground" to handle it. – Bharath Nov 12 '16 at 07:00
  • This is for iOS 10 - has new delegate methods (right?) – Ashley Mills Nov 14 '16 at 09:53
  • No, I meant that since you want to handle silent notification you can make use of the existing "didReceiveRemoteNotification" and handle it, instead of looking for "willPresentNotification" to handle it in there. – Bharath Nov 14 '16 at 10:15
  • Thanks, but I tried all delegate methods… and none get fired with a silent notification – Ashley Mills Nov 14 '16 at 11:55
  • One last time please try this delegate method "didReceiveRemoteNotification:fetchCompletionHandler:" Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in the foreground, the system calls this method when your app is running in the foreground or background. In addition, if you enabled the remote notifications background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives. – Bharath Nov 14 '16 at 13:48
  • @AshleyMills did you find the problem? I have the same one. I receive normal pushes, but `userNotificationCenter:didReceiveNotificationResponse` isn't called – OgreSwamp Nov 17 '16 at 19:57
  • @AshleyMills any luck with this? – Anchor Dec 31 '16 at 07:09
  • I'm afraid not. – Ashley Mills Dec 31 '16 at 13:09
  • 1
    @AshleyMills This might be late... For an iOS device to receive a silent notification the APN content should not include the 'badge' key? – Ahmed Khedr Mar 04 '17 at 07:06
  • Is the app still running or is it killed? If it's killed it might be delivering the payload in the `launchOptions` dictionary – Lefteris Apr 04 '17 at 16:42
  • @AhmedAbdelHadyKhedr is right, for the APNs to be Silent, it can't contain (badge, sound, alert) on payload. – andrepaulo Nov 08 '17 at 14:47

4 Answers4

5

Method

func userNotificationCenter(center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {
    // Handle notification
}

called when user taps on notification or check it on Apple Watch:

Called to let your app know which action was selected by the user for a given notification.

You need to implement the old method

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

}
OgreSwamp
  • 4,602
  • 4
  • 33
  • 54
  • 3
    This is confusing from Apple. They replaced most of the previous framework but still decided to keep this one last old delegate method. I guess there focus was for when there's a user interaction... – mfaani Jun 14 '17 at 20:10
0
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
NSLog(@"%@",center.delegate);

Checkout if the center.detegate is still AppDelegate, in my case, it was changed to something like X****Delegate, so, willPresentNotification and didReceiveNotificationResponse were never called.

Stanislav Ivanov
  • 1,854
  • 1
  • 16
  • 22
罗大满
  • 31
  • 4
-1

Are you setting minimumBackgroundFetchInterval? As mentioned in the docs:

The minimum number of seconds that must elapse before another background fetch can be initiated. This value is advisory only and does not indicate the exact amount of time expected between fetch operations.

The default fetch interval for apps is UIApplicationBackgroundFetchIntervalNever. Therefore, you must call this method and set a fetch interval before your app is given background execution time.

So if you're not setting this it's quite possible your fetch handler will never be called in the background.

Community
  • 1
  • 1
mcknut
  • 113
  • 1
  • 7
-3

When your application is in the background or not running the only way for your app to be notified is if the user select an action linked to to your notification.

See Local and remote notifications guide.

When your app is not running or is in the background, the system automatically delivers local and remote notifications using the interactions you specified. If the user selects an action, or chooses one of the standard interactions, the system notifies your app of the user’s selection. Your code can then use that selection to perform additional tasks. If your app is running in the foreground, notifications are delivered directly to your app. You can then decide whether to handle the notification quietly or alert the user.

To respond to the delivery of notifications, you must implement a delegate for the shared UNUserNotificationCenter object. Your delegate object must conform to the UNUserNotificationCenterDelegate protocol, which the notification center uses to deliver notification information to your app. A delegate is required if your notifications contain custom actions.

here is the source: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/SchedulingandHandlingLocalNotifications.html#//apple_ref/doc/uid/TP40008194-CH5-SW14

Community
  • 1
  • 1
  • 1
    This is incorrect. "Silent" push notifications can be delivered that require no user interaction… https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW1 – Ashley Mills Apr 05 '17 at 14:21
  • Yes it is delivered but handle by the system. your app is not notify until the user select an action – Fitzgerald Muiseroux Apr 05 '17 at 14:23
  • 1
    Again, this is incorrect. "silent" notifications should be delivered to the app without user interaction (that's why they are silent) Please follow the link in my previous comment. – Ashley Mills Apr 05 '17 at 14:25
  • Sorry that but this is not my invention. don't be so stubborn and read the doc for a second – Fitzgerald Muiseroux Apr 05 '17 at 14:27
  • see the related issue http://stackoverflow.com/questions/14616261/receiving-push-notifications-while-in-background – Fitzgerald Muiseroux Apr 05 '17 at 14:42
  • 1
    Can confirm: Fitzgerald, despite his accusations that the other here is stubborn, is wrong. Totally wrong. Nice one dude. – mxcl Apr 19 '17 at 12:14