Push Notification Basics (2 of 2)

Tim Johnson
Swifty Tim
Published in
5 min readAug 27, 2017

I finished my last article wrapping up how to configure your app for receiving push notifications, but I didn’t discuss what you can do with those notifications once they arrive.

So here we go.

Sending push notifications to your device really isn’t all that helpful unless you can respond to those push notifications. That’s what I’m going to walk you through today. Specifically, the following:

  1. Responding to a user action on a push notification
  2. Handling push notifications in the foreground
  3. Handling push notifications in the background

1 and 2 are both handled by UNUserNotificationCenter where 3 is strictly handled by the UIApplicationDelegate.

Responding to a user action on a push notification

UNUserNotificationCenter is a pretty powerful API in that it allows you to schedule local notifications, configure push notification actions, and interact with a user’s action on a push notification. iOS has come a long way with notifications, and this is just another layer that’s helped developers build a wonderful experience.

We’re just going to focus on responding to a user action.

When a push notification is sent to a device, something like this shows up

The user has the option to either swipe right and open the push notification, or swipe left and view some options.

Regardless of what the user does, your application will handle it exactly the same. UNUserNotificationCenter has a protocol — UNUserNotificationCenterDelegate — with the method userNotificationCenter(didReceive: withCompletionHandler:) . This is where the entry point into the application will occur.

There are a few things to notice here. Firstly, we’re interacting with a UNNotificationResponse . This is nice because the response object provides both an action identifier and a UNNotification object.

The notification object is where we get the payload. The action identifier is what tells you how the user interacted with the notification. The action identifier is only significant if you have implemented any custom actions for your notification. This is all the information you need in order to do any processing before the user enters the application. This processing can range from displaying the proper view in the application, to updating state, to firing off a something in the network.

The next thing to note is the completion handler. After all the previously mentioned processing, it is then necessary to call this completion handler. It lets the system know that the app is ready for the user.

Handling push notifications in the foreground

The second method in the UNUserNotificationCenterDelegate is userNotificationCenter(willPresent:withCompletionHandler:).

The important thing to note about this method is that it is only called when receiving a push notification in the foreground. The nifty drop down alert you get from iMessage when you’re browsing another message, this is where that gets handled. Depending on the notification, you can either decide to display an alert , badge , or a sound that the user can interact with.

Of course, before you can expect to get either of these callbacks, you’re going to need to register as the delegate of the UNUserNotificationCenter . As Apple states

You must assign your delegate object to the UNUserNotificationCenter object no later than before your app finishes launching.

So you can easily throw this code

UNUserNotificationCenter.current().delegate = self

into your app delegate.

That might not be the best practice though, as it is nice to keep most things out of the app delegate. So I personally suggest creating another object. Lets make an ApplicationLaunchHandler to handle all of the UNUserNotificationCenter logic

Application Launch Handler

and keep a reference to it from the app delegate.

That’s really all you need to do do start responding to push notifications while the app is in the foreground, or when the application is moving into the foreground.

Handling push notifications in the background

The single shortcoming of UNUserNotificationCenter is the fact that it doesn’t handle any push notification logic while the app is in the background.

Instead, all of the background processing of push notifications is handled in the UIApplicationDelegate .

Before we get to the actual callbacks themselves, there are two necessary components to responding to notifications in the background.

  1. Enabling remote(push) notifications in the background.
  2. Setting the content-available flag in the notification payload to 1

Without enabling background remote notifications, whenever your application receives a push notification while it isn’t active, it will not wake up to respond to the notification. So if you want to do any processing of notifications while your app is

  1. In the background;
  2. Been killed by the system (doesn’t wake up if killed by the user);

you must enable remote-notifications in the background.

It’s a pretty simple flag that you need to set in your project’s capabilities

Allow the remote notification background mode

With this enabled, we’re now able to respond to remote notifications in the background.

Setting the content-available flag in the notification payload to 1 lets your application know that there is information to process, and it will trigger the necessary app delegate callback method.

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

Unlike the UNNotificationResponse object we get with the UNUserNotificationCenterDelegate , we are given the barebones payload [AnyHashable: Any] here instead. The user hasn’t interacted with the push notification yet, so an action identifier would be irrelevant.

We are, however, given the completionHandler . This completion handler is again used to let the system know that any processing has finished. This is important for the system so it can either

  1. Kill the application again
  2. Keep the application in the background, but reducing the amount of resources allocated towards the application

which helps the battery last longer, the system remain efficient, yada yada yada.

The difference between this completion handler and the user notification completion handler is its signature. The completion handler here takes a UIBackgroundFetchResult which can be either noData , newData , or failed . This makes it quite clear that the processing should be a quick networking call to make any updates, as the application doesn’t have much time for activity (in fact I believe it is ~30 seconds).

The main motivation behind background remote notifications is so when a user enters “multitasking” mode, they can view each application in its most up-to-date state. To be honest, this makes a fairly nice user experience ;).

The background remote notification processing shouldn’t be confused with background fetching, which is an entirely different aspect of work in the background. I will have a post specifically about background fetching in the future.

Hope you found this a good read! More treats coming soon!

--

--