개발자의 끄적끄적

[ios] FCM Notification 구현 [펌] 본문

개발/android & ios

[ios] FCM Notification 구현 [펌]

효벨 2020. 7. 29. 02:00
728x90
반응형

[ios] FCM Notification 구현 [펌]

 

iOS에서 GCM으로 푸시 하는 방법에 이어서 FCM으로 Notification 구현해 보겠습니다.

먼저는 FCM 이 무엇인지 알아야겠지요?

FCM 은 Firebase Cloud Messaging 으로 Firebase 콘솔에서 푸시를 보낼 수도 있으며, 서버에서 푸시를 보낼 수 있도록 지원하는 서비스입니다. Google에서는 GCM에서 FCM 으로 변경할 것을 권면하고 있으며 대부분 협업에서 FCM으로 변경하고 있습니다.

 

FCM 설정 시나리오

FCM 설정 시나리오는 다음과 같습니다.

  1. Firebase 콘솔에서 앱 등록

  2. 구성 파일 다운로드 (GoogleService-Info.plist)

  3. Firebase SDK 추가

    • pod init

    • pod 'Firebase/Core'

    • pod 'Firebase/Messaging'

    • pod install

  4. 프로젝트에 FCM 코드 추가

  5. APNS Firebase 에 등록

  6. Firebase 로 테스트 Message 보내기

 

Firebase 콘솔에서 앱 등록

Firebase 콘솔에서 프로젝트 생성하고 프로젝트 안에서 iOS 프로젝트를 생성해줍니다.

iOS 프로젝트 생성 시 프로젝트에서 설정해야할 부분에 대해서 자세히 설명을 해주고 있습니다.

주의 할 점은 GoogleService-Info.plist 을 다운받고 FCM 기능을 사용할 프로젝트로 옮겨야합니다.

별도의 설명은 생략하겠습니다.

 

Pod 추가

FCM을 사용하기 위해서는 Pod에 추가하여야 합니다.

  1. 아직 Xcode 프로젝트가 없으면 생성합니다.

  2. Podfile이 없으면 새로 만듭니다.

    $ cd your-project directory
    $ pod init
  3. 설치할 pod를 추가합니다. 다음과 같이 Podfile에 Pod를 포함할 수 있습니다.

    pod 'Firebase/Core'
  4. pod를 설치하고 .xcworkspace 파일을 열어 Xcode에서 프로젝트를 확인합니다.

    $ pod install
    $ open your-project.xcworkspace



프로젝트에서 FCM 준비

AppDelegate 에 FCM 사용을 위한 Firebase 등록, FCM 토큰 발급, Messaging 푸시 알림 표시를 설정할 것입니다.

Firebase 등록

FirebaseApp.configure() 을 통하여 Firebase 등록해야 합니다.

import Firebase

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
       // Override point for customization after application launch.
       
       FirebaseApp.configure()
}


UserNotifications Framwork 추가

UserNotifications Framwork 을 추가하여 FCM 으로 메시지 왔을 때 Notification을 호출해야합니다.

UserNotifications Framwork 추가하는 방법iOS Application 구현 부분을 참고하시면 쉽게 설정할 수 있습니다.

 

FCM 코드 추가

Messaging delegate 및 iOS 10 이상과 이전을 나눠서 Notification 표시 방법을 보여줍니다.

FCM에 등록된 토큰이 있는지 검사하여 로그에 보여지도록 설정도 하였습니다.

AppDeleagate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
       // Override point for customization after application launch.
       
       FirebaseApp.configure()
       
       // Messaging
       // Override point for customization after application launch.
       /**************************** Push service start *****************************/
       
       Messaging.messaging().delegate = self
       
       // iOS 10 support
       if #available(iOS 10.0, *) {
           // For iOS 10 display notification (sent via APNS)
           UNUserNotificationCenter.current().delegate = self
           
           let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
           UNUserNotificationCenter.current().requestAuthorization(
               options: authOptions,
               completionHandler: {_, _ in })
       } else {
           let settings: UIUserNotificationSettings =
               UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
           application.registerUserNotificationSettings(settings)
       }
       
       application.registerForRemoteNotifications()
       
       // 이미 등록된 토큰이 있는지 확인 없을 경우 nil 호출됨
       let token = Messaging.messaging().fcmToken
       print("FCM token: \(token ?? "")")
       /**************************** Push service end *****************************/
       
       return true
   }

 

