SwiftUI

[SwiftUI] Remote Notification 원격 알림 (1)

하이D:) 2023. 8. 20. 19:23

이전 글에서 로컬 알림 기능이 어떻게 구현되는지와 기기에 설정된 앱의 알림 기능을 확인하는 방법에 대해서 알아보았다면, 이번에는 푸시 서버로부터 사용자의 기기까지 어떻게 원격 알림이 전달되는지에 대한 전반적 개념을 알아보고자 한다.

 

[SwiftUI] Remote Notification 원격 알림 (1)

[SwiftUI] Remote Notification (2) FCM 서비스 사용하여 원격 알림 구현

 

 

알림 관련 이전 글

[SwiftUI] Local Notification 앱의 로컬알림 기능 구현

[SwiftUI] Notification | 알림설정확인 getNotificationSettings Provisional Authorization

 

 

# 🥨 원격 알림은 왜 필요할까?

제한된 기능만 수행할 수 있는 앱의 Background 상태에서도 사용자에게 정보 전달이 가능하게 하며,APP 제공자 (= Provider = Push Server)가 APP 설치자에게 실시간으로 메시지를 줄 수 있기 때문에 거의 대부분의 앱에서는 원격 알림 기능 구현이 필요하다.

 

 

# 🥨 앱 내에서 구현할 때 로컬 알림과 원격 알림의 차이점

로컬 알림과 원격 알림을 구현할 때의 차이는 크게 3가지 정도 있는 것 같다.

 

1. APNs로부터 받은 디바이스 토큰을 Push Server(Provider)에 등록해 놓는다.

Provider가 APNs에 알림 요청을 할 때 저장해 놓은 디바이스토큰 정보를 함께 전달하기 때문에 기기 토큰을 저장해 놓는다.

 

2. Provider와 APNs의 통신을 위해 인증서, 혹은 인증키가 필요하다.

p12 인증서를 통한 연결 방식, 또는 p8 인증키를 통한 연결방식을 통해 APN과 Provider 간의 신뢰설정을 해야 한다.

 

3. Capabilities 설정

  1) 애플 개발자 사이트에서 해당 앱을 Identifier에 등록하고 Capacilities에서 Push Notification를

  2) 프로젝트 > Target > Capabilities에 Push Notification, Background Mode 추가 및 Background Mode에는 Background Fetch와 Remote Notification이 선택되어 있어야 한다

 

이 세 가지 다른 점을 정확히 이해하기 위해서는 원격 알림이 생성되고 사용자에게 전달되는 과정에서 서로 소통하고 교환이 일어나는 주체들에 대한 이해가 필요한데 이 주요 주체들은 다음에 나오는 세 가지로 요약할 수 있다.

 

# 🥨  Remote Notification에서의 Provider & APNs & App

  • Provider (Push Server) : Prush Server로도 불리는 Provider는 알림을 만들어내는 어떤 것이든 여기에 포함될 수 있다. ( 해당 앱의 서버 혹은 뒤에서 다룰 FCM 같은 것들을 일컫는다.)
  • APNs : Apple Push Notification service로서 푸시 알림을 제공하는 역할을 한다. Push Server와의 보안 연결을 통해 Push Server가 설치된 앱에 푸시 알림을 보낼 수 있도록 하는 클라우드 서비스이며, Provider가 직접 앱으로 알림을 보낼 수 없고 APNs라는 플랫폼을 통해서만 알림을 보낼 수 있다는 점에서 원격 알림을 구현할 때 반드시 알아야 하는 개념이다. ( * 클라우드 서비스란 : 타사 제공 업체가 호스팅하여 인터넷을 통해 사용자에게 제공하는 인프라, 플랫폼 또는 소프트웨어를 말한다. 즉, 우리는 인프라를 관리하지 않고 사용하기만 하면 된다.)
  • App : 사용자가 설치한, 그 사용자가 알림을 받을 앱을 의미한다.

 

