iOS) APNs(Apple Push Notification Service) - FCM Token 으로 앱에서 메시지 수신하기
아래의 게시물은 제가 이전에 작성해둔 푸시알림 APNs 설정 및 파이어베이스에 앱 추가하는 과정입니다.
iOS) APNs(Apple Push Notification Service)
- 이전 게시물에서는 파이어베이스에서 메시지를 테스트해보았다.
- 이번 프로젝트에서는 p8 인증키로 진행했다.
- 이번 프로젝트를 진행하면서 서버분들과의 협업으로 FCM Token 을 사용해서 앱에서 메시지를 수신하는 기능을 구현해 보았다.
📌iOS 클라이언트 설정
import UIKit
// import
import Firebase
import FirebaseMessaging
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Firebase 초기화 세팅.
FirebaseApp.configure()
// 메시지 대리자 설정
Messaging.messaging().delegate = self
// FCM 다시 사용 설정
Messaging.messaging().isAutoInitEnabled = true
// 푸시 알림 권한 설정 및 푸시 알림에 앱 등록
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { _, _ in })
application.registerForRemoteNotifications()
// device token 요청.
UIApplication.shared.registerForRemoteNotifications()
return true
}
/// APN 토큰과 등록 토큰 매핑
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
}
extension AppDelegate: MessagingDelegate {
/// 현재 등록 토큰 가져오기.
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
// TODO: - 디바이스 토큰을 보내는 서버통신 구현
sendDeviceTokenWithAPI(fcmToken: fcmToken ?? "")
}
}
✨등록 토큰 액세스
다음과 같은 경우에 등록 토큰이 변경될 수 있다.
- 새 기기에서 앱 복원
- 사용자가 앱 삭제/재설치
- 사용자가 앱 데이터 소거
메시지 대리자 설정
등록 토큰을 받으려면 [FIRApp configure]를 호출한 후
메시지 대리자 프로토콜을 구현하고 FIRMessaging의 delegate 속성을 설정합니다.
예를 들어 애플리케이션 대리자가 메시지 대리자 프로토콜을 준수하는 경우
application:didFinishLaunchingWithOptions:에서 대리자를 애플리케이션 대리자로 설정할 수 있습니다.
**라고 파이어베이스 개발문서에서는 명시되어있다. 어렵게 생각하지 않아도 된다. delegate 속성을 설정해서 대리자를 설정할 수 있다는 말이다. 그 후에는 다음과 같이 구현해주면 된다.extension** AppDelegate: MessagingDelegate { ... }
Messaging.messaging().delegate = self
현재 등록 토큰 가져오기
- 등록 토큰은
messaging:didReceiveRegistrationToken:메서드를 통해 전달됩니다. - 일반적으로 앱 시작 시 등록 토큰을 사용하여 이 메서드를 한 번 호출합니다. 이 메서드가 호출되면 다음과 같은 작업을 할 수 있습니다.
- 새 등록 토큰이라면 애플리케이션 서버에 전송합니다.
- 등록 토큰을 주제에 구독 처리합니다. 이 작업은 신규 구독 또는 사용자의 앱 재설치 같은 상황에서만 필요합니다.
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
// TODO: - 디바이스 토큰을 보내는 서버통신 구현
sendDeviceTokenWithAPI(fcmToken: fcmToken ?? "")
}
}
위처럼 일반적으로 앱 시작 시 등록 토큰을 사용해서 한 번 호출해보자. 아래는 등록 토큰에 엑세스하는 또 다른 방법이다.
- token(completion:)을 사용하여 직접 토큰을 가져올 수 있습니다. 어떤 방식으로든 토큰 가져오기에 실패할 경우 null이 아닌 오류가 제공됩니다.
Messaging.messaging().token { token, error in
if let error = error {
print("Error fetching FCM registration token: \(error)")
} else if let token = token {
print("FCM registration token: \(token)")
self.fcmRegTokenMessage.text = "Remote FCM registration token: \(token)"
}
}
언제든지 이 메서드를 사용하여 토큰을 저장하지 않고도 토큰에 엑세스할 수 있습니다.
APN 토큰과 등록 토큰 매핑
- 위의 작업을 모두 진행했다면 이제 APN 토큰을 명시적으로 FCM 등록 토큰에 매핑해야 한다.
didRegisterForRemoteNotificationsWithDeviceToken메서드를 재정의하여 APN 토큰을 검색한 후FIRMessaging의[APNSToken](https://firebase.google.com/docs/reference/ios/firebasemessaging/api/reference/Classes/FIRMessaging#/c:objc(cs)FIRMessaging(py)APNSToken)속성을 설정합니다.
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
✨자동 초기화 방지
- FCM 등록 토큰이 생성되면 라이브러리는 식별자와 구성 데이터를 Firebase에 업로드합니다. 사용자에게 먼저 명시적인 수신 동의를 얻으려면 FCM을 사용 중지하여 구성 시 토큰이 생성되지 않게 하면 됩니다.
- 이렇게 하려면 메타데이터 값을
Info.plist(GoogleService-Info.plist아님)에 추가합니다.
FirebaseMessagingAutoInitEnabled = NO
- FCM을 다시 사용 설정하려면 런타임 호출을 만들면 됩니다.
Messaging.messaging().autoInitEnabled = true
이 값을 설정하고 나면 앱을 다시 시작해도 유지됩니다.
📌테스트 메시지 보내기
✨알림 메시지 전송
- 대상 기기에 앱을 설치하고 실행합니다. 원격 알림 수신에 대한 허가 요청을 수락해야 합니다.
- 앱을 기기에서 백그라운드 상태로 만듭니다.
- 알림 작성기를 열고 새 알림을 선택합니다.
- 메시지 본문을 입력합니다.

- 테스트 메시지 보내기를 선택합니다.
- FCM 등록 토큰 추가 필드에 이 가이드의 앞 섹션에서 가져온 등록 토큰을 입력합니다.

- 테스트를 클릭합니다.
📌앱에서 메시지 수신
✨알림처리
- FCM은 APN을 통해 Apple 앱을 타겟팅하는 모든 메시지를 전송합니다. UNUserNotificationCenter를 통해 APN 알림을 수신하는 방법에 대한 자세한 내용은 Apple의 Handling Notifications and Notification-Related Actions(알림 및 알림 관련 작업 처리) 문서를 참조하세요.
- UNUserNotificationCenter delegate를 설정하고 적절한 대리자 메서드를 구현하여 FCM에서 디스플레이 알림을 수신해야 합니다.
라고 파이어베이스 개발자문서에서 명시하고 있다. 링크된 문서가 무엇인지 궁금할텐데 링크된 애플개발자 문서는 해당 알림의 액션을 핸들링하는 방법과 foreground 에서 알림을 핸들링하는 방법 을 명시하고 있다.
짧게 언급만 하자면 해당 알림에는 categoryIdentifier 가 존재해서 알림에 대해서 핸들링이 가능하고, actionIdentifier 가 존재해서 알림의 액션도 핸들링이 가능하다.

// 메시지 수신
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler([.sound, .banner, .list])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo
// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler()
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler(.noData)
}
}
알림에 커스텀 작업을 추가하려면 알림 페이로드에서 click_action 매개변수를 설정하세요. 이때 APN 페이로드의 category키에 사용할 값을 사용하세요. 커스텀 작업을 사용하려면 먼저 등록해야 합니다. 자세한 내용은 Apple의 Local and Remote Notification Programming Guide(로컬 및 원격 알림 프로그래밍 가이드)를 참조하세요.
다음은 알림 페이로드에서 캡쳐한 부분이다.

