๊ธฐ๋ก์ฉ
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
์ด ๋ถ์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํ์ ์.. ์ ๋ฆฌ๊ฐ ์ ๋์ด ์์ต๋๋ค