[Swift]UNUserNotificationCenter를 사용해 로컬 푸시 알림 구현

Harry Lee·2024년 11월 1일
0
post-thumbnail

자기관리 알림 기능을 위해 UNUserNotificationCenter를 사용해 로컬 푸시 알림을 구현해보려고 한다. UNUserNotificationCenter는 알림을 설정할 때 특정 날짜에 알림을 설정하는 기능이 없어 이 기능을 중점으로 다뤄보겠다.

NotificationManager 구조체

NotificationManager는 싱글톤 구조체로 알림 등록, 반복, 삭제를 관리한다.

import UserNotifications

struct NotificationManager {
    static let shared = NotificationManager()
    let center = UNUserNotificationCenter.current()

초기 알림 등록

initialNotification 메서드는 특정 날짜에 한 번 울리거나 반복 알림을 등록하는 트리거 역할을 한다. 알림 내용을 UNMutableNotificationContent로 설정하고 전달할 데이터를 userInfo에 담는다.

func initialNotification(categoryId: String, managementId: String, startDate: Date, alertTime: Date, repeatCycle: Int, body: String) {
    let content = UNMutableNotificationContent()
    content.title = "SnapPop"
    content.body = body
    content.sound = .default
    
    // 알림과 함께 추가적으로 전달할 데이터를 딕셔너리 형식으로 설정. 이 데이터는 알림이 수신되었을 때 접근할 수 있다.
    content.userInfo = ["categoryId": categoryId, "managementId": managementId, "startDate": startDate, "alertTime": alertTime, "repeatCycle": repeatCycle, "body": body]

startDate에서 연도, 월, 일 정보를 가져오고 alertTime에서 시간과 분을 가져온다.

var dateComponents = Calendar.current.dateComponents([.year, .month, .day], from: startDate)
dateComponents.hour = Calendar.current.component(.hour, from: alertTime)
dateComponents.minute = Calendar.current.component(.minute, from: alertTime)

UNCalendarNotificationTrigger를 생성하고 repeats를 false로 설정하여 한 번만 울리게 한다.

let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)

UNNotificationRequest를 생성하여 알림의 고유 식별자, 콘텐츠, 트리거를 설정한다.

let request = UNNotificationRequest(identifier: "initialNotification-\(categoryId)-\(managementId)", content: content, trigger: trigger)

반복 알림 등록

repeatingNotification 메서드는 repeatCycle 값에 따라 매일 또는 매주 반복 알림을 등록하는 역할을 한다. 예를 들어, repeatCycle == 1이면 매일, repeatCycle == 7이면 매주 같은 요일에 알림이 울린다.

func repeatingNotification(categoryId: String, managementId: String, startDate: Date, alertTime: Date, repeatCycle: Int, body: String) {
    let content = UNMutableNotificationContent()
    content.title = "SnapPop"
    content.body = body
    content.sound = .default
    
    var dateComponents = DateComponents()
    if repeatCycle == 1 {
        dateComponents.hour = Calendar.current.component(.hour, from: alertTime)
        dateComponents.minute = Calendar.current.component(.minute, from: alertTime)
    } else if repeatCycle == 7 {
        dateComponents.weekday = Calendar.current.component(.weekday, from: startDate)
        dateComponents.hour = Calendar.current.component(.hour, from: alertTime)
        dateComponents.minute = Calendar.current.component(.minute, from: alertTime)
    }
    
    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
    let request = UNNotificationRequest(identifier: "repeatingNotification-\(categoryId)-\(managementId)", content: content, trigger: trigger)
    center.add(request) { error in if let error = error { print("Error scheduling notification: \(error.localizedDescription)") }}
}

UNUserNotificationCenterDelegate

SceneDelegate에 UNUserNotificationCenterDelegate를 추가해 알림 권한을 요청하고 초기 알림 수신 시 userInfo 데이터를 통해 반복 알림을 등록한다.

extension SceneDelegate: UNUserNotificationCenterDelegate {
    func requestNotificationAuthorization() {
        UNUserNotificationCenter.current().delegate = self
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            if granted { print("Notification authorization granted") }
            else { print("Notification authorization denied") }
        }
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo
        if let repeatCycle = userInfo["repeatCycle"] as? Int, repeatCycle != 0 {
            guard let categoryId = userInfo["categoryId"] as? String,
                  let managementID = userInfo["managementId"] as? String,
                  let startDate = userInfo["startDate"] as? Date,
                  let alertTime = userInfo["alertTime"] as? Date,
                  let body = userInfo["body"] as? String else { return }
            NotificationManager.shared.repeatingNotification(categoryId: categoryId, managementId: managementID, startDate: startDate, alertTime: alertTime, repeatCycle: repeatCycle, body: body)
        }
        completionHandler([.banner, .list, .badge, .sound])
    }
}

시연화면

profile
A keyboard player

0개의 댓글