How to add custom actions for iOS push and local notifications
Learn about actionable notifications that allow users to respond without launching the app.
21 Mar 2022 · 4 min read
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.
When using actionable notifications, the iOS system displays one or more buttons in addition to the notification content. They allow the user to respond to a delivered notification without launching the app.

Let's see how to create an actionable notification and handle the user's response.
Creating notification actions
To add actions to a notification, two steps are required.
Creating a category and its actions and registering it with UNUserNotificationCenter at launch time.
Adding the category id to the notification payload.

Step 1: Creating and registering a category and its actions
A notification action is represented by the UNNotificationAction and a category by the UNNotificationCategory type.
let doneAction = UNNotificationAction(identifier: "drinkingReminder.doneAction", title: "Done", options: [])let notThirstyAction = UNNotificationAction(identifier: "drinkingReminder.notThirstyAction", title: "Not thirsty", options: [])let drinkingReminderCategory = UNNotificationCategory(identifier: "drinkingReminderCategory",actions: [doneAction, notThirstyAction],intentIdentifiers: [],options: .customDismissAction)UNUserNotificationCenter.current().setNotificationCategories([drinkingReminderCategory])
In the code above, we create a category with two actions. Then we use the setNotificationCategories method of UNUserNotificationCenter to register the category.
Step 2: Adding the category id to the notification payload
To use the category on a local notification, we set the categoryIdentifier on UNMutableNotificationContent when creating it.
let content = UNMutableNotificationContent()content.title = "Stay hydrated"content.body = "It's time for a glass of water"content.sound = .defaultcontent.categoryIdentifier = "drinkingReminderCategory"
To use the category on a remote notification, the server can include the identifier in the payload.
{"aps" : {"alert" : {"title" : "Stay hydrated","body" : "It's time for a glass of water"},"sound": "default","category" : "drinkingReminderCategory"}}
Handling notification actions
When the user taps one of the notification actions, the iOS app is launched in the background and the delegate method userNotificationCenter(_:didReceive:withCompletionHandler:) is called. Here, we can use response.actionIdentifier to switch through the actions and handle them.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {switch response.actionIdentifier {case "drinkingReminder.doneAction":// Handle actioncase "drinkingReminder.notThirstyAction":// Handle actiondefault:break}completionHandler()}
Beware that there is no possibility to switch between categories, so every action need a unique identifier.
To add more safety to our code, we may extract the ids into enums to avoid dealing with strings in different places.
enum NotificationAction {case drinkingReminderDonecase drinkingReminderNotThirstyvar id: String {switch self {case .drinkingReminderDone:return "tanaschita.notificationAction.drinkingReminder.done"case .drinkingReminderNotThirsty:return "tanaschita.notificationAction.drinkingReminder.notThirsty"}}}
Conclusion
Notification actions provide a great way to allow users to respond to a notification without having to open the app.
One additional thing to consider is that we may not be able to access files on disk while the app is in the background for example when the device is locked. In this case, an additional solution is needed like saving the response temporarily until we get the file access.

Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips