티스토리 뷰

 

 

[iOS] 로컬 Push Notification(푸시 알림) 구현하기

[iOS] FCM으로 Push Notification (푸시 알림) 구현하기 FCM(Firebase Cloud Messaging)같은 경우는 공식문서와 설정 튜토리얼이 정말 잘 되어있어서 공식 문서를 따라가시는 것도 좋을 것 같습니다! I. Key 발급 1.

dokit.tistory.com

이전 글에서는 단순하게 푸시 알림을 구현해보았는데요, 이번에는 앱이 백그라운드 상태일 때 특정 시간대에 알림이 오도록 설정해보겠습니다.

 

기존 코드


class LocalNotificationHelper {
   // ...
    
    func pushNotification(title: String, body: String, seconds: Double, identifier: String) {
	//...
    }
}

이전에 구현했던 알림 담당 객체인데요, 여기에 함수를 추가해서 사용하겠습니다.

더보기

PushNotificationHelper 전체 코드 입니다.

import Foundation
import UserNotifications
import UIKit

/// 로컬 Push Notification에 대한 인증 및 실행 클래스입니다.
///
/// - Note: 싱글턴으로 구현되어 있습니다. `LocalNotificationHelper.shared`를 통해 접근해주세요.
class LocalNotificationHelper {
    static let shared = LocalNotificationHelper()
    
    private init() {}
    
    ///Push Notification에 대한 인증 설정 함수입니다.
    func setAuthorization() {
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )
    }
    
    /// 호출 시점을 기점 seconds초 이후에 Notification을 보냅니다.
    ///
    /// - Parameters:
    ///   - title: Push Notification에 표시할 제목입니다.
    ///   - body: Push Notification에 표시할 본문입니다.
    ///   - seconds: 현재로부터 seconds초 이후에 알림을 보냅니다. 0보다 커야하며 1이하 실수도 가능합니다.
    ///   - identifier: 실행 취소, 알림 구분 등에 사용되는 식별자입니다. "TEST_NOTI" 형식으로 작성해주세요.
    func pushNotification(title: String, body: String, seconds: Double, identifier: String) {
        
        assert(seconds > 0, "seconds는 0보다 커야합니다. (런타임 에러)")
        
        let notificationContent = UNMutableNotificationContent()
        notificationContent.title = title
        notificationContent.body = body
        
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: seconds, repeats: false)
        
        let request = UNNotificationRequest(identifier: identifier,
                                            content: notificationContent,
                                            trigger: trigger)
        
        UNUserNotificationCenter.current().add(request) { error in
            if let error = error {
                print("Notification Error: ", error)
            }
        }
    }
}

 

특정 날짜(시점)에 실행하기


                                                              // ✅
