As of iOS 10, UILocalNotification
is deprecated. Scheduling and handling local notifications is now the responsibility of the User Notifications framework, a brand new framework that is much more capable than the UILocalNotification
class.
In this tutorial, I show you how to use the User Notifications framework to schedule and handle local notifications.
Project Setup
I don't want to overload you with theory. Instead, we are going to build a small application that schedules and displays local notifications. Open Xcode and create a new project based on the Single View Application template.
Name the project LocalNotifications, set Language to Swift, and Devices to iPhone.
Creating the User Interface
The idea is simple. When the user taps a button, a local notification is scheduled with a time interval. Open ViewController.swift and create an action. You can leave the implementation empty for now.
import UIKit
class ViewController: UIViewController {
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Actions
@IBAction func didTapButton(sender: UIButton) {
}
}
Open Main.storyboard and add a button to the View Controller Scene. Set the title of the button and connect the Touch Up Inside event to the didTapButton(sender:)
action.
Revisit ViewController.swift and add an import statement for the User Notifications framework. We are ready to start working with the User Notifications framework.
import UIKit
import UserNotifications
class ViewController: UIViewController {
...
}
Inspecting the Application's Notification Settings
In the early days of iOS, an application could schedule local notifications without the user's consent. In iOS 8, Apple introduced registerUserNotificationSettings(_:)
to request the user's permission to display local and remote notifications or update the application's badge number. Even though the User Notifications framework changes the flow once more, the result is a concise interface with a few additional features that you are certainly going to appreciate.
When the user taps the button of the view controller, we need to ask the User Notifications framework whether the application has the permission to display notifications, local and remote. The framework doesn't make a distinction between local and remote notifications. That is a good thing as it greatly simplifies notification handling.
The class we need to interact with to obtain this information is the UNUserNotificationCenter
class. The current()
class method gives us access to the shared UNUserNotificationCenter
instance. We ask it for the notification settings by invoking getNotificationSettings(completionHandler:)
. The method accepts a completion handler with one parameter, an instance of the UNNotificationSettings
class. This is what the didTapButton(sender: UIButton)
action should look like.
@IBAction func didTapButton(sender: UIButton) {
// Request Notification Settings
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
// Request Authorization
case .authorized:
// Schedule Local Notification
case .denied:
print("Application Not Allowed to Display Notifications")
}
}
}
Why do we ask for the notification settings of the application? We do this to determine if the application previously requested the user's permission. With the UNNotificationSettings
class, Apple has given developers more insight into the user's notification settings of your application.
The property we are interested in is the authorizationStatus
property. It tells us if the application previously prompted the user for permission to display notifications. If the value of authorizationStatus
is equal to notDetermined
, we first need to request the user's permission. If the application was already granted permission to display notifications, we can go ahead and schedule a local notification.
Requesting Authorization
To request authorization for displaying notifications, we make use of a helper method, requestAuthorization(completionHandler:)
. The method accepts a completion handler with one parameter, a boolean that indicates whether the application was granted permission to display notifications.
@IBAction func didTapButton(sender: UIButton) {
// Request Notification Settings
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
self.requestAuthorization(completionHandler: { (success) in
guard success else { return }
// Schedule Local Notification
})
case .authorized:
// Schedule Local Notification
case .denied:
print("Application Not Allowed to Display Notifications")
}
}
}
The implementation of requestAuthorization(completionHandler:)
is not difficult. We ask the user's permission by invoking requestAuthorization(options:completionHandler:)
on the shared user notification center. The method defines two parameters:
- a set of options that defines what type of notifications the application would like to display
- a completion handler that tells the application the result of the request
// MARK: - Private Methods
private func requestAuthorization(completionHandler: @escaping (_ success: Bool) -> ()) {
// Request Authorization
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
completionHandler(success)
}
}
The set of options can include the following values:
badge
: update the application's badge numbersound
: play sound when a notification arrivesalert
: display notificationscarPlay
: display notifications in a CarPlay environment
The UNNotificationSettings
class lets your inspect the permissions for your application. For example, you can ask the User Notifications framework if your application can update the badge number by asking the UNNotificationSettings
instance for the value of its badgeSetting
property.
Scheduling a Notification
We can now schedule a local notification. Update the didTapButton(sender:)
action as shown below. We implement the scheduleLocalNotification()
method in a moment.
@IBAction func didTapButton(sender: UIButton) {
// Request Notification Settings
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
self.requestAuthorization(completionHandler: { (success) in
guard success else { return }
// Schedule Local Notification
self.scheduleLocalNotification()
})
case .authorized:
// Schedule Local Notification
self.scheduleLocalNotification()
case .denied:
print("Application Not Allowed to Display Notifications")
}
}
}
The API for scheduling a local notification may seem a bit daunting at first glance, but it offers a lot of power and flexibility. This is what the implementation of the scheduleLocalNotification()
method looks like.
private func scheduleLocalNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Cocoacasts"
notificationContent.subtitle = "Local Notifications"
notificationContent.body = "In this tutorial, you learn how to schedule local notifications with the User Notifications framework."
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "cocoacasts_local_notification", content: notificationContent, trigger: notificationTrigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
We first define the content of the local notification by creating an instance the UNMutableNotificationContent
class and populating it with data. As of iOS 10, you can define a title as well as a subtitle.
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Cocoacasts"
notificationContent.subtitle = "Local Notifications"
notificationContent.body = "In this tutorial, you learn how to schedule local notifications with the User Notifications framework."
Next, we need to create a trigger for the local notification. As the name implies, we need to tell the User Notifications framework when the local notification should be shown.
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
In this example, we use an instance of the UNTimeIntervalNotificationTrigger
class. We tell the User Notifications framework that the local notification should be displayed ten seconds from now and we don't want to repeat the local notification.
There are several other triggers. You can show the local notification on a particular date and time (UNCalendarNotificationTrigger
) or you can show the local notification when the user's device enters a geofence (UNLocationNotificationTrigger
) by defining a region, an instance of the CLRegion
class.
To schedule the local notification, we create a notification request, an instance of the UNNotificationRequest
class. Each notification request has an identifier, content, and a trigger.
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "cocoacasts_local_notification", content: notificationContent, trigger: notificationTrigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
The request is added to the shared user notification center by invoking add(_:withCompletionHandler:)
. This method accepts the notification request and a completion handler. The completion handler informs the application about the result of the operation.
Implementing the Delegate Protocol
If you run the application, you won't see a local notification pop up as long as the application is in the foreground. Why is that? The UNUserNotificationCenter
class defines the UNUserNotificationCenterDelegate
protocol. This protocol gives your application even more control over how the local notification is handled.
Start by making the ViewController
class the delegate of the shared user notification center. Update the viewDidLoad()
method as shown below.
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// Configure User Notification Center
UNUserNotificationCenter.current().delegate = self
}
Next, create an extension for the ViewController
class in ViewController.swift. We only need to implement one method.
extension ViewController: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
}
The userNotificationCenter(_:willPresent:withCompletionHandler:)
method is invoked when a local notification arrives and the application is in the foreground. To display the local notification when the application is in the foreground, we need to invoke the completion handler and pass in a set of presentation options (UNNotificationPresentationOptions
). The options determine how the local notification is displayed. In the example, we tell the User Notifications framework to display the local notification (.alert
).
If you run the application and tap the button, you should see a local notification appear after ten seconds.
If you pull down the local notification, you can see more details of the local notification.
Note that userNotificationCenter(_:willPresent:withCompletionHandler:)
is only invoked if your application is in the foreground. If your application is in the background, the local notification behaves as defined by the notification's content and the user's notification settings.
Handling the Notification
In the userNotificationCenter(_:willPresent:withCompletionHandler:)
and userNotificationCenter(_:didReceive:withCompletionHandler:)
methods of the UNUserNotificationCenterDelegate
protocol, you decide how the application responds to the notification. Both methods hand you the notification object, an instance of the UNNotification
class. This class gives you access to the notification request (UNNotificationRequest
) that was used to add the notification.
let notificationRequest = notification.request
You can use the identifier of the notification request to determine what action the application should take in response to the notification. This also applies to remote notifications and it adds a lot of flexibility to local and remote notifications.
What's Next
In the next tutorial, I show you how to add actions to a notification. You can download the source files of this tutorial from GitHub.