(Swift) Using UNUserNotification to emit the notification in SwiftUI - Part 1

Introduction

To enhance user experience, most apps will ask the user's permission to emit the notification to the user device. In this article, we will discuss how to use UNUserNotificationCenter to create the local notification in SwiftUI.

Apple Documentation - UNUserNotificationCenter

Firstly, we'll create a NotificationManager to manage all of our functions and the status of user's notifications.

Within our NotificationManager, we will create an array property of UNNotificationRequest which will store all of the user's notification detail.

At here, we'll need to monitor the Authorization Status of the user's device so we create a function 'reloadAuthorizationStatus'

class NotificationManager: ObservableObject {

    //UNNotificationRequest need to import UserNotifications library
    @Published private(set) var notifications : [UNNotificationRequest] = []
    @Published private(set) var authorizationStatus : UNAuthorizationStatus?

    //Reload Notification Status
    func reloadAuthorizationSatus() {

        UNUserNotificationCenter.current().getNotificationSettings { settings in
            //Becasue getting the Notification settings is not on the main thread so I need to use the \

            DispatchQueue.main.async {
                print("\(settings.authorizationStatus)")
                self.authorizationStatus = settings.authorizationStatus
            }
        }

    }
}

Then we will need to use this notificationManager class within the screen that we want to check and ask the user's permission.

When the scene appears, we want to check the user's Authorization Status so we call notificationManager.authorizationStatus() within our onAppear modifier.

struct MeomeriesListView: View {

    @StateObject private var notificationManager = NotificationManager()

    var body: some View {
        List(notificationManager.notifications, id: \.identifier ){ notification in
            Text(notification.content.title)
                .fontWeight(.semibold)
        }
        .listStyle(InsetGroupedListStyle())
        .navigationTitle("My Memeories")
        .onAppear{
            notificationManager.reloadAuthorizationSatus()
        }
        .onChange(of: notificationManager.authorizationStatus, perform: { value in
            switch value {
            case .notDetermined:
                //Request the authorization
            case .authorized:
                //get local authorizations
            break
            default:
                break
            }
        })

    }
}

We also want to monitor our authorizationStatus so we put it into onChange modifier. When the user first time enters the app, the status is .notDetermined so it should trigger one function to request the authorization.

Reference: Asking Permission to User Notifications

At here we will at this code into our NotificationManager

func requestAuthorization() {

        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { isGranted, _ in
            DispatchQueue.main.async {
                self.authorizationStatus = isGranted ? .authorized : .denied
            }
        }

}

And whenever the user grants the authorization, the NotificationManager should trigger the function to reload/update the current notifications.

func reloadLocalNotificationCenter() {
        UNUserNotificationCenter.current().getPendingNotificationRequests { notifications in
            DispatchQueue.main.async {
                print("Reload existing notification")
                self.notifications = notifications
            }
        }
}

Then we modify our view and NotificationManager to this:

view.swift

struct MeomeriesListView: View {

    @StateObject private var notificationManager = NotificationManager()

    var body: some View {
        List(notificationManager.notifications, id: \.identifier ){ notification in
            Text(notification.content.title)
                .fontWeight(.semibold)
        }
        .listStyle(InsetGroupedListStyle())
        .navigationTitle("My Memeories")
        .onAppear{
            notificationManager.reloadAuthorizationSatus()
        }
        .onChange(of: notificationManager.authorizationStatus, perform: { value in
            switch value {
            case .notDetermined:
                //Request the authorization
                notificationManager.requestAuthorization()
            case .authorized:
                //get local authorizations
                notificationManager.reloadLocalNotificationCenter()
            break
            default:
                break
            }
        })

    }
}

NotificationManager.swift

import Foundation
import UserNotifications

class NotificationManager: ObservableObject {

    //UNNotificationRequest need to import UserNotifications library
    @Published private(set) var notifications : [UNNotificationRequest] = []
    @Published private(set) var authorizationStatus : UNAuthorizationStatus?

    //Reload Notification Status
    func reloadAuthorizationSatus() {

        UNUserNotificationCenter.current().getNotificationSettings { settings in
            //Becasue getting the Notification settings is not on the main thread so I need to use the \

            DispatchQueue.main.async {
                print("\(settings.authorizationStatus.rawValue)")
                self.authorizationStatus = settings.authorizationStatus
            }
        }

    }

    func requestAuthorization() {

        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { isGranted, _ in
            DispatchQueue.main.async {
                self.authorizationStatus = isGranted ? .authorized : .denied
            }
        }

    }

    func reloadLocalNotificationCenter() {
        UNUserNotificationCenter.current().getPendingNotificationRequests { notifications in
            DispatchQueue.main.async {
                print("Reload existing notification")
                self.notifications = notifications
            }
        }
    }

}

Now when you run the app, you will see the system asking the permission of notification.

AskingPermission.png

For the upcoming article, we will let the user sets the notification and at the certain timing, system will fire up the notification to user's device.