본문 바로가기

Framework/UIKit

UserNotifications : 알림 Push 기능 구현하기

본 포스팅은 Swift 5.2.4 기준으로 작성되었습니다.

이번 포스팅에서는 우리 모두 너무나도 익숙한 Notification 을 Push 하는 방법에 대해 공부해보겠습니다. 혹시 이게 뭔지 잘 모르는 분들이 있을까봐 한마디로 설명해보자면 카톡이 왔을 때 아이폰에 뜨는 알림이 바로 Notification 입니다. 이제 딱 감이 왔나요?


사용자에게 알림을 보내기위해서는 UserNotifications 라는 Framework 를 사용해야 합니다. 오늘도 공식문서를 하나씩 살펴보면서 공부해볼거에요.

 

 

좀 내용이 긴데... 결론적으로 Notification 은 사용자에게 중요한 정보를 알리고자 할 때 사용하면 된다는 것을 길게 풀어놓았어요 ㅎㅎ

 

아무튼!! 이제 프로젝트를 하나 새롭게 만들고 같이 한번 만들어보도록할게요. 프로젝트가 생성되었으면 UserNotifications Framework 를 import 해줍니다. 참고로 저는 화면 중앙에 버튼을 하나 만들어놓고 이 버튼이 눌렸을 때 Notification 이 올 수 있도록 구현할 예정입니다.

 

import UserNotifications

 

우리가 구현하고자하는 기능은 UserNotifications Framework 에서 제공하는 UNUserNotificationCenter 를 이용해야 합니다.

 

 

Notification 실행에 관련된 모든 행동들을 관리하는 중요한 Object 라고 하네요.

 

그리고 이것을 통해서 할 수 있는 일들은 이런 것들이 있다고 합니다.

- 사용자에게 알림 및 뱃지를 보여주기 위한 권한요청

- 어떤 Notification Type 을 사용할 것인지 설정 (승인 및 취소 버튼을 넣는다거나하는 커스터마이징을 할 수 있습니다)

- 언제 Notification 이 보내질지 설정

- 사용자에게 전달된 Notification 에 대한 처리

- 그 외 Notification 에 관련된 여러가지 설정

 

이중에서 우리가 가장 먼저해야하는 일은 사용자에게 Push 알림을 위한 권한요청을 하는 것이에요. 그럼 권한 요청 코드를 바로 한번 작성해볼게요.


사용자에게 Push 권한 요청하기

먼저 UNUserNotificationCenter 는 Singleton 형태로 사용할 수 있습니다. 그리고 Singleton 인스턴스에는 current() 를 사용해 접근할 수 가 있어요.

 

let notificationCenter = UNUserNotificationCenter.current()

 

그냥 사용해도되지만 저는 접근 코드가 조금 긴 것 같으니 편하게 접근할 수 있도록 프로퍼티에 담아두도록 할게요. 이제 권한요청을 할 수 있는 requestAuthorization() method 에 접근이 가능해졌습니다. 이 method 는 parameter 로 options 와 completionHandler 를 받게 되어있는데요. Options 를 통해 우리가 사용자에게 어떤 방식으로 알림을 보내고 싶은지 설정할 수 있으며 completionHandler 를 통해 에러 처리와 사용자가 승인 또는 거부를 했을 상황에 대한 처리를 각각 할 수 있습니다.

 

이번에는 .alert, .badge, .sound 3가지 옵션만 주도록 해보겠습니다. 이곳에서 전부 설명하기에는 글이 너무 길어질 수 있으니 적당히 넘어갈게요... 아무튼 여러가지 옵션들이 많이 제공되니 어떤 것들이 있나 꼭 한번 확인해보는걸 추천합니다!

 

private func generateUserNotification() {
    notificationCenter.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
        if let error = error {
            print(error)
        } else {
            if granted {
                print("Granted")
            } else {
                print("Not Granted")
            }
        }
    }
}

 

간단한 코드니까 저도 간단하게 설명을 해보자면 completionHandler 로 들어올 수 있는 값 중 grantederror 가 있습니다. 이 중 error 는 그냥 따로 처리할 수 있도록 분기를 나눠주었고요. granted 는 Bool 타입이므로 true 와 false 를 반환하니 각 상황에 맞는 코드를 작성할 수 있도록 다시 한번 분기를 나눠주었습니다. 즉 사용자의 승인까지 모든 것이 성공적으로 끝마쳐졌을 때는 print("Granted") 가 있는 곳으로 빠지게 됩니다.

 

사용자에게 권한 요청을 보내는 화면

그러니까 이제 우리는 granted 되었을 때 사용자에게 Notification 을 보내주도록 작업해주면 되겠죠? UNUserNotificationCenter.current() 에는 Notification 전달을 도와주는 .add method 가 있습니다. 이제 이것을 이용해서 사용자에게 알림을 보내주면 끝입니다.

 

 

