inflearn logo
강의

講義

知識共有

[Lv.2] SwiftUI 中級 - Core Data と SwiftData でアプリを完成させる

ローカル通知

Local Notification 예제 문의

320

icopy

投稿した質問数 21

0

예제를 전부 구현한 상태에서

아래 코드를 통해서 뱃지 숫자를 1씩 올려서 보내게

되어 있습니다.

 

func scheduleNotification() {
        //notification 내용 설정
        let content = UNMutableNotificationContent()
        content.title = "Local Notification 테스트 1"
        content.subtitle = "앱 알람 테스트 중입니다."
        content.sound = .default
        content.badge = NSNumber(value: UIApplication.shared.applicationIconBadgeNumber + 1)

하지만 아래 코드에 의해 뱃지가 0 으로 리셋되기에
항상 1만 발송하게 됩니다.

.onChange(of: scenePhase) { newValue in
            if newValue == .active {
                UIApplication.shared.applicationIconBadgeNumber = 0
            }
        }

추가적으로 5초 딜레이로 설정후 로컬노티 여러번 누른후에
앱을 종료하고 기다리면 노티가 여러개 오지만
모두 뱃지 1로 오기 때문에 앱아이콘에 뱃지는 1로 계속

옵니다.

 

실무에서 로컬노티에 카운터를 현재 뱃지 카운터에 + 1 해서
보내는건 실효성이 없어보이는데요.

 

따로 해결할 방법이 있을까요 ? 조언 부탁드립니다.

 

강의 관련된 질문은 언제나 환영입니다 😄

ios swift swiftui iphone-app

回答 2

1

jacobko

안녕하세요 랑프님.

앱이 활성화될 때마다 UIApplication.shared.applicationIconBadgeNumber = 0으로 뱃지가 초기화되므로, 로컬 알림을 여러 번 발송해도 모든 알림이 뱃지 값이 1인 상태로 도착합니다. 이는 알림의 뱃지 값이 항상 초기화되기 때문에 발생합니다.

이를 해결하기 위해서 UserDefaults 를 사용해서 뱃지 값을 저장하고 불러오는 방법을 사용하면 됩니다.

수정된 코드는 다음과 같습니다. *수정한 부분만 사진으로 올려드리고 전체 코드는 맨아래 있습니다.

  1. 앱이 종료 되어도 뱃지값 저장하기

image

  1. CancelNotifiactaion 에서 값 초기화

image

  1. View에서 화면이 나타날때 reset 하는거 삭제

image

  • 수정된 코드

class NotificationManager {
    
    static let instance = NotificationManager() // 인스턴스 생성
    
    func requestAuthorization() {
        
        let option: UNAuthorizationOptions = [.alert, .sound, .badge]
        
        // UserNotification 접근
        UNUserNotificationCenter.current().requestAuthorization(options: option) { (success, error) in
            if let error = error {
                print("에러: \(error)")
            } else {
                print("성공")
            }
        }
    }
    
    func scheduleNotification() {
        
        // UserDefaults 에다가 자장할 currentBadgeCount
        let currentBadgeCount = UserDefaults.standard.integer(forKey: "badgeCount")
        
        // 값을 1씩 증가 시킴
        let newBadgeCount = currentBadgeCount + 1
        // 증가한다음에서는 값을 저장
        UserDefaults.standard.set(newBadgeCount, forKey: "badgeCount")
        
        // notification 내용 설정
        let content = UNMutableNotificationContent()
        content.title = "Local Notification 테스트 1"
        content.subtitle = "앱 알람 테스트 중입니다"
        content.sound = .default
        content.badge = NSNumber(value: newBadgeCount) // 1씩 증가 시킴
        
        
        // Trigger 2가지 종류
        
        
        // 1.시간 기준 : Interval - 몇 초 뒤에 울릴것인지 딜레이 설정 repeats 반복 여부 설정 (최소 1분이여지 반복이 돔)
        let timeTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 5.0, repeats: false)
        
        
        // 2.날짜 기준 : DateMating 은 DateComponent 기준맞는 알림
        var dateComponents = DateComponents()
        dateComponents.hour = 8 // hour 를 24시간 기준
        dateComponents.minute = 30
        dateComponents.weekday = 1 // 1은 일요일이 되고, 6은 금요일이 됨
        
        //		let calendarTigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
        
        
        // 설정한 값을 NotificationCenter 에 요청하기
        let request = UNNotificationRequest(
            identifier: UUID().uuidString, // 각각의 request ID 값 String 을 uuid 값으로 설정
            content: content,
            trigger: timeTrigger)
        UNUserNotificationCenter.current().add(request)
    }
    
    // 생성된 Notification Cancel 하기
    func cancelNotification() {
        
        // peding notification 은 tigger 상에서 만족된 조건이 되어도 더이상 notification 되지 않게 하기
        UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
        
        // 아이폰 상태바를 내렸을때 남아있는 notification 없애기
        UNUserNotificationCenter.current().removeAllDeliveredNotifications()
        
        
        // Cancel 하면 UserDefault 값 초기화 하기
        UserDefaults.standard.set(0, forKey: "badgeCount")
        UIApplication.shared.applicationIconBadgeNumber = 0
    }
    
    
}


struct LocalNotificationInter: View {
    
    @Environment(\.scenePhase) var scenePhase
    
