deprecated/코로나 알림(project-ios)

[iOS14] 백그라운드에서 특정 시간 로컬 알림보내기

lgvv 2021. 7. 29. 16:31

[iOS14] 백그라운드에서 특정 시간 로컬 알림보내기

 

로컬알림 예시

로컬 알림이란 서버없이 로컬에서 알림 호출.

 

글의 목차

1. 로컬 알림은 어떤 처리과정을 거칠까?

2. SceneDelegate에서 로컬 알림 보내기 

3. AppDelegate에서 권한 얻기

4. 특정 시간 말고 다른 trigger는?

 

✅ 1. 로컬 알림은 어떤 처리과정을 거칠까?

    - 로컬 알림 발송의 4단계 - 

 1️⃣ 발송한 내용을 정의 UNMuatableNotificationContent
 2️⃣ 발송 조건의 정의 UNTimeIntervalNotificationTrigger
 3️⃣ 알림 요청을 만듦 UNNotificationRequest
 4️⃣ 노티피케이션 센터에 해당 요청을 등록 UNUserNotificationCenter

 

위의 네 가지 단계로 구성.

 

✅ 2. SceneDelegate에서 로컬 알림 보내기 

func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
        
        if #available(iOS 10.0, *) { // iOS 버전 10 이상에서 작동
            
            UNUserNotificationCenter.current().getNotificationSettings { settings in
                
                if settings.authorizationStatus == UNAuthorizationStatus.authorized {
                    /*
                     로컬 알림을 발송할 수 있는 상태이면
                     - 유저의 동의를 구한다.
                     */
                    let nContent = UNMutableNotificationContent() // 로컬알림에 대한 속성 설정 가능
                    nContent.title = "🦠오늘의 코로나 현황 알림⏰"
                    nContent.subtitle = "총 확진자 : \n 우리지역 확진자 : "
                    nContent.body = "총 확진자 : \n 우리지역 확진자 : "
                    nContent.sound = UNNotificationSound.default
                    nContent.userInfo = ["name":"lgvv"]
                    
                    var date = DateComponents()
                    date.hour = 15
                    date.minute = 52
                    
                    
                    // 알림 발송 조건 객체
                    let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: false)
                    // 알림 요청 객체
                    let request = UNNotificationRequest(identifier: "wakeup", content: nContent, trigger: trigger)
                    // NotificationCenter에 추가
                    UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
                } else {
                    NSLog("User not agree")
                }
            }
            
        } else {
            NSLog("User iOS Version lower than 13.0. please update your iOS version")
            // iOS 9.0 이하에서는 UILocalNotification 객체를 활용한다.
        }
        
    }

 

우선 우리가 백그라운드로 들어갔을 때, 코드가 작동하게 만들 예정이므로, SceneDelegate 부분에서 백그라운드로 넘어갔을 때의 메소드 부분에 작성해 줄 필요가 있음.

 

맨 위에 if 조건은 우리가 백그라운드에서 알림 보내는 권한을 허락했는지 하지 않았는지에 대해서 검사하는 부분.

권한을 주었을 때만 돌아가게끔!! -> 권한 설정은 AppDelegate 부분에 작성하도록 하는 것이 앱을 처음 설치할 때, 작동하므로 효율적이다.

 

nContent 부분은 우리의 알림에 표시될 부분들

date 변수는 특정 시간을 지정해주고

trigger 변수를 통해 어떤 조건에서 발생시킬건지 정의해준 다음.

request 변수를 통해 우리가 만든 notification에 id와 content 내용 그리고 발생조건을 주어서 객체를 만들어

그리고 마지막으로 NotificationCenter에 등록하면 끝!

 

❗️UNUserNotificationCenter 는 싱글톤 패턴으로 작성되어 있어서 우리가 마음대로 객체를 선언하면 안된다.

그럼 if문을 통과하기 위해서 권한은 어떻게 얻어야 함.

 

✅ 3. AppDelegate에서 권한 얻기

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        if #available(iOS 11.0, *) {
                    // 경고창 배지 사운드를 사용하는 알림 환경 정보를 생성하고, 사용자 동의여부 창을 실행
                    let notiCenter =  UNUserNotificationCenter.current()
                    notiCenter.requestAuthorization(options: [.alert, .badge, .sound]) { (didAllow, e) in }
                    notiCenter.delegate = self // 이 코드는 사용자가 알림을 클릭하여 들어온 이벤트를 전달받기 위한 델리게이트 패턴구조
                    // 즉, 알림 센터와 관련하여 뭔가 사건이 발생하면 나(앱 델리게이트) 한테 알려줘 이런 의미임
                    /* 클로저 매개변수 설명
                     사용자가 메시지 창의 알림 동의 여부를 true / false
                     오류 발생시 사용하는 오류 발생 타입의 매개변수 e
                     */
                } else {
                    // 경고창, 배지, 사운드를 사용하는 알림 환경 정보를 생성하고, 이를 애플리케이션에 저장.
                    let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
                    application.registerUserNotificationSettings(setting) // 생성된 정보 애플리케이션에 등록
                }
        return true
    }
    
    /*
       유저노티피케이션센터는 프로토콜이다. 그래서 위에 노티센터.딜리게이트 셀프 이 코드가 있어야 작성가능하다.
       이 메소드는 알림 배너의 표시 여부와 관계없이 알림이 도착하면, 호출된다.
       */
      @available(iOS 10.0, *)
      func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
          if notification.request.identifier == "wakeup" { // 로컬 알림 등록시 입력한 식별 아이디를 읽어오는 속성
              let userInfo = notification.request.content.userInfo // 유저가 커스텀으로 정의한 정보를 읽어오는 역할
              print(userInfo["name"]!) // 딕셔너리 값을 출력
          }
          // 알림 배너 띄워주기
          completionHandler([.alert, .badge, .sound])
      }

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        /*
         앞에서와 비슷하지만, 이 메소드는 실제로 사용자가 알림 메시지를 클릭 했을 경우에 실행된다는 차이를 가짐.
         이떄 알림 메시지에 대한 정보는 모두 위 메소드의 두번쨰 인자값인 response 매개변수에 담겨 전달됩니다.
         */
        
        if response.notification.request.identifier == "wakeup" {
            let userInfo = response.notification.request.content.userInfo
            print(userInfo["name"]!)
        }
        completionHandler()
    }

 

코드를 쭉 읽어보면 쉽게 이해할 수 있을 것이다. 

우선 appDelegate쪽에 코드를 작성하고, iOS11 이상과 다른 버전에서의 작동하는 방식이 달라서 분기해서 권한을 얻어온다.

그리고 아래에 willPresent와 didReceive 두 가지가 있는데 전자는 알림 배너를 띄우는 역할, 후자는 알림 배너를 클릭했을 때 처리할 이벤트를 넣어준다. (예를 들면 배너 클릭 시, 앱의 시작이 아닌 그 곳으로 바로 이동하게 설정해줄 수도 있다.)

 

✅ 4. 특정 시간 말고 다른 trigger는?

물론 특정 시간에만 보내는 것 말고도 다양한 트리거들이 존재한다.

https://developer.apple.com/documentation/usernotifications

 

Apple Developer Documentation

 

developer.apple.com

애플 공식 문서에 따르면

트리거들

특정 시간이 아니라 지역, 푸쉬, 일정시간 반복 등 다양한 것들이 존재하니까 잘 활용해 보도록 하자.

공식 문서에 가면 더 다양한 정보가 있어서 참고하면 좋겠다...!