[iOS] Firebase Cloud Messaging - APN
iOS/Swift

[iOS] Firebase Cloud Messaging - APN

기록용

 

 

1. firebase project 만들기

https://console.firebase.google.com/u/3/?hl=ko



2. iOS 앱 추가하기

 

iOS를 눌러 앱을 추가합니다

그러면 앱 등록 화면이 나오는데 이때 Apple 번들 ID를 입력해야 함

요건 어느 것이냐면 오른쪽 엑스코드 창에서!! Signing & Capabilities 안에 있는 Bundle Identifier 입니다

 

나머지 앱 닉네임, App Store ID는 선택사항이니 패스할게요

 

 

그러면 2번 단계 구성 파일 다운로드가 나오고, GoogleService-Info.plist 다운로드 받아서 Xcode 프로젝트 안에 추가해 주세요

 

 

저는 위 사진처럼 Plists라는 폴더를 따로 만들어 여기에 Info.plist와 함께 넣어 두었습니다

 

참고!!!! GoogleService-Info.plist 안에는 앱에 관련된 정보가 들어있어서 gitignore에 추가하여 따로 로컬에서 관리하는 것을.. 권장드립니다

 

3. Apple Developer > Identifiers 설정

이제 Firebase Console은 잠시.. 멈춰 두고 Apple Developer로 갑니다

https://developer.apple.com/account

 

Identifiers 탭에서, App ID를 만들었는지 확인합니다 (Push Notifications 말고도 다른 기능 (Sign in with Apple 등..)을 이용하셨다면 이미 만들어져 있을 겁니다 !)

만약, App ID가 없다면 새로 추가합니다

 

저는 이미 있으니 이거 쓸게요

사용할 App ID를 클릭해서 들어간 후, Push Notifications를 활성화시킵니다

4. Apple Developer > Keys 설정

고다음... Keys로 가서

사용할 Key가 없으면 새 Key를 만들어 주세요... 전 이미 있으니 있는 걸 쓰겠습니다 (참고로 Key는 한 계정당 3개인.. 가? 발급받을 수 있는 걸로 알아요. 그냥 개인 프로젝트를 하시는 분들은 있던 Key를 계속 다른 프로젝트에 사용하셔도 괜찮습니다.. 아닐 수 있음)

 

 

 

Key를 만들 때 주의할 점은 ... 저 Download가 한 번만 가능하다는 점입니다!!!

그래서 꼭 Key를 다운로드받고, (.p8 확장자를 가지고 있는 파일입니다) 개인적으로 꼭 따로 저장하여 관리해 주세요~ 잃어버리면 곤란~

.p8 Key 파일까지 받았다면 Apple Developer에서 해야 할 일은 끝입니다

 

 

5. Firebase Console 프로젝트 설정

 

다시 Firebase Project Console로 돌아와서... 설정 > 클라우드 메시징으로 들어와 주세요

 

아래로 좀 내려가 보면 아까 추가했던 iOS 앱이 보입니다

"APN 인증 키" 부분에 좀 전에 받았던 .p8 파일을 업로드하여 주세요

 

그러면 키 ID팀 ID를 입력하라고 뜰 텐데,

키 ID는 Apple Developers > Keys에서 저~ 기 Key ID를 쓰시면 됩니다!

 

팀 ID는 Apple Developers 우측 상단 계정 정보에 나와 있는
저 가린 부분!! 저기예요~! 위 사진에서 Key ID 밑에 CONFIGURATION에도 똑같은 부분이 있을 거예요!

그럼 Firebase Console도 진짜 끝났습니다

 

6. Xcode로 가서 프로젝트 Capability 설정

 

프로젝트 설정에서, 좌측 상단 +Capability를 눌러 Push Notifications와 Background Modes를 추가합니다.

Background Modes에는 Background fetch와 Remote notifications를 체크합니다

 

그 다음에, Info.plist 파일로 이동하여 FirebaseAppDelegateProxyEnabled 프로퍼티를 추가합니다. 값은 NO

 

 

