Quick guide on local notifications for iOS
Learn how to schedule local notifications in different ways and how to handle them.
iOS local and push notifications allow us to keep users up to date or get reminded of time or location sensitive events, even if the app is running in the background or is inactive.
While remote push notifications are send by a server using the Apple Push Notification Service, local notifications are fully controlled and send by the app itself. Both notification types are configured by using the UserNotifications framework.
In this guide, we are going to look at how local notifications work, how to ask user’s permission, how to schedule them in different ways and how to handle them.
Get user’s permission
As a first step, we need to ask for the user’s permission to send notifications, for example on app start or when the user activates or starts using a certain feature.
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in}
As options, the requestAuthorization method takes an UNAuthorizationOptions type.
With [.alert, .badge, .sound], we ask for the ability to display alerts, to update the app’s badge and to play sounds.
There are more options available. For example, we could ask for a criticalAlert permission which would require a special entitlement issued by Apple because they bypass the device’s mute and do not disturb settings. Or for the option .carPlay to display notifications in a CarPlay environment.
Create the content of a local notification
After asking for permission, the first step to send a local notification is to create its content. The content of a local notification is represented by the UNMutableNotificationContent type.
let content = UNMutableNotificationContent()content.title = "Stay hydrated"content.body = "It's time for a glass of water"content.sound = UNNotificationSound(named: UNNotificationSoundName("water.wav"))
In the above example, we set the title, body and sound properties. For a native sound, we could just set it to .default.
There are more options available. For example the badge property that specifies the number to apply to the app’s icon when the notification arrives. Or the threadIdentifier property to group notifications visually. We could also set the userInfo dictionary to add some custom data we can use later when handling the notification. Checkout the UNMutableNotificationContent type for a full list of configuration possibilities.
Schedule a local notification
The second step is to schedule the local notification. The following triggers are available:
- UNCalendarNotificationTrigger — triggers the notification at a certain date or or time.
- UNTimeIntervalNotificationTrigger — triggers the notification after a certain number of seconds elapses.
- UNLocationNotificationTrigger — triggers the notification when the user enters or exits a region.
The following calendar trigger example triggers the notification every morning at 7:30.
var dateComponents = DateComponents()dateComponents.hour = 7dateComponents.minute = 30let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
The following time interval trigger example triggers the notification in 10 minutes from now.
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10*60, repeats: false)
The following location trigger example triggers the notification when the user exits a radius of 20km around Leipzig’s city center.
let center = CLLocationCoordinate2D(latitude: 51.3396955, longitude: 12.3730747)let region = CLCircularRegion(center: center, radius: 20*1000, identifier: "leipzig")region.notifyOnEntry = falseregion.notifyOnExit = truelet trigger = UNLocationNotificationTrigger(region: region, repeats: false)
With the notifyOnEntry and notifyOnExit properties, we specify whether the app should deliver notifications on entry, exit or both.
Register a notification request
With content and trigger of the notification created, we can now register a notification request.
let id = UUID().uuidStringlet request = UNNotificationRequest(identifier: id, content: content, trigger: trigger)UNUserNotificationCenter.current().add(request) { error in if let error = error { // handle error }}
The adding the request to UNUserNotificationCenter, it schedules the local notification for delivery.
The identifier parameter allows us to edit or cancel a specific notification request when the conditions change or we no longer need to notify the user.
Note — the method above is also available as an asynchronous method func add(_ request: UNNotificationRequest) async throws that we can use when preferring working with async/await.
Cancel a notification request
To cancel a specific request, we pass the id we used when creating it.
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [id])
To remove all pending requests, the notification center provides the method removeAllPendingNotificationRequests().
Receiving notifications when the app is in the foreground
When the app is running in the foreground, the notification will not be shown to the user by default.
To show the notification anyway, we can use UNUserNotificationCenterDelegate that notifies us when the notification is about to be presented.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { UNUserNotificationCenter.current().delegate = self return true}func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.alert, .badge, .sound])}
Calling the completionHandler will show the notification based on the UNNotificationPresentationOptions parameter we pass in indicating how to present a notification in a foreground app.
Instead of showing the notification, we could also implement a custom solution for example to show an app dialog that makes more sense for this specific use case.
Handle notification actions
In case the app is not in the foreground, the system shows the notification to the user. When the user taps on the delivered notification, the delegate method userNotificationCenter(_:didReceive:withCompletionHandler:) is called.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo // Handle notification completionHandler()}
Here, we could for example use the userInfo to trigger certain flows or to show information or screens related to the notification.
Originally published at https://tanaschita.com.