Tutorial

Introduction to User Notifications Framework in iOS 10


Hello, and welcome to the notifications in iOS 10 tutorial! Today, we will be talking about how to implement notifications in iOS 10. iOS 10 features a plethora of changes and additions to the notifications APIs, which includes a new, powerful notification request system based off of triggers, which we will talk more about shortly. The biggest change to notifications in iOS 10 is part of a framework called UserNotificationsUI, which lets us embed custom view controller in our notifications! This allows us to create powerful new notifications that simply weren’t possible before.

In this tutorial, we will be covering various types of local notifications on iOS, starting with basic text notifications and working our way up to embedding an image and an action in our notification. Follow along for more and feel free to comment any questions you may have.

Simple User Notifications

Not all of the notifications we want to show will be fancy and interactive. For this reason, we will start by demonstrating how to show a basic text notification. Download the starter project and open up NotificationsUI.xcodeproj. Looking around, you’ll see it’s pretty empty: we have Main.storyboard for the user interface, along with ViewController.swift and AppDelegate.swift.

user-notification-storyboard

Open up Main.storyboard and take a look at ViewController. The app we’re making today is going to remind its users to go online and read an AppCoda article. It lets users pick a date and time for a notification reminder. The first change we’re going to make to this app is simple: we’re going to enable notifications! Currently, picking a date and time does nothing. We’re going to update the app so that setting a date and time creates a notification at the specified time.

Go ahead and open ViewController.swift. Let’s get started.

When you open ViewController.swift, you’ll notice it’s pretty empty. There is only an action method named datePickerDidSelectNewDate that will be invoked when a new date is selected in the date picker. As mentioned before, right now, the app does nothing instead of creating a notification. Let’s implement the feature.

The process for creating a notification has changed slightly in iOS 10. Developers must now create requests, which are requests to iOS to present a notification. These requests consist of 2 components: triggers and content. A trigger is a set of conditions that must be met for a notification to deliver. To show a notification in iOS 10, we begin with a trigger. The class we use for date based triggers is UNCalendarNotificationTrigger. Apple provides a few others, such as UNLocationNotificationTrigger (which triggers a notification when the user arrives a particular location).

The first step to displaying a notification on iOS, as stated above, is creating a trigger. Let’s go ahead and make one now.

Go to AppDelegate.swift, and make sure you import the UserNotification framework. All the notification-related APIs are organized in this framework:

Next, add a function called scheduleNotification(at date: Date). As its name implies, this function will be responsible for scheduling a notification at a provided date.

In the above code, we use the Gregorian calendar to separate a provided date into components. Dates and components are beyond the scope of this tutorial, but all you need to know is that a date consists of components. An individual component represents a piece of a date, such as the hour, minute, second, etc. The code we have written so far separates the date parameter into components and it saves these components in the components constant. The reason we do this is that UNCalendarNotificationTrigger requires date components, not dates, to function. However, one other oddity of UNCalendarNotificationTrigger is that the complete set of components taken directly from a date do not seem to work. Instead, we need to construct our own instance of DateComponents using some information from the existing instance we have. The third line does just that: it creates a new instance of DateComponents using only the relevant information from date.

Now that we have the components from date, let’s go ahead and make a calendar notification trigger. Like most other things in iOS, Apple has made this process pretty easy. Just add the following line of code in the function:

As you can probably infer, this line creates a new UNCalendarNotificationTrigger using the date components we extracted above. We have set repeats to false because we only want the notification to be appeared once.

Now that we have created a trigger, the next thing is to create some content to display in our notification. This can be done through the UNMutableNotificationContent class. You can add the following lines of code to create the notification content. Simply put the code snippet right below the trigger variable:

These lines are pretty self explanatory: we create a new instance of UNMutableNotificationContent, and then set its title, body, and sound accordingly.

It looks like we’re all ready to show our first notification! However, there are still a couple of steps left: 1. creating a notification request, 2. providing it to the system, that tells iOS to show our notification.

