Article

Declaring Your Actionable Notification Types

Differentiate your notifications and add action buttons to the notification interface.

Overview

Actionable notifications let the user respond to a delivered notification without launching the corresponding app. Other notifications display information in a notification interface, but the user's only course of action is to launch the app. For an actionable notification, the system displays one or more buttons in addition to the notification interface. Tapping a button sends the selected action to the app, which then processes the action in the background.

Figure 1

Displaying the actions for a notification

A notification for a meeting app contains an invitation along with buttons for accepting or declining the invitation.

To support actionable notifications, you must:

  • Declare one or more notification categories at launch time from your iOS app.

  • Assign appropriate actions to your notification categories.

  • Handle all actions that you register.

  • Assign category identifiers to notification payloads when generating notifications.

Declare Your Custom Actions and Notification Types

Because your app must handle all actions, you must declare the actions that your app supports at launch time. You declare actions using a combination of category and action objects. UNNotificationCategory objects define the types of notifications that your app supports, and UNNotificationAction objects define the buttons to display for each type. For example, a notification for a meeting invitation might include buttons to accept or reject the invitation.

Each UNNotificationCategory object has a unique identifier and options for how you want to handle notifications of that type. The string in the identifier property is the most important part of the category object. When generating notifications, you must include the same string in your notification's payload. The system uses that string to locate the corresponding category object and any actions.

To associate actions with a notification category, assign one or more UNNotificationAction objects to it. Each action object contains the localized string to display to the user and options indicating how you want that action handled. For example, when you tag an action as destructive, the system displays it with a different highlight to indicate its behavior.

Listing 1 shows how to register a custom category with two actions. In addition to a title and options, each action has a unique identifier. When the user selects the action, the system passes that identifier to your app.

Listing 1

Registering actions and notification types

// Define the custom actions.
let acceptAction = UNNotificationAction(identifier: "ACCEPT_ACTION",
      title: "Accept", 
      options: UNNotificationActionOptions(rawValue: 0))
let declineAction = UNNotificationAction(identifier: "DECLINE_ACTION",
      title: "Decline", 
      options: UNNotificationActionOptions(rawValue: 0))
// Define the notification type
let meetingInviteCategory = 
      UNNotificationCategory(identifier: "MEETING_INVITATION",
      actions: [acceptAction, declineAction], 
      intentIdentifiers: [], 
      hiddenPreviewsBodyPlaceholder: "",
      options: .customDismissAction)
// Register the notification type.
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.setNotificationCategories([meetingInviteCategory])

Most actions simply result in a user selection, but text input actions also let the user type custom text-based responses. Your app can then incorporate the user's typed response into your handling of the action. For example, a messaging app could send the typed text as the response to an incoming message. To create a text input action, create a UNTextInputNotificationAction object instead of a UNNotificationAction object. When the user taps the button for a text input action, the system displays an editable text field. When reporting the action to your app, the system includes the text that the user typed as part of the response.

Include a Notification Category in the Payload

The system displays actions only for notifications whose payload contains a valid category identifier string. The system uses the category identifier to look up your app's registered categories and their associated actions. It then uses that information to add the action buttons to the notification interface.

To assign a category to a local notification, assign the appropriate string to the categoryIdentifier property of your UNMutableNotificationContent object. Listing 2 shows the creation of the content for a local notification. In addition to the basic information, this code also adds custom data to the notification's userInfo dictionary, which it uses later to process the invitation.

Listing 2

Assigning a category to a local notification

let content = UNMutableNotificationContent()
content.title = "Weekly Staff Meeting"
content.body = "Every Tuesday at 2pm"
content.userInfo = ["MEETING_ID" : meetingID, 
                    "USER_ID" : userID ]
content.categoryIdentifier = "MEETING_INVITATION"

To add a category identifier to a remote notification, include the category key in the aps dictionary of your JSON payload, as shown in Listing 3. Set the value of this key to the appropriate category string. In the example, the category is set to the same meeting invitation category that was previously defined. As in the local notification example, the payload includes custom keys with the meeting ID and user ID, which are put into the payload's userInfo dictionary. The app can use that information to accept or decline the invitation.

Listing 3

Assigning a category to a remote notification

{
   “aps” : {
      “category” : “MEETING_INVITATION”
      “alert” : {
         “title” : “Weekly Staff Meeting”
         “body” : “Every Tuesday at 2pm”
      },
   },
   “MEETING_ID” : “123456789”,
   “USER_ID” : “ABCD1234”

} 

Handle the Selected Action

Your app must handle all of the actions that it defines. When the user selects an action, the system launches your app in the background and notifies the shared UNUserNotificationCenter object, which notifies its delegate. Use your delegate object's userNotificationCenter(_:didReceive:withCompletionHandler:) method to identify the selected action and provide an appropriate response.

Listing 4 shows an implementation of the delegate method for an app that manages meeting invitations. The method uses the actionIdentifier property of the response to determine whether to accept or decline a given invitation. It also relies on custom data from the notification payload to process the notification successfully. Always call the completion handler after you finish handling the action.

Listing 4

Performing a selected action

func userNotificationCenter(_ center: UNUserNotificationCenter,
       didReceive response: UNNotificationResponse,
       withCompletionHandler completionHandler: 
         @escaping () -> Void) {
       
   // Get the meeting ID from the original notification.
   let userInfo = response.notification.request.content.userInfo
   let meetingID = userInfo["MEETING_ID"] as! String
   let userID = userInfo["USER_ID"] as! String
        
   // Perform the task associated with the action.
   switch response.actionIdentifier {
   case "ACCEPT_ACTION":
      sharedMeetingManager.acceptMeeting(user: userID, 
                                    meetingID: meetingID)
      break
        
   case "DECLINE_ACTION":
      sharedMeetingManager.declineMeeting(user: userID, 
                                     meetingID: meetingID)
      break
        
   // Handle other actions…
 
   default:
      break
   }
    
   // Always call the completion handler when done.    
   completionHandler()
}

See Also

Notification Categories and User Actions

class UNNotificationCategory

A type of notification that your app supports and the custom actions to display with it.

class UNNotificationAction

A task to perform in response to a delivered notification.

class UNTextInputNotificationAction

An action that can accept user-typed text.