-
iOS - Local NotificationiOS 2020. 12. 14. 15:05
Local Notification
[알림 설정 ]
알림을 받고 싶은 시점을 선택하면 해당 시점에 사용자에게 알려줌
이 기능이 Local Notification을 통해 구현할 수 있는 대표적인 기능
App에서 Notification을 예약하면 해당시점에 Notification을 전달한다.
App이 실행중이라면 App에게 전달하고 실행중이 아니라면 직접 배너를 통해 표시한다.
사용자는 Notification을 통해 중요한 정보나 알람을 빠르게 확인할 수 있다.
또한, Notification에 추가된 action을 통해서 App을 실행하지 않고도 간단한 작업을 수행할 수 있다.
Notification 구현은 크게 3단계로 나눌 수 있다.
[Asking Permisstion to Use Notification]
첫번째 단계에서는 Notification 권한을 요청한다.
사용자가 직접 허가한 경우에만 Local Notification을 예약하고 받을 수 있다
[Scheduling a Notification Locally from your App]
두번째 단계에서는 notification 객체를 생성하고 필요한 정보를 담아서 notificationCenter에 예약을 요청한다.
[Handling Notification and Notification-Related Actions]
세번째 단계에서는 notification이 전달되었을때 실행될 코드를 구현
notification은 실행상태에 따라서 호출되는 메소드가 달라진다.
App이 forground에서 실행되고 있다면 delegate 메소드가 호출된다.
반대로 background에서 실행되거나 아예 실행되고 있지 않다면 ios가 직접 notification을 표시한다.
그리고 사용자가 배너를 터치하거나 액션을 선택하면 연관된 delegate 메소드가 호출된다.
UserNotification freamwork에는 UNUserNotificationCenter class가 구현되어 있다.
Local Notification과 관련된 기능은 이 클래스가 제공하는 메소드를 통해 구현한다.
이 클래스의 인스턴스를 직접 생성하는 것은 불가능하고 .current가 리턴하는 싱글톤 인스턴스를 사용한다.
App으로 전달된 Local notification은 UNSerNotificationCenterDelegate 프로토콜을 통해 처리한다.
[프로젝트 직접 실습해보기]
1. 권한 요청
[AppDelegate.swift]
권한 요청은 대부분 AppDelegate안의 application 메소드 안에서 구현해야 한다.
만약 다른 곳에서 구현을 해야 한다면 Local Notification과 연관된 다른 코드를 실행하기 전에 호출될 수 있도록 구현해야 한다.
import UIKit import UserNotifications @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { //UNUserNotificationCenter.current() 로 UNUseNotificationCenter의 싱글톤 인스턴스를 얻은 다음 // 첫번째 파라미터 options는 notification을 전달하는 방식을 설정 // 두번째 파라미터에는 사용자가 허가여부를 선택한 후에 호출할 closer, 클로저에는 허가여부와 오류정보가 파라미터로 전달된다. UNUserNotificationCenter.current().requestAuthorization(options: [UNAuthorizationOptions.badge, .alert, .sound]) { (granted, error) in // 보통 사용자가 권한을 허가한 경우 델리게이트를 구현하고 나머지 초기화 작업을 진행한다. // 여기에서는 우선 delegate만 설정한다. if granted { UNUserNotificationCenter.current().delegate = self } print("granted \(granted)") } return true } } // notification과 관련된 초기화 작업은 항상 클로저에 전달되는 파라미터 값을 기준으로 해야한다 // 처음 사용자가 선택했던 값을 캐시에 저장하고 저장한 값을 재사용하는 것은 잘못된 방식이다. // 항상 현재 설정값을 기준으로 구현해야 한다. // 여기까지의 코드는 Local Notification을 구현하기 위한 최소한의 코드 // 그리고 remoteNotification 권한을 얻을 때도 동일한 코드를 사용한다. extension AppDelegate: UNUserNotificationCenterDelegate{ }
textField에서 메세지를 입력하고 picker view에서 시간을 선택한 다음 스캐줄 버튼을 탭하면 local notification을 예약하도록 구현!
import UIKit import UserNotifications class LocalNotificationViewController: UIViewController { var interval: TimeInterval = 1 @IBOutlet weak var inputField: UITextField! @IBAction func schedule(_ sender: Any) { // 버튼과 연결되어 있는 schedule 메소드에서 // local notification을 예약하도록 구현 // 이 클래스에 선언되어 있는 속성으로 local notification의 // 기본 속성을 설정해야 한다. let content = UNMutableNotificationContent() content.title = "Hello" content.body = inputField.text ?? "Empty body" //content.badge = 양수로 설정하면 숫자가 표시되고 0으로 설정하면 표시되지 않는다. content.badge = 123 // notification이 전달되었을때 나오는 sound 설정 //UNNotificationSound.default() -> 기본 사운드로 설정 content.sound = UNNotificationSound.default() // 위의 title, body, badge, sound는 모두 허가가 필요한 속성 // 예를들어 sound속성을 설정했다고해서 항상 sound가 재생되는 것은 아니다. // 권한을 요청할때 sound 옵션이 추가되어 있어야 하고, 설정 앱에서도 sound 권한이 허가되어 있어야 한다. // 그렇지 않은 경우는 속성으로 설정하더라도 재생되지 않는다. // 이어서 trigger를 통해 local notification이 전달되는 조건을 지정해야 한다. // 현재는 3개의 trigger를 사용할수 있다. // 1. UNCalendarNotificationTrigger // Notification이 전달되는 날짜와 시간을 직접 지정할때 사용 // 매일아침 몇시에 전달되어야 하거나 특정 시간에 전달되어야 한다면 // 이 트리거를 사용 // 2. UNTimeIntervalNotificationTrigger // 현재 시점을 기준으로 시간을 지정할때 사용 // 예를 들어 한시간뒤에 전달되어야 할 알람을 구현할 때 사용 // 3. UNLocationNotificationTrigger // 특정 지역에서 notification을 지정할때 // 사용자가 매장 부근에 진입했을때 notification을 통해 프로모션을 제공하는 기능을 제공할 수 있다. // 두번째 파라미터로 true를 전달하면 반복해서 전달된다. // 이 경우에는 반드시 60보다 큰 timeInterval을 전달해야 한다. // 60보다 작은 값을 전달하면 crush가 발생 let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false) // 첫번째 파라미터에는 식별자를 전달 // 예약된 local notification을 삭제하는 경우 사용 // let request = UNNotificationRequest(identifier: "test", content: content, trigger: trigger) // 마지막으로 실제 예약을 요청해야 한다. // 두번째 파라미터에는 예약결과를 처리하는 클로저를 전달하고 // 오류결과를 콘솔에 출력하도록 구현 UNUserNotificationCenter.current().add(request) { (error) in if let error = error{ print(error) }else{ print("Done") } } inputField.text = nil } // 전부 동일하게 했고 Done도 멀쩡히 출력되는데?~ // notification이 안온다. // ios 버전이 업되서 그런걸까 override func viewDidLoad() { super.viewDidLoad() } } extension LocalNotificationViewController: UIPickerViewDataSource { func numberOfComponents(in pickerView: UIPickerView) -> Int { return 1 } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return 60 } } extension LocalNotificationViewController: UIPickerViewDelegate { func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { return "\(row + 1)" } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { interval = TimeInterval(row + 1) } }
이 까지 했으면 분명히 notification이 잘 출력이 되야하는데
안된단 말이지.........
일단 다시 한번 보고 다음걸로 넘어가보자
앞서 말했듯이 Notification은 app이 forground일때와 background일때를 나눠서 코딩해줘야 한다.
[AppDelegate.swift]
extension AppDelegate: UNUserNotificationCenterDelegate{ // app이 forground일때 notification이 전달되면 // 이 메소드가 호출되고, 두번째 파라미터를 통해 notification이 전달된다. func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // 그리고 request 속성을 통해 local notification을 요청할때 전달한 content와 trigger instance에 접근할 수 있다. let content = notification.request.content let trigger = notification.request.trigger // 메소드에서 필요한 기능을 구현한 다음 반드시 세번째 파라미터로 전달된 CompletionHandler를 호출하고 notification 처리방식을 지정해야 한다. completionHandler([UNNotificationPresentationOptions.alert]) } // 사용자가 notification의 배너를 터치하거나 notificationCenter에서 notification을 통해 앱을 실행하면 이 메소드가 호출된다. func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // notification에 대한 정보는 두번째 파라미터를 통해 확인할 수 있다. let content = response.notification.request.content let trigger = response.notification.request.trigger // 위의 메소드와 마찬가지로 모든 코드를 수행하고 난뒤에는 세번째 파라미터로 전달받은 completionHandler() 를 호출해야 한다. completionHandler() } }
!! 이 코드 추가하니까 정상적으로 notification이 전달되는 것을 확인 할 수 있음!!
그리고 badge는 처음 설정한 123으로 표시되어 나오기 때문에 지금은 간단하게 앱 진입시 0으로 초기화 해주는 코드를 작성
[LocalNotificationViewController.swift]
override func viewDidLoad() { super.viewDidLoad() // 앱실행하면 badge 초기화 // UIApplication.shared -> app을 나타내는 sigleton instance에 접근할 수 있다. UIApplication.shared.applicationIconBadgeNumber = 0 }
'iOS' 카테고리의 다른 글
iOS - Password AutoFill (0) 2020.12.14 iOS - Remote Notification (0) 2020.12.14 iOS - textView (0) 2020.12.14 iOS - Button (0) 2020.12.11 iOS - UserDefaults (0) 2020.12.04