Push Notifications Tutorial: Getting Started

Push notifications allow developers to reach users, even when users aren’t actively using an app! In this tutorial, you’ll learn how to configure your app to receive push notifications and to display them to your users or perform other tasks. By Chuck Krutsinger .

4.9 (27) · 2 Reviews

Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Handling Push Notifications

In this section, you’ll learn how to perform actions when your app receives notifications and when users tap them.

Understanding What Happens When You Receive a Push Notification

When your app receives a push notification, iOS calls a method in UIApplicationDelegate.

You’ll need to handle a notification differently depending on what state your app is in when the notification is received:

  • If your app wasn’t running and the user launches it by tapping the push notification, iOS passes the notification to your app in the launchOptions of application(_:didFinishLaunchingWithOptions:).
  • If your app was running either in the foreground or the background, the system notifies your app by calling application(_:didReceiveRemoteNotification:fetchCompletionHandler:). When the user opens the app by tapping the push notification, iOS may call this method again, so you can update the UI and display relevant information.

In the first case, WenderCast will create the news item and open directly to the News tab. In AppDelegate.swift, add the following code to the end of application(_:didFinishLaunchingWithOptions:), just before the return statement:

// Check if launched from notification
let notificationOption = launchOptions?[.remoteNotification]

// 1
if 
  let notification = notificationOption as? [String: AnyObject],
  let aps = notification["aps"] as? [String: AnyObject] {
  // 2
  NewsItem.makeNewsItem(aps)
  
  // 3
  (window?.rootViewController as? UITabBarController)?.selectedIndex = 1
}

This is what you’re doing:

  1. Check whether the value for UIApplication.LaunchOptionsKey.remoteNotification exists in launchOptions. If it does, then your app was launched from a notification. This will contain the push notification payload you sent.
  2. Since the aps dictionary exists, create a NewsItem with it.
  3. Change the selected tab of the tab controller to the News section.

To test this, you need to edit the scheme of WenderCast. First, build and run to install the latest code on the simulator. Then, click the WenderCast scheme and select Edit Scheme…:

Edit the Scheme

Select Run from the sidebar, then in the Info tab select Wait for executable to be launched:

Choose wait for the executable to be launched

This option will make the debugger wait for the app to be launched for the first time after installing to attach to it.

Build and run. Once it’s done installing, send out more breaking news using xcrun simctl as before. Tap the notification, and the app will open to news:

App opened to the news tab

To handle the situation where your app is running when a push notification is received, add the following to AppDelegate:

func application(
  _ application: UIApplication,
  didReceiveRemoteNotification userInfo: [AnyHashable: Any],
  fetchCompletionHandler completionHandler:
  @escaping (UIBackgroundFetchResult) -> Void
) {
  guard let aps = userInfo["aps"] as? [String: AnyObject] else {
    completionHandler(.failed)
    return
  }
  NewsItem.makeNewsItem(aps)
}

This tries to extract the aps from the supplied userInfo object and, if successful, creates a new NewsItem from it.

Since iOS calls this method when the app is running, you need to change the scheme back to launching the app automatically to test it. In the Scheme editor, under Launch, select Automatically.

Build and run. Keep the app running in the foreground and on the News tab. Send another news push notification and watch as it appears in the feed:

Second push notification shown in the news tab

That’s it! Your app now can magically receive breaking news as it happens. :]

Note: Push notifications are not guaranteed to arrive. This is OK for WenderCast, because having the full list of news isn’t too important for this app. In general, though, you should not use push notifications as the only way of delivering content. Instead, push notifications should signal that there is new content available and let the app download the content from the source (for example, from a REST API).

Working With Actionable Notifications

Actionable notifications let you add custom buttons to the notification itself. You might have noticed this on email notifications or Tweets that let you “reply” or “favorite” on the spot.

Your app can define actionable notifications when you register for notifications by using categories. Each category of notification can have a few preset custom actions.