To create a notification request, you instantiate a UNNotificationRequest object with the corresponding content and trigger. You also need to give it a unique identifier for identifying this notification request. Insert the following line of code in the scheduleNotification function:

Easy, right? We create a request with 3 parameters:

  • identifier: This is a unique identifier for our request. As you’ll see shortly, this identifier can be used to cancel notification requests.
  • content: This is the notification content we created earlier.
  • trigger: This is the trigger we would like to use to trigger our notification. When the conditions of the trigger are met, iOS will display the notification.

Okay, the last thing we have to do is add the request to the notification center that manages all notifications for your app. The notification center will listen to the appropriate event and trigger the notification accordingly.

Before we add the notification request to the notification center, it is good to remove any existing notification requests. This step helps prevent unnecessary duplicate notifications. Insert the following code snippet in the function:

The first line of code gets the shared instance of the notification center and calls the removeAllPendingNotificationRequests method to remove all pending notification requests. And then we add the request to the notification center. The method also takes in a completion handler. In our implementation, we use this handler to print an error. Before we continue, make sure your scheduleNotification function looks something like this:

If it does, you’re ready to go! All we need to do now is configure ViewController.swift to call on scheduleNotification(date:) when the user picks a date. In ViewController.swift, insert the following code in the datePickerDidSelectNewDate method:

The above lines fetch the current instance of AppDelegate that our application is using and schedule a notification using the function we wrote earlier. Let’s try it out! Run your app and select a future time. Wait for your device’s clock to reach the time and see what happens!

Ooops! The notification didn’t appear. But why?

There are a couple of reasons it doesn’t work.

First, Apple strives to maintain a flawless user experience on iOS, and part of this experience is giving users ultimate control over the notifications they receive from apps. The user hasn’t granted us access to display notifications yet, which is why they aren’t being delivered.

Let’s fix this. Add the following at the method in AppDelegate.swift:

Here we call the requestAuthorization method of the notification center to ask the user’s permission for using notification. We also request the ability to display alerts and play sounds.

Now run the app again. When the app is launched, you should see the authorization request. Make sure you accept it, and the app is allowed to send notifications to the device.

The other thing you have to take note is that the notification will not be presented in-app. Therefore, once you set the date, make sure you go back to home screen or lock screen.

If you’ve done all the things correctly, the notification should be delivered!

user-notification-1

See? It’s not so hard to send notifications to users on iOS, we just need to take a few precautionary steps first, such as requesting notification access. Now that we’ve sent simple text, let’s move on to attaching an image!

Attaching an Image in the Notification

The notification is now in text-based. This is nothing new! Let’s explore some other features, like displaying an image in a notification.

In the starter project, I have already bundled an image: named logo.png. If you haven’t seen it, it may be because it’s buried in the NotificationsUI group. Anyhow, the image is in the starter project. Let’s see how to display it in the notification.

The UserNotification framework provides the UNNotificationAttachment class for developers to add attachments to the notification. The attachment can be audio, images, and videos. It also supports a variety of file formats. For details, you can check them out on the Apple Developer Website.

Creating an attachment is rather easy, just like most tasks in UserNotifications.framework. We simply initialize an instance of UNNotificationAttachment and add it to the notification content. Update the scheduleNotification method and Insert the following code snippet right before the request variable:

The above code loads the path for our logo image, converts it to a URL, and then initializes an attachment using the image. The initializer for UNNotificationAttachment is marked as throwing, so we include a catch block to handle any errors. Once we have created an attachment, we add it to content. Let’s test out the app again. Once it loads, pick a time and wait for the notification to appear.

user-notification-image

Wow! Look at that, we’ve sent a notification with an image bundled. This is a new feature that was first introduced in iOS 10. This is pretty cool, but I think it will be even better if we can add a “remind me later” button that allows users to temporarily ignore a reminder.

Let’s do that now.

Adding a Reminder Using Notification Actions