func pushReservedNotification(title: String, body: String, date: Date, identifier: String) {

    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = title
    notificationContent.body = body

    // ✅
    let triggerComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
    let trigger = UNCalendarNotificationTrigger(dateMatching: triggerComponents, repeats: false)

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

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

새로운 함수를 추가했습니다. date를 받아 해당 시점에 알림이 실행되도록 했습니다. 트리거 객체가 UNCalendarNotificationTrigger로 변경된 것에 주의해주세요!

 

주기적으로 실행하기


하루 중에 특정 시간이 되면 알림 오는 앱들이 있는데요, 마찬가지로 UNCalendarNotificationTriggerrepeats를 이용해서 구할 수 있습니다.

func pushScheduledNotification(title: String, body: String, hour: Int, identifier: String) {

    assert(hour >= 0 || hour <= 24, "시간은 0이상 24이하로 입력해주세요.")

    let notificationContent = UNMutableNotificationContent()
    notificationContent.title = title
    notificationContent.body = body

    var dateComponents = DateComponents()
    dateComponents.hour = hour  // ✅ 알림을 보낼 시간 (24시간 형식)

    let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true) // ✅ true
    let request = UNNotificationRequest(identifier: identifier,
                                        content: notificationContent,
                                        trigger: trigger)

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

Trigger의 repeats를 true로 하면 특정 주기로 반복적으로 알림을 보낼 수 있습니다.

이때 DateComponents를 이용해서 시점을 정해주면 하루 중 특정 시간에 알림이 옵니다.

다른 주기를 설정하고 싶다면 DateComponets의 다른 속성을 수정하면 되겠죠?

 

알림 등록하기


이제 이 알림들이 실행될 수 있도록 등록을 해주어야하는데요, 주기 알림은 AppDelegate에서 설정해주는게 좋겠죠?

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        
        UNUserNotificationCenter.current().delegate = self
        
        // 예약 알림 설정
        let triggerDate = Calendar.current.date(byAdding: .minute, value: 5, to: Date())! // 예: 현재로부터 5분 후
        LocalNotificationHelper
            .shared
            .pushReservedNotification(title: "예약 알림입니다.",
                                      body: "예약 알림 테스트 중입니다.",
                                      date: triggerDate,
                                      identifier: "RESERVED_NOTI")
        LocalNotificationHelper
            .shared
            .pushScheduledNotification(title: "주기 알림입니다.",
                                       body: "주기 알림 테스트 중입니다.",
                                       hour: 2,
                                       identifier: "SCHEDULED_NOTI")
        
        return true
    }
}

테스트겸 특정 시점에 실행되는 알림도 추가해주었습니다.

 

기다려서 알림이 오는지 확인해보았는데, 잘 작동하는 것을 확인했습니다 👍

 

등록된 알림 관리하기


마지막으로 등록된 알림들을 관리하는 방법을 알아보겠습니다.

func printPendingNotification() {
    UNUserNotificationCenter.current().getPendingNotificationRequests { requests in
        for request in requests {
            print("Identifier: \(request.identifier)")
            print("Title: \(request.content.title)")
            print("Body: \(request.content.body)")
            print("Trigger: \(String(describing: request.trigger))")
            print("---")
        }
    }
}

아직 실행되지 않고 등록되어 있는 알림들을 출력해보는 메서드입니다.

 

func removePendingNotification(identifiers: [String]){
    UNUserNotificationCenter
        .current()
        .removePendingNotificationRequests(withIdentifiers: identifiers)
}

func removeDeliveredNotification(identifiers: [String]){
    UNUserNotificationCenter
        .current()
        .removeDeliveredNotifications(withIdentifiers: identifiers)
}

대기중인 알림과 전달된 알림을 삭제하는 메서드입니다. identifier를 이용해서 삭제할 수 있습니다.

 

 

⬇️ 전체 코드

더보기

 

복붙해서 쓰시면 빠르게 구현하실 수 있을 것 같습니다!

import Foundation
import UserNotifications
import UIKit

/// 로컬 Push Notification에 대한 인증 및 실행 클래스입니다.
///
/// - Note: 싱글턴으로 구현되어 있습니다. `LocalNotificationHelper.shared`를 통해 접근해주세요.
class LocalNotificationHelper {
    static let shared = LocalNotificationHelper()
    
    private init() {}
    