FCM 토큰 값을 못 가져왔을 경우 디바이스의 토큰 값으로 설정할 수 있습니다.

AppDeleagate.swift

// Called when APNs has assigned the device a unique token
   func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
       // Convert token to string (디바이스 토큰 값을 가져옵니다.)
       let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
       
       // Print it to console(토큰 값을 콘솔창에 보여줍니다. 이 토큰값으로 푸시를 전송할 대상을 정합니다.)
       print("APNs device token: \(deviceTokenString)")
       
       Messaging.messaging().apnsToken = deviceToken
       
       // Persist it in your backend in case it's new
   }

 

Messaging Delegate와 UNUserNotification Delegate는 extention으로 표현했습니다.

FCM으로 메세지 전달 받았을 때 Notification에 표현하기 위한 소스코드 입니다.

// [START ios_10_message_handling]
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
   
   // Receive displayed notifications for iOS 10 devices.
   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)
       // Print message ID.
       if let messageID = userInfo[gcmMessageIDKey] {
           print("Message ID: \(messageID)")
       }
       
       // Print full message.
       print(userInfo)
       
       // Change this to your preferred presentation option
       completionHandler([])
   }
   
   func userNotificationCenter(_ center: UNUserNotificationCenter,
                               didReceive response: UNNotificationResponse,
                               withCompletionHandler completionHandler: @escaping () -> Void) {
       let userInfo = response.notification.request.content.userInfo
       // Print message ID.
       if let messageID = userInfo[gcmMessageIDKey] {
           print("Message ID: \(messageID)")
       }
       
       // Print full message.
       print(userInfo)
       
       completionHandler()
   }
}
// [END ios_10_message_handling]
extension AppDelegate : MessagingDelegate {
   // [START refresh_token]
   func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
       print("Firebase registration token: \(fcmToken)")
       
       let dataDict:[String: String] = ["token": fcmToken]
       NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
       // TODO: If necessary send token to application server.
       // Note: This callback is fired at each app startup and whenever a new token is generated.
   }
   // [END refresh_token]
   // [START ios_10_data_message]
   // Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
   // To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
   func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
       print("Received data message: \(remoteMessage.appData)")
   }
   // [END ios_10_data_message]
}

 

APNS 등록 시나리오

프로젝트에서 설정이 완료 되었으니 마지막으로 Firebase에 APNS 을 등록하겠습니다.

GCM 에서는 APNS 을 직접 만들어서 사용하였습니다. 궁금하신 분은 GCM Notification Push 에서 확인 할 수 있습니다.

Firebase에서는 APNS을 등록하는 방법은 인증키 또는 인증서 로 설정할 수 있습니다.

그럼 인증서 등록 방법을 알아보겠습니다.

 

APNS 인증서 등록

FCM에서 APNS(Apple Development IOS Push Services) 인증서 등록 시 APNS 발급은 총 2번 받아야합니다.

 

개발 APN과 프로덕션 APN 이 필요합니다.

 

키체인으로 인증서 발급

우선 키체인으로 인증서를 발급합니다.

키체인 > 키체인 접근 > 인증서 지원 > 인증기관에서 인증서 지원

이렇게 두 개를 생성합니다.

1) 개발 APN 에 사용할 인증서 (PushDeveloper_CertificateSigningRequest) 2) 프로덕션 APN 에 사용할 인증서 (PushProduction_CertificateSigningRequest)

인증서를 만드셨으면 Apple Developer - identifiers - App IDs 로 진입합니다.

 

Apple Developer에서 AppID 추가

 

오른쪽 상단의 '+' 버튼을 눌러 AppID을 추가합니다.

주의할 것은 xcode로 작성한 프로젝트의 bundleID하고 AppID 생성에 사용할 bundleID가 동일해야 합니다.

생성 완료한 파일은 저장합니다.

 

Push Notifications 인증서 등록

Push를 지원하는 AppID를 생성한 후에 Developement SSL 인증서와 Production SSL 인증서를 등록하지 않으면 다음과 같은 화면이 보입니다.

 