# 🥨 APNs 와 Provider간의 신뢰 설정 및 이를 위한 인증 종류 ( P12, P8 )

원격 알림에 대한 기능을 찾아보았다면 흔히 듣게 되는 p8, p12 인증 방법이 있다. 그렇다면 p8 인증 키나 p12 인증서 같은 인증 절차가 필요한 이유는 무엇일까? 다음과 같은 다양한 이유들이 있다.

  1. Server가 신뢰할 수 있는 소스임을 APNs에 증명해야 한다.
  2. 사용자의 개인정보가 포함되어 있다면 정보를 전송하기 전에 사용자와 앱 간의 연결이 안전한지 확인해야 한다. 인증을 통해 알림의 송수신이 암호화되며, 외부에서 엿볼 수 없도록 보호된다. 
  3. 이러한 인증절차를 통해 사용자가 설치한 앱은 APNs에 등록되고, 각 앱에 고유한 토큰이 부여된다. 이 토큰을 통해 알림을 특정 디바이스에 전달한다. 
  4. 인증을 사용하여 앱이나 서버가 APNs와 통신하도록 하면 APNs는 신뢰할 수 있는 소스만을 처리하게 되기 때문에 APNs의 효율과 성능을 향상시키고 무분별한 알림 요청으로 인한 부하를 줄인다.

 

즉, iOS 앱은 APNs를 사용하여 원격 알림을 받는데, 이때 디바이스가 알림을 받기 위해 APNs와 상호작용하는 과정에서 iOS 앱이 APNs와 원격 알림을 효율적으로 처리하고 보안 및 개인 정보 보호를 유지하기 위해서는 서버 측에 인증이 필요한 것이다. 

Push Server에서 생성한 알림 요청은 APNs로 보내기 위해서는 Provider 서버가 HTTP/2 및 TLS를 사용해서 토큰기반 신뢰 설정 (.p8 인증키를 통해) 또는 인증서 기반 신뢰 설정 (.p12 인증서를 통해) 을 해야하는데 이 두 가지 방법은 차이는 아래와 같다.

 

  • 인증서 기반 연결 방식 (p12)
    • 유효기간 1년이며,
    • 개발용, 프로덕션용 따로 발급받아야 하고,
    • 앱별로 개별 생성해주어야 한다.
  • 토큰 기반 연결 방식 (p8)
    • 여기서의 토큰은 서버와 APNs 간의 연결을 설정하는 데 사용되는 토큰(구체적으로 p8 인증서 키에서 생성된 인증 토큰)을 의미하며 APNs에서 발급해 주는 디바이스 토큰과는 다른 개념이다.
    • 유효기간은 없으며, 
    • 개발 및 프로덕션용 구분 없이 사용하고
    • 애플 디벨로퍼 계정별로 생성하여 모든 앱이 함께 사용할 수 있다.

 

# 🥨  푸시 알림을 받기 위한 필수 동작

  1. APNs와 앱의 연결이 설정되면 APN으로부터 장치 토큰을 받을 수 있다.
  2. 이 장치 토큰을 받으면 앱은 Provider에게 이 토큰을 전달하며 토큰값을 저장한다.

 

# 🥨 실제 푸시가 발생했을 때의 동작방식

  1. 알림이 발생할 때마다 Provider는 APNs에 어느 기기에(토큰) 어떤 알림 콘텐츠(payload)를 전달하게 된다.
  2. APNs는 해당 디바이스 토큰으로 데이터를 보내게 된다.
  3. 이렇게 알림을 발송하면 앱 설치자가 푸시알람으로 알림을 받아볼 수 있게 되는 것이다.

 

# 🥨 원격 알림 전반적 구현과정

1. 애플 디베로퍼 홈페이지에서 Identifier 등록 (등록한 Identifier에서 Capabilities로 Push Notification이 체크되어 있어야 한다.)

 