Adding actions to notifications is slightly complex, due to the way the APIs are set up. However, it’s nothing we can’t handle. To add an action in the notification, you need to utilize UNNotificationAction and UNNotificationCategory.

First, we need to define categories for our actions. We’ll keep it simple and define just a single category and one action. Insert the following lines of code in the application(_:didFinishLaunchingWithOptions:) method:

The above code creates an action and a category, and it registers the category with UNUserNotificationCenter.

Probably, you’re wondering why categories exist. They do serve a distinct purpose. Think of a category as a group of actions. Once you create a category, you can set a field in UNNotificationContent to add a category to a notification. All of the actions contained within that category will be present on this notification.

In this demo, we only have one action in our category, but if we had multiple actions, assigning this category to our notification would result in all of them being used. So that’s why Apple’s engineers provide UNNotificationCategory for managing the notification actions.

Now that we have created an action and a category and registered the category, let’s use it. Modify the section of your code that creates content and add the following:

This tells the system that we would like to use “myCategory” with our new notification. Now, build and run the app again to see what happens:

User notification action

Awesome! Our notification has a lovely action button now. But if you tap the button, it just dismisses the notification. All we have left to do is to write code to respond to the action.

The UNUserNotificationCenterDelegate protocol defines methods for responding to actionable notifications. So, to respond to the action, let’s extend AppDelegate to implement the UNUserNotificationCenterDelegate protocol:

The userNotificationCenter(_:didReceive:withCompletionHandler:) method is called when the user selects an action. You can determine which action the user has selected by accessing the actionIdentifier of the given UNNotificationResponse. Let’s implement the method like this:

The above code schedules a new notification 900 seconds (60 seconds * 15 minutes) after the current date. Finally, set the default notification center’s delegate to AppDelegate in the scheduleNotification(at:) method:

Now run the app again and schedule a notification to test it out. When the notification appears, tap the Remind me later button. You should receive another notification after 15 minutes.

Wrapping up

I hope you enjoy reading this introductory tutorial for the UserNotifications framework. In part 2, we will discuss notifications in more depth and learn about embedding custom view controllers in our notifications.

For reference, you can download the demo project on Github.