.add method 의 공식문서를 보면 총 3가지의 parameter 를 받도록 되어있는데 이 중 우리가 눈여겨 볼 것은 request 입니다. 다른 값들은 optional 로 nil 을 줘도되지만 request 는 필수로 작성해야하는 부분이거든요. UNNotificationRequest 타입을 받도록 되어있는데 얘는 또 무엇일까요?

 

UNNotificationRequest 은 Notification 의 Content(내용) 와 Trigger Condition (발동 조건) 을 포함하는 요청이라고 나와있네요. 그리고 인스턴스 생성 시 identifier, content, trigger 3가지를 입력 받도록 되어 있어요.

 

첫번째 identifier 는 각각의 Notification 을 구분해주는 역할을 하며 어떤 Notification 을 임의대로 지우고 싶을 때 이 identifier 를 통해 특정 Notification 만 삭제할 수 있습니다.


Content 생성하기

두번째로는 content 인데요. 무엇인지 정확히 모르지만 UNNotificationContent 타입을 받도록 되어있어요. 처음보는 타입이니까 이 타입이 무엇인지부터 확인해봐야겠죠?

 

 

음... 수정할 수 없는 형태의 content 라고하네요. Overview 의 마지막 문단을 읽어보면 이것을 인스턴스화 시키기말고 UNMutableNotificationContent 를 만들어서 쓰라고 되어있어요.

 

수정이 가능한 Content!! 이제 뭔가 좀 제대로 찾아온 느낌이 드네요 ㅎㅎ 이것을 인스턴스화 해서 사용하라고 나와있어요.

 

이름에 Content 가 들어가는 만큼 당연히 Notification 의 내용을 구성하는 것에 관련된 class 일 것 같은 느낌이에요. 우리가 접근할 수 있는 method 목록을 봐도 title, subtitle, body 등 내용을 나타내는 것이 확실해졌어요. 그럼 UNMutableNotificationContent 를 인스턴스화 시키고 기본적인 내용들을 입력해보도록 할게요.

 

private func generateUserNotification() {
    notificationCenter.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
        if let error = error {
            print(error)
        } else {
            if granted {
                let content = UNMutableNotificationContent()
                content.title = "This is title"
                content.subtitle = "This is subtitle"
                content.body = "This is body"
                content.badge = 1
            } else {
                print("Not Granted")
            }
        }
    }
}

 

이렇게 Content 가 생성되었어요. 이제 마지막 항목인 Trigger Condition 을 만들어 볼까요?


Trigger Condition 생성하기

Trigger Condition 은 UNNotificationTrigger 타입을 받고 있습니다. 

 

이번에도 문서를 읽어보니 이 타입은 바로 인스턴스화 시켜서 사용하지 말고 Subclass 를 이용하라고 나와있네요.

 

Subclass 의 종류로는 이렇게 4종류가 있습니다.

- UNTimeIntervalNotificationTrigger

- UNCalendarNotificationTrigger

- UNLocationNotificationTrigger

- UNPushNotificationTrigger

 

이름만 읽어봐도 어떤 것을 기준으로 Notification 이 발동될지 느낌이 오네요. 일단 우리는 이번에 UNTimeIntervalNotificationTrigger 을 사용해서 Trigger Condition 을 생성해보도록 하겠습니다. 이전에 작성한 Content 아래쪽에 입력해주세요.

 

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)

 

간단하죠? Trigger 가 발동되면 3초 뒤에 Notification 이 올 수 있도록 설정해놓았어요.


Request 생성 및 Notification 등록

이제 Content 와 Trigger Condition 이 모두 준비되었으니까 초반에 만들려고 했었던 UNNotificationRequest 을 생성해보도록 하겠습니다.

 

let request = UNNotificationRequest(identifier: "Sample Notification", content: content, trigger: trigger)


그리고 이제 마지막으로 .add method 에 생성한 request 를 등록해주면 끝입니다.

 

private func generateUserNotification() {
    notificationCenter.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
        if let error = error {
            print(error)
        } else {
            if granted {
                let content = UNMutableNotificationContent()
                content.title = "This is title"
                content.subtitle = "This is subtitle"
                content.body = "This is body"
                content.badge = 1
                let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
                
                let request = UNNotificationRequest(identifier: "Sample Notification", content: content, trigger: trigger)
                self.notificationCenter.add(request, withCompletionHandler: nil)
            } else {
                print("Not Granted")
            }
        }
    }
}

 

이제 실행을 해보면 Notification 이 도착하는 것을 확인해볼 수 있습니다. 추가적으로 우리가 아까 작성했던 Title 과 Subtitle 그리고 Body 가 무엇인지도 확실히 알 수 있겠죠~~??