    ///Push Notification에 대한 인증 설정 함수입니다.
    func setAuthorization() {
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )
    }
    
    /// 호출 시점을 기점 seconds초 이후에 Notification을 보냅니다.
    ///
    /// - Parameters:
    ///   - title: Push Notification에 표시할 제목입니다.
    ///   - body: Push Notification에 표시할 본문입니다.
    ///   - seconds: 현재로부터 seconds초 이후에 알림을 보냅니다. 0보다 커야하며 1이하 실수도 가능합니다.
    ///   - identifier: 실행 취소, 알림 구분 등에 사용되는 식별자입니다. "TEST_NOTI" 형식으로 작성해주세요.
    func pushImmediateNotification(title: String, body: String, seconds: Double, identifier: String) {
        
        assert(seconds > 0, "seconds는 0보다 커야합니다. (런타임 에러)")
        
        let notificationContent = UNMutableNotificationContent()
        notificationContent.title = title
        notificationContent.body = body
        
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: seconds, repeats: false)
        
        let request = UNNotificationRequest(identifier: identifier,
                                            content: notificationContent,
                                            trigger: trigger)
        
        UNUserNotificationCenter.current().add(request) { error in
            if let error = error {
                print("Notification Error: ", error)
            }
        }
    }
    
    /// 특정 시점에 Notification을 보냅니다.
    ///
    /// - Parameters:
    ///   - title: Push Notification에 표시할 제목입니다.
    ///   - body: Push Notification에 표시할 본문입니다.
    ///   - date: date에 최대한 가깝게 알림을 보냅니다.
    ///   - identifier: 실행 취소, 알림 구분 등에 사용되는 식별자입니다. "TEST_NOTI" 형식으로 작성해주세요.
    func pushReservedNotification(title: String, body: String, date: Date, identifier: String) {
        
        let notificationContent = UNMutableNotificationContent()
        notificationContent.title = title
        notificationContent.body = body
        
        let triggerComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
        let trigger = UNCalendarNotificationTrigger(dateMatching: triggerComponents, repeats: false)
        
        let request = UNNotificationRequest(identifier: identifier,
                                            content: notificationContent,
                                            trigger: trigger)
        
        UNUserNotificationCenter.current().add(request) { error in
            if let error = error {
                print("Notification Error: ", error)
            }
        }
    }
    
    /// 하루를 주기로 특정 시간에 Notification을 보냅니다.
    ///
    /// - Parameters:
    ///   - title: Push Notification에 표시할 제목입니다.
    ///   - body: Push Notification에 표시할 본문입니다.
    ///   - hour: 하루 중 해당 시간에 알림을 보냅니다. (24시간 단위)
    ///   - identifier: 실행 취소, 알림 구분 등에 사용되는 식별자입니다. "TEST_NOTI" 형식으로 작성해주세요.
    func pushScheduledNotification(title: String, body: String, hour: Int, identifier: String) {
        
        assert(hour >= 0 || hour <= 24, "시간은 0이상 24이하로 입력해주세요.")
        
        let notificationContent = UNMutableNotificationContent()
        notificationContent.title = title
        notificationContent.body = body
        
        var dateComponents = DateComponents()
        dateComponents.hour = hour  // 알림을 보낼 시간 (24시간 형식)
        
        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
        let request = UNNotificationRequest(identifier: identifier,
                                            content: notificationContent,
                                            trigger: trigger)
        
        UNUserNotificationCenter.current().add(request) { error in
            if let error = error {
                print("Notification Error: ", error)
            }
        }
    }
    
    /// 대기중인 Push Notification을 출력합니다.
    func printPendingNotification() {
        UNUserNotificationCenter.current().getPendingNotificationRequests { requests in
            for request in requests {
                print("Identifier: \(request.identifier)")
                print("Title: \(request.content.title)")
                print("Body: \(request.content.body)")
                print("Trigger: \(String(describing: request.trigger))")
                print("---")
            }
        }
    }
    
    /// 대기중인 Push Notification을 취소합니다.
    /// - Parameter identifiers: 삭제하고자하는 알림 식별자 리스트입니다.
    func removePendingNotification(identifiers: [String]){
        UNUserNotificationCenter
            .current()
            .removePendingNotificationRequests(withIdentifiers: identifiers)
    }
    
    /// 이미 전달된 Push Notification을 알림센터에서 삭제합니다.
    /// - Parameter identifiers: 삭제하고자하는 알림 식별자 리스트입니다.
    func removeDeliveredNotification(identifiers: [String]){
        UNUserNotificationCenter
            .current()
            .removeDeliveredNotifications(withIdentifiers: identifiers)
    }
}

읽어주셔서 감사합니다.

 

ref.

ChatGPT

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함