하단에 보시면 'Edit' 버튼이 보일 것입니다.

Edit 버튼 클릭 > 하단 Push Notifications 확인

Development SSL Certificate 와 Production SSL Certificate 각각 Create Certificate 하여 키체인으로 생성한 인증서를 등록합니다.

 

Firebase APNS 등록

이제 등록한 APNS을 Firebase에 등록하는 절차만 남았습니다.

Firebase 접속 > 프로젝트 진입 > 왼쪽 메뉴의 톱니바퀴 클릭 > 프로젝트 설정 진입

 

 

프로젝트 설정 진입 후 상단에 보며 클라우드 메시징 이 있습니다.

진입 후 iOS 앱 구성의 APN 인증키, APN 인증서 두 가지 중 하나를 넣는 공간이 있습니다.

이번 포스트에서는 APN 인증서로 동작해보겠습니다.

우선 인증서를 추출해야합니다.

키체인 > push로 등록한 인증서 > Deleoper(Production) 인증서 내보내기

인증서를 성공적으로 내보냈으면 .p12 파일로 추출이 되었을 것입니다.

이 두 파일을 Firebase의 Development APN, Production APN에 넣어줍니다.

 

APN과 인증서 비밀번호까지 올바르게 입력하면 준비가 다 되었습니다.

 

테스트

마지막 단계인 테스트 단계입니다.

Firebase > 성장 > Cloud Messaging

 

첫 번째 메시지를 보냅니다.

 

테스트를 위해서 단일 기기로 보내겠습니다.

메시지 내용은 TEST 로 하며 단일 기기의 토큰을 입력합니다.

FCM 토큰 값은 앱을 실행 하면 AppDelegate에서 print 한 값을 확인 할 수 있습니다.

//실제 토큰값은 더 길고 복잡합니다.
Firebase registration token: AnLVPk:APA91bHUlPNOQaj-kXU2PwJQwOcLux3wXV2d1xcEvMQl2uWT....

모두 작성 후 메시지 보내기 버튼을 클릭하여 메시지를 보냅니다.

전송 성공 여부도 확인할 수 있습니다.

 

(번외) Firebase에 APN 인증키 등록

Firebase 등록 방법을 인증서 뿐만 아니라 인증키 등록으로 할 수도 있습니다.

인증키로 Firebase APN 인증 키 업로드 시 APN 인증 키, 키 ID, 앱 ID 프리픽스 세가지 항목이 필요합니다.

APN 인증키 및 키 ID 확인 방법

AppID에 DeveloperAPN, Production APN 등록하는 과정은 똑같습니다.

차이점은 인증키를 만들어야합니다. Apple Developer 에서 Key을 생성해야합니다.

Apple Developer > Keys > All

오른쪽 '+' 눌러 인증키를 생성합니다.

 

여기서 주의할 사항은 1번만 다운 가능하므로 생성 후 다운받아 안전히 저장합니다.

Apple Developer 사이트에서 생성한 키를 클릭하면 Key ID 을 확인 할 수 있습니다.

앱 ID 프리픽스 확인 방법

Apple Developer 에서 생성한 AppID 클릭 하면 앱 ID 프리픽스 확인 할 수 있습니다.

FCM 인증키 등록 방법

생성한 인증키와 Key ID, 앱 ID 프리픽스를 FCM 인증키 등록 부분에 넣어주면 등록이 됩니다.

 

정리

FCM으로 Push Message 보내는 방법에 대해서 알아봤는데요. 생각보다 복잡하고 설정해줘야할 부분이 많았습니다.

공유드린 인증서 등록으로 푸시를 보낼 경우 1년마다 갱신해야하는 불편함이 있습니다.

따라서 Firebase 팀에서는 인증키로 하는 것을 추천하고 있습니다.

기회가 된다면 인증키로 푸시 보내는 것도 테스트해보실 것을 추천합니다. Push 기능으로 더 풍성한 기능을 제공할 것을 기대합니다.

제가 공유드린 내용 밖에 자세한 내용은 Firebase Clould Messaging 에서 확인 할 수 있습니다.



출처: https://faith-developer.tistory.com/156 [개발 이야기]

반응형
Comments