July 17, 2019

How to Send Local Notification With Swift 5

In this tutorial we will go through how you can send local notifications from Swift. Local notifications are simple and can add a lot of value to your app.

How to Send Local Notification With Swift 5

Notifications can be daunting, in this post I hope to make it simple by showing you how to send local notification as well as how to handle the user tapping that notification.

Foundational information

Local notifications have three main parts. The content, trigger and request. These three parts will allow you to create a local notification.

Content

The content of a notification is straight forward. It is what you are going to show the user. This will include things such as title, body, badge number, user info, attachments etc.

I will use most of these except user info. User info is just a dictionary which will allow you to put whatever content you want into it. Later in the tutorial I will show you how to handle the tap event for a notification. When a user taps the notification the user info will be accessible at that time and you will be able to use the information there.

Trigger

The time trigger will set off the the event that will show the notification to the user. There are 3 different kinds of triggers. Namely time, calendar and location triggers. These do as their name says. The time trigger will allow you to set a time, in this case it will be a time interval of seconds, once the time is up, the notification will show.

The next is a calendar trigger. This will allow you to create a date and then use the date to trigger the notification. This is similar to the time trigger in a sense as they both use time. The major difference is that the time trigger uses a time interval and the calendar trigger uses an instance of DateComponents.

The location trigger will allow you to create a location, in this case you will need a center location as well as a region location. This will allow you to send a notification when the user enters the region or exits the region, or both.

Request

Once you have your content and trigger set up you need to create a request. The request will take both content and trigger as arguments as well as an identifier.

The identifier cannot be nil, and can be used to cancel notifications that are still pending.

Step 1: Basic setup

Now that you have a basic knowledge of a notification we can start setting it up. The first thing that you will need to add a new import to your file. Just below the other imports add import UserNotifications.

You will also need to create a new property called userNotificationCenter:

// Notification center property
let userNotificationCenter = UNUserNotificationCenter.current()

Once you have done that, there are two more methods that we will add. One that will request the user to grant permission to the app so that it can show notificatins, and one to send the notification.

These two methods will look like this:

func requestNotificationAuthorization() {
    // Code here
}

func sendNotification() {
    // Code here
}

I am doing this in the default view controller that gets created for every new project. All I am going to do is call those methods from the viewDidLoad method:

override func viewDidLoad() {
    super.viewDidLoad()
    self.requestNotificationAuthorization()
    self.sendNotification()
}

At the moment this will do nothing. In the next step we will prompt the user to give the app permission to show the notifications.

Step 2: Ask for the users permission

When we ask the user to grant the app permission to display the notifications, we have to specify what the notifications will want to use. In our case we will ask the user to authenticate for an .alert, .badge and .sound.

In your requestNotificationAuthorization add the following code:

// Auth options
let authOptions = UNAuthorizationOptions.init(arrayLiteral: .alert, .badge, .sound)

When we make the request, it will tell the user what type of notifications we might send to them.

The next part is to ask the user for permission, add the following code below the authOptions variable in the requestNotificationAuthorization method.

self.userNotificationCenter.requestAuthorization(options: authOptions) { (success, error) in
    if let error = error {
        print("Error: ", error)
    }
}

Your requestNotificationAuthorization method should now look like this:

func requestNotificationAuthorization() {
    let authOptions = UNAuthorizationOptions.init(arrayLiteral: .alert, .badge, .sound)
    
    self.userNotificationCenter.requestAuthorization(options: authOptions) { (success, error) in
        if let error = error {
            print("Error: ", error)
        }
    }
}

If you run the app now, you should get an alert on your screen asking to grant permission for notifications. It will look like this.

Permissions alert view


Step 3: Send the notification

All the following code will be added to the sendNotificationmethod that we created earlier.

The first thing that we need to do here is to create the contentof the notification. We are going to set the title, body, attachments as well as the badge count. The badge count is the little red dot with a number in it that shows above the app icon.

Create the content

To create content for a notification you will need to create a new instance of UNMutableNotificationContent. Once that is done we will add all the content.

We need to add the below code to our sendNotificationmethod:

// Create new notifcation content instance
let notificationContent = UNMutableNotificationContent()

