→ User Notification

[User Notification] 로컬 알림 구현하기

Swift librarian 2024. 1. 29. 17:16

User Notification

앱을 사용하다보면 아래와 같은 알림을 많이 찾아볼 수 있다. 이것을 앱에서 간단하게 어떻게 구현할 수 있을까?

출처 : 애플 공식 문서

 

 

User Notifications | Apple Developer Documentation

Push user-facing notifications to the user’s device from a server, or generate them locally from your app.

developer.apple.com

 

Notification 권한 요청하기

우선 Notification 을 사용하려면 권한 요청이 필요하다. NotificationCenter 라는 파일을 만들어주고, 권한을 요청할 것이다.

 

NotificationCenter 클래스를 만들어주고, import UserNotifications 을 해준다. 그리고 NotificationCenter 의 경우 앱에는 반드시 하나의 클래스가 있어야 하기 때문에 싱글톤패턴을 사용하여 클래스를 만들어 줬다.

import UserNotifications

class NotificationCenter {
    static let shared = NotificationCenter()
    
    private init() { }
}

 

권한 요청을 하는 함수를 추가해준다. 나같은 경우 func requestAuthorization() 으로 함수명을 설정했다. 여기서 granted 의 경우 true 일 때 권한요청을 허용했을때, false 일 때 권한요청을 거부했을때 작업을 부여할 수 있다.

import UserNotifications

class NotificationCenter {
    static let shared = NotificationCenter()
    
    private init() { }
    
    func requestAuthorization() {
        let options: UNAuthorizationOptions = [.alert, .sound, .badge]
        UNUserNotificationCenter.current().requestAuthorization(options: options) { granted, error in
            if granted {
                // 권한 허용했을 때
            } else {
                // 권한 거부했을 때
            }
            
            if let error = error {
                // 에러 발생
            }
        }
    }
}

 

아래와 같이 권한요청이 가능하다

import SwiftUI

struct ContentView: View {
    private let notificationCenter = NotificationCenter.shared
    
    var body: some View {
        VStack {
            Button("Notification 권한 요청") {
                notificationCenter.requestAuthorization()
            }
            .buttonStyle(.bordered)
        }
    }
}

 

Notification 메세지 설정하기

이제 권한요청을 완료했다면 어떤 메세지를 보낼 것인가에 대한 문제인데, 예를들어 매일 오전 9시에 알림을 보낸다고 생각해보자. 아래의 함수를 추가해주면 된다. badge 의 경우 앱의 우측 상단에 있는 빨간원에 있는 숫자를 표현한다고 보면 된다.

    func schedule() {
        let content = UNMutableNotificationContent()
        content.title = "title"
        content.subtitle = "subtitle"
        content.sound = .default
        content.badge = 0
        
        var dateComponents = DateComponents()
        dateComponents.hour = 09
        dateComponents.minute = 00
        
        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
        
        let request = UNNotificationRequest(
            identifier: UUID().uuidString,
            content: content,
            trigger: trigger
        )
        
        UNUserNotificationCenter.current().add(request)
    }

 

나는 5시 5분으로 설정 해 보았는데 아래와 같이 나온다.

 

Notification 취소하기

만약 설정했는데 Notification 을 받고싶지 않다면? 아래의 함수를 추가해주면 된다.

    func cancel() {
        let center = UNUserNotificationCenter.current()
        center.removeAllPendingNotificationRequests()
    }

 

Notification 권한상태 확인하기

권한상태를 확인하려면 아래와 같은 함수를 통해 확인할 수 있다. 공식문서에서는 authorized, provisional 일 경우 권한이 허용된 경우로 생각하는 듯 하다.

    func checkAuthorization() {
        let center = UNUserNotificationCenter.current()
        
        center.getNotificationSettings { settings in
            let status = settings.authorizationStatus
            
            if status == .notDetermined {
                // 권한을 물어보지 않았을 때
            } else if status == .denied {
                // 권한이 거부되었을 때
            } else if status == .authorized && status == .provisional {
                // 권한이 있을때
            }
        }
    }

 

권한상태의 종류를 살펴보면 아래와 같이 5가지의 경우의 수가 있는데 설명에 자세하게 나와있다.

@available(iOS 10.0, *)
public enum UNAuthorizationStatus : Int, @unchecked Sendable {
    
    // The user has not yet made a choice regarding whether the application may post user notifications.
    case notDetermined = 0

    
    // The application is not authorized to post user notifications.
    case denied = 1

    
    // The application is authorized to post user notifications.
    case authorized = 2

    
    // The application is authorized to post non-interruptive user notifications.
    @available(iOS 12.0, *)
    case provisional = 3

    
    // The application is temporarily authorized to post notifications. Only available to app clips.
    @available(iOS 14.0, *)
    case ephemeral = 4
}

 

전체 코드

import UserNotifications

class NotificationCenter {
    static let shared = NotificationCenter()
    
    private init() { }
    
    func checkAuthorization() {
        let center = UNUserNotificationCenter.current()
        
        center.getNotificationSettings { settings in
            let status = settings.authorizationStatus
            
            if status == .notDetermined {
                // 권한을 물어보지 않았을 때
            } else if status == .denied {
                // 권한이 거부되었을 때
            } else if status == .authorized && status == .provisional {
                // 권한이 있을때
            }
        }
    }
    
    func requestAuthorization() {
        let options: UNAuthorizationOptions = [.alert, .sound, .badge]
        UNUserNotificationCenter.current().requestAuthorization(options: options) { granted, error in
            if granted {
                // 권한 허용했을 때
            } else {
                // 권한 거부했을 때
            }
            
            if let error = error {
                // 에러 발생
            }
        }
    }
    
    func schedule() {
        let content = UNMutableNotificationContent()
        content.title = "title"
        content.subtitle = "subtitle"
        content.sound = .default
        content.badge = 0
        
        var dateComponents = DateComponents()
        dateComponents.hour = 09
        dateComponents.minute = 00
        
        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
        
        let request = UNNotificationRequest(
            identifier: UUID().uuidString,
            content: content,
            trigger: trigger
        )
        
        UNUserNotificationCenter.current().add(request)
    }
    
    func cancel() {
        let center = UNUserNotificationCenter.current()
        center.removeAllPendingNotificationRequests()
    }
}