iOS
Creating Simple View Animations in Swift
iOS
A Beginner’s Guide to Automated UI Testing in iOS
iOS
Best Practices for Building Swift Classes
  • James Hartley

    How could we do this without using the calendar but instead using location? Meaning, the notification is triggered when a user gets within 100 yards of a location?


    • Pranjal Satija

      Hey James, sorry for the delayed reply. I would look into UNLocationNotificationTrigger (https://developer.apple.com/reference/usernotifications/unlocationnotificationtrigger). Basically, you create a trigger just like you do in our tutorial, but you use UNLocationNotificationTrigger. Here’s a short example:

      let center = //the point you want to trigger a notification at as a CLLocationCoordinate2D
      let region = CLCircularRegion(center: center, radius: 100, identifier: “identifier”) //replace “identifier” with an identifier

      region.notifyOnEntry = true //you can configure these two properties however you’d like
      region.notifyOnExit = false

      let trigger = UNLocationNotificationTrigger(region: region, repeats: false)

      And set the notification’s trigger to the one we created in this example. Good luck! Let me know if you need more help.


  • Jeffrey B Hougentogler

    If you run this code from your page – it will clear the notifications you are adding because removeAllPendingNotificationRequests() executes asynchronously.

    // async
    UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
    // these will be cleared by the line above it
    UNUserNotificationCenter.current().add(request) {(error) in
    if let error = error {
    print(“Uh oh! We had an error: (error)”)
    }
    }


  • timbojill

    timbojilltimbojill

    Author Reply

    I want to create a simple notification for my app as well without the calendar. I have an app for a Radio station. I want the use to be able to select a pre-set notification time for all our shows. Kindly let me know the best way to do this.


    • Pranjal Satija

      Hey timbojill, to do something like this, you would use the techniques discussed in the tutorial. The only change would be replacing the date components with your own custom ones.


  • Krickkkk

    KrickkkkKrickkkk

    Author Reply

    Why Xcode give me this warning…

    Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.

    It told me that I did not call compeletion handler. so, why i need to call this. did this cause something go wrong?
    and how is the handler work?


    • Jason Crispell

      If you go to the where you have this function:
      func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)

      Option-click on “withCompletionHandler” and it explains it. Basically you’re supposed to call completionHandler() once you’re done processing the notification’s response to let it know you’re done. So if you just add completionHandler() to the end of the method you won’t get that error message.


  • Vikram Kagde

    Will this work for push notification also


  • Bence Szabo

    Hi,

    Firstly, I’d like to say thanks for this tutorial.

    Secondly, I’m struggling to schedule the notification without user interaction. I have it detailed here:
    http://stackoverflow.com/questions/40886790/scheduling-notification-with-swift-3-for-an-array-of-dates

    I’d appreciate any help I can get. Cheers
    Ben


  • Ben Larrabee

    Thanks, you wrote the best how-to for notifications that I’ve run into this week.
    Simple question (I hope): How would I go about adding a .wav as my notification sound. My team (students) is making an eSports-type app and wants a crowd-roar when notifications are delivered.


  • Ethan Lillie

    Great article, Pranjal.

    For anyone that’s curious on how to get the Notification Center to present notifications while the app is open (a somewhat confusing point when you first start working with local notifications), adding the following function to some class that implements UNUserNotificationCenterDelegate (A logical choice: AppDelegate.swift) will do the trick:

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler(.alert)
    }


  • azd1995

    azd1995azd1995

    Author Reply

    i want to use this code with multi local notification , so i have 10 notifications repeat every day .
    i try to edit the tutorial and i do not get any thing
    so any one can help me !?
    thanks 🙂


  • Mritunjay Marc

    This part of the code:

    let selectedDate = sender.date

    let delegate = UIApplication.shared.delegate as? AppDelegate

    delegate?.scheduleNotification(at: selectedDate)

    should be in datePickerDidSelectNewDate method. Where is that method?


  • Mritunjay Marc

    in viewcontroller.swift?


  • Mritunjay Marc

    Also, this part:

    delegate?.scheduleNotification(at: selectedDate)

    when entered says that it has no member “scheduleNotification”


  • parmesh mahore

    I am not able to convert GMT to IST. Due to that Not able to get current time and notification is not coming. Please help.


  • Cesare

    CesareCesare

    Author Reply

    Is it just me or the remind me later functionality is NOT working at all, (I am setting a very little time interval to test it out)?


  • Jasper M. Goce

    great and easy to follow article. where’s the part 2 🙂


  • Doug Breaux

    First, this has been a really clear, helpful tutorial. Thanks!

    But next, I think I have the exact code shown here, and I do not get a button to “Remind me later”. Come to think of it, I also get a small graphic to the side of the notification, not a large one below it. I see both types are shown here, so there must be something fundamental I’m misunderstanding. But I haven’t been able to get from the one notification type to the other, from the Xcode simulator.


  • Doug Breaux

    BTW, one thing that caused me a problem once adding images: adding the attachment will actually *move* the original file, if it’s not a file from the application’s own resources. In my case, an image file stored by the application after the user picks a photo. That deleted the image file from its original location.

    https://stackoverflow.com/questions/40156424/not-able-to-fetch-images-in-extension-app-from-app-group-shared-container-in-ios
    https://developer.apple.com/reference/usernotifications/unnotificationattachment

    “Once validated, attached files are moved into the attachment data store
    so that they can be accessed by the appropriate processes. Attachments
    located inside an app’s bundle are copied instead of moved.”


  • User786

    User786User786

    Author Reply

    Can any one please help me???
    I really have to fix my issue badly… please…
    Here is the info …
    https://stackoverflow.com/q/44478910/6510768


  • ynstek

    ynstekynstek

    Author Reply

    Can we do it the same way with firebase?


Shares