Once registered, your server can set the category of a push notification. The corresponding actions will be available to the user when received.

For WenderCast, you’ll define a News category with a custom action named View. This action will allow users to view the news article in the app if they choose to.

In registerForPushNotifications(), insert the following just below the guard and above the call to getNotificationSettings():

// 1
let viewAction = UNNotificationAction(
  identifier: Identifiers.viewAction,
  title: "View",
  options: [.foreground])

// 2
let newsCategory = UNNotificationCategory(
  identifier: Identifiers.newsCategory,
  actions: [viewAction],
  intentIdentifiers: [],
  options: [])

// 3
UNUserNotificationCenter.current().setNotificationCategories([newsCategory])

Going through this, step-by-step:

  1. Create a new notification action, with the title View on the button, that opens the app in the foreground when triggered. The action has a distinct identifier, which iOS uses to differentiate between other actions on the same notification.
  2. Define the news category, which will contain the view action. This also has a distinct identifier that your payload will need to contain to specify that the push notification belongs to this category.
  3. Register the new actionable notification by calling setNotificationCategories.

Build and run the app to register the new notification settings.

Background the app and then send the following payload via the xcrun simctl utility:

{
  "aps": {
    "alert": "Breaking News!",
    "sound": "default",
    "link_url": "https://raywenderlich.com",
    "category": "NEWS_CATEGORY"
  }
}

When the notification appears, pull down on it to reveal the View action:

Push notification with the view action revealed

Nice! Tapping View will launch WenderCast, but it doesn’t do anything exciting just yet. To get it to display the news item, you need to do some more event handling in the delegate.

Handling Notification Actions

Whenever a notification action gets triggered, UNUserNotificationCenter informs its delegate. Back in AppDelegate.swift, add the following class extension to the bottom of the file:

// MARK: - UNUserNotificationCenterDelegate

extension AppDelegate: UNUserNotificationCenterDelegate {
  func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse,
    withCompletionHandler completionHandler: @escaping () -> Void
  ) {
    // 1
    let userInfo = response.notification.request.content.userInfo
    
    // 2
    if 
      let aps = userInfo["aps"] as? [String: AnyObject],
      let newsItem = NewsItem.makeNewsItem(aps) {
      (window?.rootViewController as? UITabBarController)?.selectedIndex = 1
      
      // 3
      if response.actionIdentifier == Identifiers.viewAction,
        let url = URL(string: newsItem.link) {
        let safari = SFSafariViewController(url: url)
        window?.rootViewController?
          .present(safari, animated: true, completion: nil)
      }
    }
    
    // 4
    completionHandler()
  }
}

This is the callback you get when the app opens because of a custom action. It might look like there’s a lot going on, but there’s not much new here:

  1. Get the userInfo dictionary.
  2. Create a NewsItem from the aps dictionary and navigate to the News tab.
  3. Check the actionIdentifier. If it is the “View” action and the link is a valid URL, it displays the link in an SFSafariViewController.
  4. Call the completion handler the system passes to you.

There is one last bit: You have to set the delegate on UNUserNotificationCenter. Add this line to the top of application(_:didFinishLaunchingWithOptions:):

UNUserNotificationCenter.current().delegate = self

Build and run. Close the app again, then send another news notification with the following payload:

{
  "aps": {
    "alert": "New Posts!",
    "sound": "default",
    "link_url": "https://raywenderlich.com",
    "category": "NEWS_CATEGORY"
  }
}

Pull down the notification and tap the View action, and you’ll see WenderCast present a Safari View controller right after it launches:

Notification link URL opened in a Safari view

Congratulations, you’ve implemented an actionable notification! Send a few more and try opening the notification in different ways to see how it behaves.

Chuck Krutsinger

Contributors

Chuck Krutsinger

Author

Keegan Rush

Author

Mark Powell

Tech Editor

Luke Freeman

Illustrator

Adrian Strahan

Final Pass Editor

Richard Critz

Team Lead

Over 300 content creators. Join our team.