Local Notifications with Swift

Setukanani
7 min readJun 5, 2020

--

Here you’ll learn how to schedule and handle local notifications into your iOS app with Swift.

We will go through the below mentioned sequence to understand Local Notifications:

  1. Understanding of Types of Notifications
  2. Create a NotificationManagerClass to handle and schedule Local Notifications
  3. User’s Permission to Send Local Notifications
  4. Local Notification Permission Status
  5. Schedule Local Notifications
  6. Handle Incoming Local Notifications

Understanding of Types of Notifications

On iOS, we can send and receive two types of notifications:

  • Push Notifications: Push notifications are sent via the internet, such as chat messages. It gets delivered to user’s iPhone Device via Apple Push Notification Service (APNS).
  • Local Notifications: Local notifications are scheduled and sent locally on our iPhone, so we don’t require internet on our phone to receive it. For example, calendar reminders or iPhone alarm clock reminders.

In this post, we’ll focus on local notifications. Local notifications are short, text-based messages that you can schedule from within the iOS app, to be delivered at a future point in time. It can be in a recurring form as well.

Local notifications are ideal for use cases like, reminding a user about an upcoming calendar event, a medicine reminder, water intake reminder, physiotherapy/exercise reminder.

Create a NotificationManagerClass to handle and schedule Local Notifications

We will use LocalNotificationManager class to help us manage & schedule local notifications.

Here’s the starting definition of the LocalNotificationManager class:

The class has one instance property called notifications, of type [LocalNotification].

Now We’ll define that LocalNotification type :

This LocalNotification struct will help us organize the notifications in a better way.

In above struct,

  • id is used to identify unique notifications.
  • title to get displayed as part of local notification.
  • subtitle to get displayed as part of local notification.
  • datetime is for the time when we want to schedule the notifications.
  • repeats will be used to make it recurring or not.

User’s Permission to Send Local Notifications

Before we schedule local notifications, we need to ask for user’s permission. Asking permission to send local notifications involves the requestAuthorization(options:completionHandler:) function of a shared UNUserNotificationCenter instance. This singleton instance is used to manage everything related to notifications in our iOS app.

Write the below mentioned function inside LocalNotificationManager Class.

Below mentioned is what happens inside the function:

  • First, we’re accessing the shared instace of UNUserNotificationCenter by calling the current() function. That way we get access to the single object that manages notifications on iOS.
  • Then, the function requestAuthorization(options:completionHandler:) is called which prompts the permission dialog. The parameter options is asking permission to display alerts, to change an app icon’s badge number, and to play a sound when the notification alert pops up.
  • Then, as the last parameter completion handler gets executed. It has two parameters, granted of type Bool, and error of type Error. We can check if the permission has been given or not based on these parameters.
  • So this function asks the iPhone users for permission to send local notifications. If permission is given, the scheduleLocalNotifications() function is called. If permission isn’t given, or an error occurs, nothing happens.

Local Notification Permission Status

We can use below mentioned schedule() function to start the local notification permissions and the scheduling of notifications.

  • First, we’re accessing that shared UNUserNotificationCenter and calling the getNotificationSettings(completionHandler:) function. Here completion handler is executed when the settings have been received.
  • Then we have authorizationStatus of enum type UNAuthorizationStatus. It tell us if and what permission has been given.
  1. .notDetermined. If the authorization is not determined, it means we haven’t asked for permission before. So, we’ll ask for permission by calling the requestAuthorization()function.
  2. Authorized or provisional. If the value of authorizationStatus is .authorized or .provisional, it means we have (temporary) permission to schedule notifications. So, we’ll schedule notifications by calling scheduleNotifications().
  3. In the case of .denied, we don’t do nothing.

We have to call scheduleNotifications() at 2 places :

  1. If permission has not been given, so it’s asked, and scheduleNotifications() is called from requestAuthorization().
  2. If permission has been given before, so scheduleNotifications() is called directly from the schedule() function.

Schedule Local Notifications

Below mentioned function iterates over the LocalNotification objects in the notifications array and schedules them for delivery in the future.

Here function iterates over the notifications array with a for loop. Inside the loop, for every item in the array, this happens:

  • Creating an object of type UNMutableNotificationContent. This object contains the content of the notification, such as its title, subtitle, sound, repeats and time.
  • Then, create an object of type UNCalendarNotificationTrigger. This object contains the trigger for the notification, such as a date and time.
  • Then, we’re creating an object of type UNNotificationRequest. This object combines the content and the trigger, together with a unique ID. Every notification needs a unique ID, which we can conveniently use to reschedule a local notification.
  • Finally, the request object is passed to the add(request:completionHandler:) function of the shared UNUserNotificationCenter instance. This schedules the local notification and then executes the completion handler. In this completion handler, we’re checking that no errors occurred.

Now that the LocalNotificationManager class is complete, we can schedule notifications :

We can remove pending or delivered notifications using their ids in this way:

Handle Incoming Local Notifications

When we tap on a local notification, iOS app opens by default. This is perfect if you just want to use notifications to open the app, but what if we want to handle specific notifications in the app?

We can respond to local notifications in two ways:

  1. When the app isn’t running, i.e. it’s in the background or closed, using the delegate function userNotificationCenter(_:didReceive:withCompletionHandler:)
  2. When the app is running and in the foreground, using the delegate function userNotificationCenter(_:willPresent:withCompletionHandler:)

To handle local notifications, iOS app needs to register a delegate instance that conforms to the UNUserNotificationCenterDelegate protocol before the app’s application(_:didFinishLaunchingWithOptions:) function returns as mentioned below.

UNUserNotificationCenter.current().delegate = self

Below mentioned delegate function gets called when the app starts from a tapped notification:

The response object contains all information about the notification. In the above code we’re using the local notification’s identifier to find out what notification was sent. In the app, we can respond to a notification by restoring the state of the app, or presenting UI, or by taking some action.

It’s important to call completionHandler() when we are done. This closure is passed to the delegate function, and it should be called when we want to indicate to the system that we are done handling the notification.

If we’ve defined any custom actions for the local notification, the response object will also contain information about that action.

iOS app can also receive local notifications while it’s running. We have to use a different delegate function to respond to these notifications, and we use that function to determine what happens with the notification:

The above code is similar to the delegate function that responds to non-foreground notifications. Again, we’re checking what local notification was triggered, and we’re executing the completionHandler to indicate that handling the notification is done.

We can pass options from the UNNotificationPresentationOptions struct to the completion handler, to indicate what we want iOS to do with the notification. The above code shows an alert to the user, and plays the notification’s sound. You can also silence the notification by passing an empty array, i.e. no options, like this: completionHandler([]).

Note: Don’t forget to import UserNotifications.on top of the LocalNotificationManager class.

That’s all about Local Notifications with Swift.

Hope iOS Developers find this post useful. Please leave a comment if you have any questions or thoughts regarding the Local Notifications.

If you like this article, feel free to share it.

Thank you.

--

--