출처: https://firebase.google.com/docs/cloud-messaging/http-server-ref#notification-payload-support
알림 페이로드에서 click_action 이 APN 페이로드의 category 키에 해당한다고 했는데, 이것이 앞서 잠깐 언급했던 categoryIdentifier 로 넘어오는 문자열이고 이를 통해서 알림별 분기처리가 가능하다.
✨자동 푸시 알림 처리
- 메시지가 자동 알림으로 전달되어 백그라운드 데이터 새로고침과 같은 작업을 위해 앱이 백그라운드에서 실행됩니다.
- 포그라운드 알림과 달리 이러한 알림은
[appDelegate(_:didReceiveRemoteNotification:fetchCompletionHandler:)](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application)메서드를 통해 처리되어야 합니다.
라고 파이어베이스 개발자문서에 명시하고 있다. 즉, 백그라운드로 오는 알림은 위의 메서드를 통해서 처리해주어야 한다는 이야기이다.
// 백그라운드에서 자동 푸시 알림 처리
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(userInfo)
completionHandler(UIBackgroundFetchResult.newData)
}
✨알림 메시지 페이로드 해석
알림 메시지의 페이로드는 키와 값으로 구성된 사전입니다. APN을 통해 전송된 알림 메시지는 다음과 같이 APN 페이로드 형식을 따릅니다.
{
"aps" : {
"alert" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
},
"badge" : 1,
},
"customKey" : "customValue"
}
- 서버와의 협업 없이도 푸시 알림이 잘오는지 확인해보자! 아래의 글을 참조하면 Postman 을 통해서도 푸시 알림을 받아 볼 수 있다.
Postman 을 이용해서 firebase notification 전송하기
Postman을 이용하여 Firebase Notification 전송하기
- 출처:
| [Set up a Firebase Cloud Messaging client app on Apple platforms | Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/ios/client) |
| [Receive messages in an Apple app | Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/ios/receive) |