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.

5 (9) · 1 Review

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

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.

Grouped Notifications

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:

  1. Go to Settings ▸ Select the app.
  2. Tap Notifications.
  3. Tap Notification Grouping.
  4. 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:

  1. Declare the notification category at the launch of the app.
  2. Create and assign actions to the notification category.
  3. Assign the category identifiers to the notification payload.
  4. 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:

  1. You declare two actions: dismissAction and markAsDone. These will display as action buttons with the notification. Each instance of UNNotificationAction has an identifier, title and array of options. The identifier uniquely identifies the action. The title 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.
  2. 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.
  3. 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:

  1. iOS calls userNotificationCenter(_:didReceive:withCompletionHandler:) when the user acts on the notification.
  2. Check if the response’s actionIdentifier is set to markAsDone. Then, you decode the task from userInfo.
  3. After the decode succeeds, you remove the task using the shared instance of the TaskManager.

Build and run.

Handling Notification Actions

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.