본문 바로가기

MOBILE/ios

[iOS] UNUserNotificationCenterDelegate 로 보낸 로컬 알람 처리하기

지난 포스팅에서는 UNUserNotification 객체를 사용하여 로컬 알람을 보내는 방법을 알아보았다.

 

[iOS] UserNotification으로 로컬 알림 사용하기

로컬 알림은 앱 내부의 메세지를 사용자에게 전달할 때 ios의 알림 센터를 거치도록 하여 전달하는 방식으로 이루어진다. 즉 앱이 종료되어 있거나 백그라운드 상태에서도 사용자 알림을 보낼

josushell.tistory.com

 

로컬 알림은 잘 활용하면 사용자에게 아주 좋은 효과를 줄 수 있다는 점에서 유용하다.

하지만 로컬 알림이 알림에서 그치지 않고 사용자 액션으로 이어질 수 있도록 하기 위해서는 어떻게 해야할까?

예를 들면, 카카오톡은 상단바 알림에서도 메세지를 보낼 수 있다. 또는 알림을 터치하면 그 카카오톡방으로 들어가게 된다.

 

이러한 사용자 액션은 델리게이트 패턴을 이용하며, UNUserNotificationCenterDelegate 을 구현함으로써 만들 수 있다.

 

 

이러한 UNUserNotificationCenterDelegate의 메소드들을 살펴보자

UNUserNotificationCenterDelegate


Delegate 객체 설정하기

앞에서 말했듯이 UNUserNotificationCenterDelegate 은 델리게이트 패턴으로 동작한다.

즉 이벤트를 받았을 때 이를 전달해줄 delegate 객체가 필요하다는 의미이다. delegate 객체는 이 이벤트를 받아 특정 코드를 실행한다.

UNUserNotificationCenterDelegate를 구현하는 클래스에서 delegate 속성을 self 로 설정해주면 된다.

 

지난 포스팅에서는 앱 화면이 뜨자마자 user에게 알람 권한을 요청하는 코드를 작성했다.

그렇다면 user가 승인한 경우에 UNUserNotificationDelegate 의 delegate 객체는 이때 설정해야 하는 것이다.

따라서 지난 포스팅에서의 코드를 이어서 UIApplication 클래스에 UNUserNotificationDelegate를 구현한다.

 

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    
    if #available(iOS 10.0, *) {
        let noti = UNUserNotificationCenter.current()
        noti.requestAuthorization(options: [.alert, .badge, .sound], completionHandler: {(didAllow, e) in
        	noti.delegate = self
        })
    }
      
    return true 
}

UNUserNotificationDelegate method

userNotificationCenter(_:didReceive:withCompletionHandler:)

앱의 실행 유무와 상관없이, 사용자가 실제로 알람을 클릭하면 실행된다.

 

optional func userNotificationCenter(_ center: UNUserNotificationCenter, 
                          didReceive response: UNNotificationResponse, 
               withCompletionHandler completionHandler: @escaping () -> Void)

Parameters

center

notification을 받는 notification center 객체이다.

response

notification에 대한 user의 응답이 전달된다. 이 객체는 notification 정보와 사용자가 선택한 action에 대한 identifier를 포함한다. 카카오톡 처럼 textual response가 가능하도록 되어있다면, 이 객체 대신에 UNTextInputNotificationResponse 객체가 전달된다.

completionHandler

user의 응답에 대한 작업이 끝났을 때 실행되는 블록이다. 이 핸들러는 system에게 user action에 대한 처리가 끝났음을 알려주는 역할을 하기 때문에 반드시 호출해야 한다. 하지 않는 경우에는 custom action에 대한 작업이 실행되지 않는다.

Discussion

이 메소드는 synchronous한 code에서 호출 가능하다. asynchronous 하게 작동하기 위해서는 다음 코드를 사용할 수 있다.

optional func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async

 

 

 

userNotificationCenter(_:willPresent:withCompletionHandler:)

이 메소드는 앱 실행 중에도 메세지가 도착했는지 알 수 있다. 반대로 이를 구현하지 않으면 앱 실행 도중에 도착한 알림은 배너 형태로 표시되지 않는다.

optional func userNotificationCenter(_ center: UNUserNotificationCenter, 
                         willPresent notification: UNNotification, 
               withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)

Parameters

center

notification을 받는 notification center 객체이다.

notification

전달되고자 하는 알림이다. 이 객체 안의 정보를 사용하여 action을 정한다. 

completionHandler

알람에 대한 선택 사항과 함께 실행한다. 이 handler를 통해 system에게 어떻게 알람을 보낼지 알려주게 된다. 

options

사용자에게 알람을 보낼때 사용하는 option이다. UNNotificationPresentationOptions 구조체에 정의되어 있다.

이 구조체의 속성은 다음과 같다.

 


실제로 사용자가 알림을 클릭했을 때 정보를 출력하도록 해보자.

이 경우 didReceive 메소드를 구현하면 된다.

 

알람을 다음과 같이 앱이 종료되고 난 후 5초 뒤에 보내지도록 했다고 가정한다.

 

  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).
        print("sceneWillResignActive")
        
        let noti = UNUserNotificationCenter.current()
        
        noti.getNotificationSettings(completionHandler: {settings in
            if settings.authorizationStatus == .authorized {
                // Allow 일때의 코드
                let notiContent = UNMutableNotificationContent()
                
                notiContent.badge = 1
                notiContent.title = "noti title"
                notiContent.subtitle = "this is noti subtitle"
                notiContent.body = "welcome to josushell's tistory"
                notiContent.sound = .default
                notiContent.userInfo = ["date" : Date()]
                
                let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
                
                let request = UNNotificationRequest(identifier: "wake", content: notiContent, trigger: trigger)
                
                print("등록 완료")
                noti.add(request)
            }
        })
    }

 

이 경우 이에 대한 반응 코드는 다음과 같다.

 

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        if (response.notification.request.identifier == "wake") {
            print(response.notification.request.content.userInfo["date"]!)
        }
        completionHandler()
    }

알림 정보에서 userInfo 속성에서 읽고 싶은 값을 정의하면 된다.

이때 notification.request.identifier는 알림 요청 객체를 생성할 때 정의한 식별자이다.

 

결과는 다음과 같다.