    var body: some View {
        VStack (spacing: 40) {
            Button {
                NotificationManager.instance.requestAuthorization()
            } label: {
                Text("권한 요청하기")
                    .font(.title2)
                    .fontWeight(.semibold)
                    .foregroundColor(.black)
                    .padding()
                    .background(Color.green)
                    .cornerRadius(10)
            }
            
            Button {
                NotificationManager.instance.scheduleNotification()
            } label: {
                Text("Time Notification")
                    .font(.title2)
                    .fontWeight(.semibold)
                    .foregroundColor(.black)
                    .padding()
                    .background(Color.green)
                    .cornerRadius(10)
            }
            
            Button {
                NotificationManager.instance.scheduleNotification()
            } label: {
                Text("Calendar Notification")
                    .font(.title2)
                    .fontWeight(.semibold)
                    .foregroundColor(.black)
                    .padding()
                    .background(Color.green)
                    .cornerRadius(10)
            }
            
            
            Button {
                NotificationManager.instance.cancelNotification()
            } label: {
                Text("Notification 취소하기")
                    .font(.title2)
                    .fontWeight(.semibold)
                    .foregroundColor(.black)
                    .padding()
                    .background(Color.green)
                    .cornerRadius(10)
            }
            
        } //: VSTACK
        // schne 이 나타 날때 Badge 0 으로 초기화 하기
        .onChange(of: scenePhase) { newValue in
            if newValue == .active {
                // 0으로 초기화 되지 않게 reset 하지 않기
//                UIApplication.shared.applicationIconBadgeNumber = 0
            }
        }
    }
}

0

icopy

답변 감사합니다.

0

communityai8509

안녕하세요, 인프런 AI 인턴입니다.

랑프_Langpeu님의 질문에 대해 답변 드리겠습니다.

문제의 핵심은 앱이 활성 상태로 전환될 때 뱃지 숫자가 0으로 초기화되어, 로컬 알림으로 설정한 뱃지 숫자가 기대와 다르게 작동한다는 점입니다.

이문제를 해결하기 위해서는 애플리케이션이 활성 상태가 될 때마다 뱃지 숫자를 초기화하지 않고, 알림을 확인하거나 필요한 조치를 취했을 때 명시적으로 뱃지 숫자를 조정하는 로직을 구현해야 합니다.

전송되는 알림의 뱃지 숫자를 올바르게 관리하기 위해서는 애플리케이션 내부적으로 알림이 몇 번 전송되었는지를 추적할 필요가 있습니다. 이를 위해, 앱의 로컬 저장소나 데이터 베이스를 사용하여 알림이 발송될 때마다 카운터를 증가시키고, 앱이 활성화될 때 해당 카운터를 참조하여 UIApplication.shared.applicationIconBadgeNumber을 올바르게 설정하시는 것이 좋습니다.

예를 들어, 알림 발송 함수 내에서 뱃지 숫자를 증가시키는 로직을 추가하고:

func increaseBadgeNumberByOne() {
    let currentBadgeNumber = UserDefaults.standard.integer(forKey: "badgeNumber")
    UserDefaults.standard.set(currentBadgeNumber + 1, forKey: "badgeNumber")
    content.badge = NSNumber(value: currentBadgeNumber + 1)
}

앱이 활성 상태가 될 때 뱃지 숫자를 리셋하는 대신 사용자가 알림을 확인하였다는 가정하에 뱃지 숫자를 관리할 수 있는 로직을 추가합니다:

.onChange(of: scenePhase) { newValue in
    if newValue == .active {
        // 사용자가 알림을 확인했다고 가정하고 뱃지 숫자를 초기화
        UserDefaults.standard.set(0, forKey: "badgeNumber")
        UIApplication.shared.applicationIconBadgeNumber = 0
    }
}

이렇게 변경하면 앱이 활성화될 때마다 뱃지 숫자가 초기화되는 문제를 보완할 수 있습니다. 단, 이러한 방법은 알림이 발송될 때마다 앱 내부에서 뱃지 숫자를 관리해야 한다는 추가적인 구현이 필요합니다.

실제로 이 외에도 다양한 방법과 조건에 따라 뱃지 숫자를 관리할 수 있으므로, 애플리케이션의 특성과 필요에 맞게 적절한 로직을 설계하는 것이 중요할 것입니다.

수강 기간 연장 문의

0

28

1

수강연장부탁드려도될까요..

0

42

2

Combine Playground 에서 실행 시

0

57

2

70강 - 글로벌 액터로 격리된 Protocol 을 extension 에서 conform 시 타입 본체의 격리 수준 질문

0

42

1

searchable이 화면 하단에 위치해요

0

62

2

Drawing Cycle 관련 질문

0

72

1

앱 제작 시 주로 코드로 작성하시는 이유가 있을까요?

0

95

2

델리게이트 패턴 관련 질문

0

66

2

ios 애드몹 광고

0

134

2

수강 기간 연장 부탁드릴 수 있을까요?

0

61

1

Sorted, Filter, Map - UserViewModel 부분 오류 발생

0

102

1

ViewBuilder 강의 관련 질문입니다.

0

80

1

CoreData Array의 변화에 따른 SwiftUI View 변화 적용(with @Observable Macro)

0

205

2

init-deinit의 무한루핑을 벗어나는 방법이 궁금합니다.

1

167

2

Apple 공식 문서 보는법

0

325

2

5월 업데이트 예정이었던 , iOS17 컨텐츠 SwifData 업데이트 언제 되나요 ?

0

252

1

Spacer() 를 넣으니 예제처럼 SafeArea 확보가 안됩니다.

0

490

3

Local Notification 강의 편집오류 있어요

0

236

2

강의중 코드폴딩 단축키 (커맨트+옵션+왼쪽방향키)

0

208

2

코어데이터에 중복값 입력 방지

0

313

1

Combine 관련 질문드립니다.

0

244

1

if let else 질문있습니다.

0

220

1

강의 Weak Self 코드 실행시 오류에 대해

0

653

1

SwiftData가 Core Data를 대체하는지요?

0

2111

1