[SwiftUI] Local Notifications

Junyoung Park·2022년 8월 18일
1

SwiftUI

목록 보기
11/136
post-thumbnail
post-custom-banner

How to schedule local Push Notifications in SwiftUI | Continued Learning #11

Local Notifications

  • 실제 노티는 서버에서 푸시하는 게 일반적
  • 로컬 특정 조건이 만족된다면 서버를 사용하지 않아도 푸시 가능
  • 좋은 UI의 기본이 될 수 있는 방법

구현 목표

구현 태스크

  1. 알림 요청 허가를 받는다.
  2. 알림을 주는 기준에 따라 트리거를 설정한다.
  3. 알림에 따른 효과(배지 등)를 조작한다.

핵심 코드

return UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)

...
 let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger.trigger)
        UNUserNotificationCenter.current().add(request)

소스 코드

import SwiftUI
import UserNotifications
import CoreLocation

class NotificationManager {
    static let instance = NotificationManager()
    private init() {}
    
    func requestAuthorization() {
        let options: UNAuthorizationOptions = [.alert, .sound, .badge]
        UNUserNotificationCenter.current().requestAuthorization(options: options) { (success, error) in
            if let error = error {
                print(error.localizedDescription)
            } else {
                print("SUCCESS")
            }
        }
    }
    
    enum TriggerType: String {
        case time = "time"
        case calendar = "calendar"
        case location = "location"
        
        var trigger: UNNotificationTrigger {
            switch self {
            case .time:
                return UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
            case .calendar:
                let dateComponents = DateComponents(hour: 20, minute: 26, weekday: 2)
                return UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
            case .location:
                let coordinate = CLLocationCoordinate2D(latitude: 40.0, longitude: 50.0)
                let region = CLCircularRegion(center: coordinate, radius: 100, identifier: UUID().uuidString)
                region.notifyOnExit = false
                region.notifyOnEntry = true
                return UNLocationNotificationTrigger(region: region, repeats: true)
            }
        }
    }
    
    func scheduleNotification(trigger: TriggerType) {
        let content = UNMutableNotificationContent()
        content.title = "This is my first Notification"
        content.subtitle = "This was so easy!"
        content.sound = .default
        content.badge = 1
        
        let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger.trigger)
        UNUserNotificationCenter.current().add(request)
    }
    
    func cancelNotification() {
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
    }
}

struct LocalNotificationBootCamp: View {
    let manager = NotificationManager.instance
    var body: some View {
        VStack(spacing: 40) {
            Button("Request Permission") {
                manager.requestAuthorization()
            }
            Button("Schedule Notification Time") {
                manager.scheduleNotification(trigger: .time)
            }
            Button("Schedule Notification Calendar") {
                manager.scheduleNotification(trigger: .calendar)
            }
            Button("Schedule Notification Location") {
                manager.scheduleNotification(trigger: .location)
            }
            Button("Scedule Delete") {
                manager.cancelNotification()
            }
        }
        .onAppear {
            UIApplication.shared.applicationIconBadgeNumber = 0
        }
    }
}
  • 트리거 종류에 따른 enum을 만들어 파라미터에 곧바로 기본값으로 따라오도록 구현했다. 만일 시간, 날짜 등 커스텀할 필요가 있다면 위와 같은 연산 프로퍼티가 아니라 파라미터로 값을 전달하는 함수를 TriggerType 안에 구현하면 된다.
  • 알림이 오면 배지 개수를 1로 고정했는데, 기본 동작대로라면 누적 합이 옳다. 또한 배지 카운트를 빼주는 동작을 onAppear, 즉 현재 뷰를 다시 확인하는 것을 기준으로 했는데, 기본 동작대로라면 백그라운드 상태에서도 동작하도록 수정하면 좋을 것 같다.

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글