7. AppDelegate.swift에서 토큰 관련 코드 작성

 

마지막!!

제가 푸시알림을 구현할 때 사용하는 코드를 그대로 가져왔습니다...

코드에 대한 피드백은.. 환영합니다

 

import UIKit
import Firebase
import FirebaseCore

@main
class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        FirebaseApp.configure()
        PushNotificationHelper.shared.setAuthorization()
        // 앱 실행 시 사용자에게 알림 허용 권한 받기
        UNUserNotificationCenter.current().delegate = self
        
        // 원격 알림 등록
        application.registerForRemoteNotifications()

        /// 메시지 대리자 설정
        Messaging.messaging().delegate = self
        
        /// 자동 초기화 방지
        Messaging.messaging().isAutoInitEnabled = true
        
        /// 현재 등록 토큰 가져오기
        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)")
                UserDefaultsManager.fcmDeviceToken = token
                UserInfo.shared.deviceToken = token 
            }
        }
        
        return true
    }
    
    // MARK: UISceneSession Lifecycle
    
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }
    
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }
    
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        if (AuthApi.isKakaoTalkLoginUrl(url)) {
            return AuthController.handleOpenUrl(url: url)
        }
        
        return false
    }
    
    /// APN 토큰과 등록 토큰 매핑
    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Messaging.messaging().apnsToken = deviceToken
    }
    
    /// APN 토큰과 등록 토큰 매핑 실패
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        debugPrint("APN 토큰 등록 실패", "fail")
    }
    
    /// 디바이스 세로방향으로 고정
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.portrait
    }
    
    /// 토큰 갱신 모니터링 메서드
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        print("Firebase registration token: \(String(describing: fcmToken))")
        UserDefaultsManager.fcmDeviceToken = fcmToken
        UserInfo.shared.deviceToken = fcmToken ?? "non-token"
        let dataDict: [String: String] = ["token": fcmToken ?? ""]
        NotificationCenter.default.post(
            name: Notification.Name("FCMToken"),
            object: nil,
            userInfo: dataDict
        )
    }
}

// MARK: - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {

    /// foreGround에 푸시알림이 올 때 실행되는 메서드
    func userNotificationCenter(_ center: UNUserNotificationCenter,willPresent notification: UNNotification,withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.badge, .sound, .list, .banner])
    }
}

 

//
//  PushNotificationHelper.swift
//  GAM
//
//  Created by Jungbin on 1/24/24.
//

import Foundation
import Firebase

class PushNotificationHelper {
    static let shared = PushNotificationHelper()

    private init() { }

    func setAuthorization() {
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // 필요한 알림 권한을 설정
        UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: { _, _ in }
        )
    }
}

 

 

8. 테스트하기

 

이제 실행을 시켜 봅니다!

별 문제가 없다면 다음과 같이 콘솔에 device token이 출력될 텐데요, 이 토큰을 복사해 둡니다.

 

Firebase Console > Messaging으로 들어가서, Firebase 알림 메시지 캠페인을 선택합니다.

 

그리고 알림 제목, 알림 내용을 입력하고, 오른쪽에 "테스트 메시지 전송" 버튼 클릭

 

 

 

Xcode 콘솔에서 복사해 뒀던 FCM 등록 토큰을 추가합니다!


그리고 테스트를 누르면~

 

짜잔

 

 

이상입니다 ^_^

 

FCM - APN, FCM 토큰 만료 시점 등에 대해서는

https://seungwoolog.tistory.com/88

 

[Firebase] FCM을 도입할 때 고려할 것들

최근 진행하는 프로젝트에 FCM을 앱 푸시 알림 서비스로 사용하게 되었다. 도입할 때 서버 개발자로서 고려할 것들을 정리하였다. Firebase Cloud Messaging (FCM) Firebase 클라우드 메시징(FCM)은 무료로 메

seungwoolog.tistory.com

 

이 분의 블로그를 참고하셔요.. 정리가 잘 되어 있습니다