Local Notifications: Getting Started
Learn how to create notifications by time intervals, time of day and location, as well as how to support category grouping and prompting for action. By Vidhur Voora.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Local Notifications: Getting Started
25 mins
- Getting Started
- Introducing Notifications
- Requesting Notification Permission
- Prompting Notification Authorization
- Understanding Critical Notifications
- Creating Notifications
- Triggering TimeInterval Notifications
- Scheduling the Notification
- Viewing Notification When the App Is in the Foreground
- Removing Scheduled Notifications
- Triggering Calendar Notifications
- Triggering Location Notifications
- Creating a Location Trigger
- Grouping Notifications
- Handling Notification Actions
- Declaring Category and Creating Actions
- Assigning Identifiers to Notification Payload
- Handling Actions
- Where to Go From Here?
Grouping Notifications
By default, you group all an app’s notifications based on the app’s bundle identifier. However, you can create custom groups for your app. A good example of this is a messaging app that groups the notifications for different message groups.
For OrganizerPlus, you’ll group notifications based on the trigger type.
Open NotificationManager.swift and add the following before NotificationManager
:
enum NotificationManagerConstants {
static let timeBasedNotificationThreadId =
"TimeBasedNotificationThreadId"
static let calendarBasedNotificationThreadId =
"CalendarBasedNotificationThreadId"
static let locationBasedNotificationThreadId =
"LocationBasedNotificationThreadId"
}
Here, you define the constants you’ll use to group the notifications based on the notification trigger type.
Find switch task.reminder.reminderType
in scheduleNotification(task:)
. Add the identifier for each case by setting threadIdentifier
for the notification content, as shown below:
switch task.reminder.reminderType {
case .time:
content.threadIdentifier =
NotificationManagerConstants.timeBasedNotificationThreadId
// ...
case .calendar:
content.threadIdentifier =
NotificationManagerConstants.calendarBasedNotificationThreadId
// ...
case .location:
content.threadIdentifier =
NotificationManagerConstants.locationBasedNotificationThreadId
// ...
}
threadIdentifier
helps group related notifications. Here, you set the identifier for the notification content based on reminderType
.
Build and run.
Create a few tasks with different triggers. When the notifications appear, you’ll see them grouped based on the type of trigger.
You can choose to turn off notification grouping for an app. To do so:
- Go to Settings ▸ Select the app.
- Tap Notifications.
- Tap Notification Grouping.
- Set grouping to Off.
This turns off grouping. The notifications will appear in the order they’re received.
Tapping a notification opens the app. Is there a way to act on a notification without opening the app? You’ll explore that next.
Handling Notification Actions
Actionable notifications allow the user to perform actions on a notification without opening the app. An actionable notification can display one or more buttons in addition to the content.
To support actionable notifications, you’ll need to:
- Declare the notification category at the launch of the app.
- Create and assign actions to the notification category.
- Assign the category identifiers to the notification payload.
- Handle the registered actions.
You’ll implement each of these next.
Declaring Category and Creating Actions
Open AppDelegate.swift. Then, add the following to configureUserNotifications()
below UNUserNotificationCenter.current().delegate = self
:
// 1
let dismissAction = UNNotificationAction(
identifier: "dismiss",
title: "Dismiss",
options: [])
let markAsDone = UNNotificationAction(
identifier: "markAsDone",
title: "Mark As Done",
options: [])
// 2
let category = UNNotificationCategory(
identifier: "OrganizerPlusCategory",
actions: [dismissAction, markAsDone],
intentIdentifiers: [],
options: [])
// 3
UNUserNotificationCenter.current().setNotificationCategories([category])
Here’s a step-by-step breakdown:
-
You declare two actions:
dismissAction
andmarkAsDone
. These will display as action buttons with the notification. Each instance ofUNNotificationAction
has an identifier, title and array of options. Theidentifier
uniquely identifies the action. Thetitle
represents the text on the button.options
denotes the behavior associated with the action. The different options are:- authenticationRequired: A user can perform this action only when the device is unlocked. If the device is locked, the system prompts the user to unlock it.
- destructive: This action performs a destructive task. The button for this option displays with special highlighting.
- foreground: This option causes the app to launch in the foreground.
- Here, you define a notification category.
UNNotificationCategory
defines the type of notifications an app can receive.identifier
uniquely identifies the category.intentIdentifiers
let the system know that the notification relates to a request made by Siri. The options denote how to handle the notifications associated with them. You can learn more about them Apple developer documentation. - Here, you register the new actionable notification.
Now the system knows about your notification category and which actions it has, but an app may have more than one category for notifications and not every category will have actions assigned to it. To let the system know that it should show your actions, you must assign your notifications to this category.
Assigning Identifiers to Notification Payload
Open NotificationManager.swift. Then, add the following in scheduleNotification(task:)
below content.body = "Gentle reminder for your task!"
:
content.categoryIdentifier = "OrganizerPlusCategory"
let taskData = try? JSONEncoder().encode(task)
if let taskData = taskData {
content.userInfo = ["Task": taskData]
}
Here, you set the notification content’s categoryIdentifier
to the identifier you used when you created the instance of UNNotificationCategory
. Then, you encode the task data and assign it to the notification content’s userInfo
. The app will be able to access this content when a user acts on the notification.
Handling Actions
Open AppDelegate.swift. Add the following to the AppDelegate
extension:
// 1
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
// 2
if response.actionIdentifier == "markAsDone" {
let userInfo = response.notification.request.content.userInfo
if let taskData = userInfo["Task"] as? Data {
if let task = try? JSONDecoder().decode(Task.self, from: taskData) {
// 3
TaskManager.shared.remove(task: task)
}
}
}
completionHandler()
}
Here’s a code breakdown:
- iOS calls
userNotificationCenter(_:didReceive:withCompletionHandler:)
when the user acts on the notification. - Check if the response’s
actionIdentifier
is set tomarkAsDone
. Then, you decode the task fromuserInfo
. - After the decode succeeds, you remove the task using the shared instance of the
TaskManager
.
Build and run.
Create a task by selecting the time trigger. Long-press the notification when it appears. You’ll see two buttons with the notification. Tap the Mark as Done button. The task is removed without opening the app.
Great job! You’ve now become a pro in local notifications.
Where to Go From Here?
Download the project by clicking the Download Materials button at the top or bottom of this page.
In this tutorial, you’ve learned to create, schedule, group and handle local notifications. You can customize the appearance of notifications using a Notification Content Extension. Push Notifications Tutorial for iOS: Rich Push Notifications covers that in detail.
I hope you’ve enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below.