2. SwiftUI 앱을 만드는 경우 AppDelegate 파일을 만들고 UIApplicationDelegate 프로토콜 채택한 AppDelegate class를 정의한다.

class AppDelegate: NSObject, UIApplicationDelegate{
...
}

 

3. App 프로토콜을 채택한 프로젝트의 최상위 구조체에 delegate 정의해주어야 한다. 

import SwiftUI

@main
struct notificationTestApp: App {
    @UIApplicationDelegateAdaptor var delegate: AppDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

 

4. 앱에서 알림 기능을 사용하기 위해서는 알림 권한 설정을 해주어야 하며 AppDelegate class의

application(_:didFinishLaunchingWithOptions:) 메서드에서 알림 센터 인스턴스의 requestAuthorization메서드를 호출해 준다. 

let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
    guard error == nil else {
        print("Error while requesting permission for notifications.")
        return
    }
    
    print("Success while requesting permission for notifications.")
    
    DispatchQueue.main.async {
        //APNs에 디바이스 등록
        UIApplication.shared.registerForRemoteNotifications()
    }
}

 

5. 권한 요청에 성공했다면 UIApplication 싱글톤의 registerForRemoteNotifications 메서드를 통해 APNs에 디바이스를 등록한다.

UIApplication.shared.registerForRemoteNotifications()

 

6. APNs에 디바이스를 등록 성공, 실패했을 때 호출되는 메서드 작성

- APNS에 등록 성공하면 application(_:didRegisterForRemoteNotificationsWithDeviceToken:)메서드를 통해 디바이스 토큰을 확인할 수 있고,

- 실패하면 application(_:didFailToRegisterForRemoteNotificationsWithError:) 메서드를 통해  에러를 확인할 수 있다.

//디바이스가 APNs에 등록실패했을 때
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print(error.localizedDescription)
    print(error)
}

//디바이스가 APNs에 등록되었을 때
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let deviceTokenString = deviceToken.map { String(format: "%02x", $0) }.joined()
    print(deviceTokenString)
    
}

 

7. 프로젝트 > Targets에서 > Capabilities 탭에서 Push Notification & Background Mode 를 추가해야하고 Background Mode에서는 Background Fetch 와 Remote Notification 을 활성화해야한다. 

 

* 아래와 같은 에러가 뜰 때는 아마 두 가지 원인 중에 한 가지일 것이다. 

Error Domain=NSCocoaErrorDomain Code=3000 "응용 프로그램을 위한 유효한 ‘aps-environment’ 인타이틀먼트 문자열을 찾을 수 없습니다." UserInfo={NSLocalizedDescription=응용 프로그램을 위한 유효한 ‘aps-environment’ 인타이틀먼트 문자열을 찾을 수 없습니다.

원인 1) 애플디벨로퍼 페이지에서 identifier등록해 놓은 것에서 Capabilities에 Push Notification 체크 누락

원인 2) Xcode 에서 target - Capabilities tab 에서 Push Notification & Background Mode 를 추가해야하고 Background Mode 에서는 Background Fetch 와 Remote Notification 을 활성화해야한다.

 

 


 

이렇게 준비가 완료되면 p12 인증서를 발급받아 remote notification 테스터앱으로 원격 알림이 제대로 작동하는지 테스트해 볼 수 있게 된다.  (인증서 발급 참고 글 : https://babbab2.tistory.com/57 ) 하지만, 나는 p8 인증키를 통해 Firebase Cloud Messaging 서비스로 원격 알림을 구현해 보고자 하기 때문에 위의 구현과정을 기반으로 FCM를 연동해보고자 한다.

 

푸시 알림 테스터 앱으로 테스트해보고자 한다면 해당 Mac용 앱으로 시도해 볼 수 있다.

 

 

참고

iOS) APNs :: Push Notification 동작 방식

[iOS] Remote Notification (.p8 VS .p12)

[iOS] APNs push 인증서 방식 & 인증 토큰 방식

Establishing a token-based connection to APNs