Creating notifications can be a great way to inform your users of specific events or notify them about important tasks. While striving to create engaging notifications we want to remember some of Apple’s suggestions, particularly around being mindful of people’s time:
· Send notifications only when they are relevant
· Don’t spam
· Don’t send notifications to boost traffic or engagement

As one of Apple’s design evangelists puts it

Don’t think of notifications as just a hook into your app, they should be a self contained packet of information that allows you to complete a specific task

I’m going to focus on creating local notifications, as displaying them in the app is similar to remote notifications without the required sever work. As with many of Apple’s services where privacy can be an issue, we need to request authorization to send the user notifications first. There are several different attributes that we can request access to defined underUNAuthorizationOptions. We will ask for the most common ones and ignore the fourth option which is for car play.

let center =  UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound, .badge]) { (result, error) in
//handle result of request failure
}

You generally want to request authorization to notifications as early as possible, otherwise any notifications received before access is granted will not be displayed. Apple suggests completing this before app launch using application:didFinishLaunchingWithOptions:. Whether you handle this in the AppDelegate or in a separate object, make sure that before you start receiving local or remote notifications that access has been granted.

Creating Notifications
Creating a notification is done through the UNNotificationRequest object which requires three pieces of information: an identifier, content, and a trigger.

identifier — a way of uniquely identifying notifications in your app. The identifier allows you to update or remove the notification at a latter time. Scheduling a notification with the same identifier will automatically remove any existing one, and replace it with the new one.

content — the information that will be displayed in the banner and consists of attributes such as the title, subtitle, body, and media attachments (if any). There are a variety of other content attributes that can be associated with notifications the details of which can be found in the documentation. When we create a notification’s content we do so using the class UNMutableNotificationContent. This allows us to create the base object and then set the desired attributes.

trigger — the event that will trigger the notification to be displayed to the user. There are three basic triggers that can be defined: time, date, and location. Each notification type is defined by a class, all of which are subclasses of UNNotificationTrigger. The available trigger classes are as follows:

UNTimeIntervalNotificationTrigger
UNCalendarNotificationTrigger
UNLocationNotificationTrigger

The classes are pretty self-explanatory and each takes parameters relevant to their type (time interval, date, region) making creation of the trigger easy and straightforward. You just initialize the class with the required type. Lets create a notification to see how this works.

This code creates a local notification that will be displayed to the user after 2 seconds. We set the basic values such as the title, subtitle, and body text that will appear in the notification. Notice that we use the UNMutableNotificationContent class to create the notification. The notification center will generate the notification which will include a UNNotificationContent object as the payload so we can access this information later.

Basic Notification

If you were to run this while the app was in the foreground, you would not see the notification displayed, but it would appear in the device’s Notification Center. The reason for this is that in order for the notification to appear when the app is in the foreground we need to implement the UNUserNotificationCenterDelegate protocol. This is a simple protocol with only two methods, both of which require that you call the completion handler when done. I created a separate object to conform to the protocol and implement these two methods.

We need to call the completion handler in willPresent: with the desired foreground options. Creating a basic notification is really simple, but not all that engaging. What we need now is some engaging content and as previously mentioned an action for the user to perform.

Actions and Media Attachments
Notifications can also contain media attachments such as images, videos, or audio. Media attachments will appear in the long look and the short look (images). Actions appear as buttons in long look of the notification. Lets add some media and some basic actions.

We create actions using the UNNotificationAction class. We need to provide an identifier and a title for our action. For this purpose I defined an enum to represent the two different types of action we will support, dismiss and reminder.

Custom actions must be associated with a category. We create a category using theUNNotificationCategory class. Each category can contain a set of actions to be displayed when the notification is accessed in the long look. We can reuse a category with different notifications, but each category requires a unique identifier. These are the two required items, but you can also add some predefined options and intents (for use with Siri). Some options can be used to override user settings for notification display. Lastly we assign the category we created the to notification center. In order for the actions to be displayed, we need to assign the same category identifier on the notification’s content catergoryIdentifier field otherwise the actions will not be visible.

content.categoryIdentifier = CategoryIdentifiers.general

When we access the long look, we will see our notification details and also the actions the the user can perform. The actions for the notification are handled by the notification delegate object we created earlier. When an action is selected by the user the delegate receives the call back via
userNotificationCenter(_:didReceive:withCompletionHandler:) 
 the system includes the action identifier as part of the UNNotificationResponse provided in the call back so your app can respond appropriately.

Notification long look showing actions

This great, we now have some custom actions the user can initiate while viewing the notification without ever going into our app. Next what we need is to add some media content to give our notification some pizazz. We can add media attachments by updating our notification content’s attachments property. This property takes an array of UNNotificationAttachment objects.

if let url = Bundle.main.url(forResource: "jurassic_world", 
withExtension: "png") {
if let attachment = try? UNNotificationAttachment(identifier:
"image", url: url, options: nil) {
content.attachments = [attachment]
}
}

Here we load an image URL from the local file system and create our UNNotificationAttachment object. We then assign it to the attachments property. Just as a note, if we were creating remote notifications then we would need to create a service extension to add the media content before the notification is delivered.

Now when we receive our notification we get a small image accompanying the original content. When we access the long look we can see a larger image is displayed along with our custom actions.

That is certainly a more engaging notification then when we started. Simply by adding an attachment we get a new visually appealing interface and we didn’t have to write any UI code. But what if I want to display a custom interface you ask? That will be the topic of my next post on using Notification Content Extensions to create your own custom interface.