// Add the content to the notification content
notificationContent.title = "Test"
notificationContent.body = "Test body"
notificationContent.badge = NSNumber(value: 3)

// Add an attachment to the notification content
if let url = Bundle.main.url(forResource: "dune",
                                withExtension: "png") {
    if let attachment = try? UNNotificationAttachment(identifier: "dune",
                                                        url: url,
                                                        options: nil) {
        notificationContent.attachments = [attachment]
    }
}

As you see in the above code, we create a new instance of UNMutableNotificationContent which will allow us to set the title, body, badge as well as the attachment.

For the attachment, you will need to add the relevant files to your project. You can use any file type that notifications will allow for. You can find the supported file types here.

Create the trigger

Creating a trigger is very easy. We just need to create a new instance of UNTimeIntervalNotificationTrigger with the timeInterval we want to wait for before the notification shows up.

Add the following code below the code we added above.

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5,
                                                repeats: false)

Create the request

The request needs an identifier as well as the content and trigger we just created. Add the following code below the trigger code from above:

let request = UNNotificationRequest(identifier: "testNotification",
                                    content: notificationContent,
                                    trigger: trigger)

Add the request to userNotificationCenter

The final step to sending the local notification is to add it to the userNotificationCenter property that we creating in the beginning of the post.

Add this code after the request code we just added:

userNotificationCenter.add(request) { (error) in
    if let error = error {
        print("Notification Error: ", error)
    }
}

Great that should be it. Your sendNotification method should look like this if everything is correct:

func sendNotification() {
    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = "Test"
    notificationContent.body = "Test body"
    notificationContent.badge = NSNumber(value: 3)
    
    if let url = Bundle.main.url(forResource: "dune",
                                withExtension: "png") {
        if let attachment = try? UNNotificationAttachment(identifier: "dune",
                                                        url: url,
                                                        options: nil) {
            notificationContent.attachments = [attachment]
        }
    }
    
    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5,
                                                    repeats: false)
    let request = UNNotificationRequest(identifier: "testNotification",
                                        content: notificationContent,
                                        trigger: trigger)
    
    userNotificationCenter.add(request) { (error) in
        if let error = error {
            print("Notification Error: ", error)
        }
    }
}

Before you run the app there is something you need to know about the notifications. They will not show up if you app is in the foreground. In order to see this notification, you will need to run the app and then background the app immediately. This will allow the notification to show up. I will show you how to get the notification to show while the app is in the foreground later on in this post.

Step 4: Handle notification being tapped

In the above step when we created the content we set the badge count to 3. In this step I will show you how to handle the user tapping the notification and how to reset the badge count to be 0.

Now you need to go to your appDelegate file and add the following function and its content.

// Local notifications
func application(_ application: UIApplication, didReceive notification: UILocalNotification) {
    UIApplication.shared.applicationIconBadgeNumber = 0
}

When your app is in the background and the notification gets displayed. If you tap the notification this method will be called. From here you can access the information of the notification via the notification argument.

All I am doing in this method is setting the badge number to be 0, this will clear it so that it is not shown above the app icon.

Earlier in this post I mentioned that I would tell you where you could get the user info from if you set it when we were creating the content. The notification argument has a property called userInfo which will contain the user info if you set it before.

Step 5: Show notification when app is in foreground

To do this we need to conform to the UNUserNotificationCenterDelegate. This is quite simple as it only has two methods that we need to implement. The implementations are straight forward too.

We first need to add the protocol to our class as below:

// Class
class ViewController: UIViewController, UNUserNotificationCenterDelegate

We now need assign our class instance as the delegate to our userNotificationCenter property:

override func viewDidLoad() {
    super.viewDidLoad()

    // Assing self delegate on userNotificationCenter
    self.userNotificationCenter.delegate = self

    self.requestNotificationAuthorization()
    self.sendNotification()
}

As you can see I assigned self as the delegate in my viewDidLoad method.

Now we just need to add the two methods that the delegate needs.

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    completionHandler()
}

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

In the second method I have used the options that we asked permission for in Step 2.

Conclusion

That should be it. You should now be able to send local notifications when the app is in the foreground and in the background.