Remote Notification
1. APNs(애플 서버)한테 사용자(해당 기기)에게 identifier 같은 식별자를 제공해달라고 요청함
2. APNs 서버에 해당 기기를 등록해달라고 함
3. APNs 서버에서 푸쉬 받을 수 있게 식별자를 줌 (해당 식별자를 토큰이라고 함 - 쉽게 말해 기기 별로 민증번호를 발급함)
4. 발급 받은 민증번호(토큰)를 토대로 카톡 서버에 전달함
5. 그러면 Jack이 카톡 서버에 사용하는 id가 있겟지? 카톡 서버에서도 Jack이라는 유저에 해당하는 id와 매칭되는 민증번호가 있을 것임
만약 Jack이 Hue라는 유저에게 톡을 보내서 푸쉬를 보내고자 하면
6. 카톡 서버가 Hue라는 민증번호를 가진 사람한테 푸쉬를 보내라고 애플 서버한테 요청을 할 것임
좀 더 쉽게 말하면 이거임...
앱을 빌드하면 -> 애플 서버한테 먼저 요청을 함
푸쉬 기능 다 만들었응께
민증 번호 (토큰) 발급해조!
그럼 APNs는 발급해줌
그럼 카톡 서버한테 전달하고
카톡 서버가 매칭해줌 (잭이라는 유저는 어떤 토큰을 쓰고, 휴라는 유저는 어떤 토큰을 쓴다.. )
그럼 카톡 서버가 APNs한테 요청해서 APNs가 푸쉬를 해당 유저의 기기에 보내줌
그리고 토큰 만료도 필요하다.
provider는 카톡 서버 / 파베 서버 등이 될 수 있음
근데 Push Notification을 사용하려면 3가지 조건이 필요한데
1. 결제해야 하고 (유료계약) -> 푸시 인증키를 발급 받을 수 있기 때문임
2. 실기기에서 사용해야 하고
3. Xcode App > Capabilities - 푸시알림 사용 / 백그라운드 설정 옵션을 해야 한다
유저가 앱을 사용하지 않더라도 background 모드에서도 앱의 기능을 사용하겠다.
예를 들어, 멜론이 백그라운드에 있어도 음악을 듣는 것처럼..
APNs 관련 Key는 2개만 만들 수 있음
근데 한 개의 키로로 여러개에 등록해서 만들 수 있음
요즘에 사용하는 p8이라는 인증키가 만들어짐
한 번 다운로드 후 재 다운로드가 불가능해서 관리가 필요함 -> 만약 그런 경우에 출시한 모든 앱에 변경이 필요함
그리고 여러 앱에 사용이 가능함
이전에 사용하던 p12는 인증서가 2개로 나뉘었음
- 개발용 푸쉬
- 배포용 푸쉬
유효기간이 1년으로 있음
회사에서 1년이 지나면 푸쉬가 안와서 갱신이 필요함
아모튼 나는 파베 서버를 통해 푸쉬 알림을 구현하려고 함
글서 파베 Cloud Messaging 프로젝트 설정에서 APN 인증 키에 추가해야 하는데
키ID는 p8 인증 키에 붙어 있는 ID이고,
팀ID는 애플 developer.apple.com에 있는 팀 ID를 넣어주면 된다.
APN 인증서는 p12 인증서를 넣는 부분임
이제 코드 부분임
코드를 쳐야 완성되는 것임
https://firebase.google.com/docs/cloud-messaging/ios/client?hl=ko
//
// AppDelegate.swift
// FirebaseProject
//
// Created by heerucan on 2022/10/11.
//
import UIKit
import FirebaseCore
import FirebaseMessaging
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// 알림 시스템에 앱 등록 - 권한 요청
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()
// 메시지 대리자 설정
Messaging.messaging().delegate = self
// 현재 등록된 토큰 가져오기
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)")
}
}
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.
}
}
// 애플 내장 기능
extension AppDelegate: UNUserNotificationCenterDelegate {
// 재구성 사용 중지됨: APNs 토큰과 등록 토큰 매핑
func application(application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
}
// foreground에서 알림 수신: 로컬/푸시 동일
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.badge, .sound, .banner, .list])
}
// 푸시 클릭
// 유저가 푸시를 클릭했을 때에만 수신 확인 가능
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print("사용자가 푸시를 클릭했습니다.")
print(response.notification.request.content.title)
print(response.notification.request.content.userInfo)
print(response.notification.request.content.body)
let userInfo = response.notification.request.content.userInfo
if userInfo[AnyHashable("sesac")] as? String == "project" {
print("홈 화면으로 넘긴다.")
} else {
print("그냥 냅둔다.")
}
}
}
// 파베 기능
extension AppDelegate: MessagingDelegate {
// 토큰 갱신 모니터링: 토큰 정보가 언제 바뀔까?
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("Firebase registration token: \(String(describing: 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.
}
}
UNNotificationInterruptionLevel
열거형인데 알림마다 중요도를 줄 수 있음
방해금지 모드여도 알림이 전달되는 거는 timeSensitive
완전 긴급해도 critical
로그아웃이나 탈퇴를 하는 경우에는 어케??
사용자 정보가 없더라도 푸시가 날라오게 됨
토큰 처리가 중요하다!!!
파베 서비스를 삭제해주는 방식으로 수동적으로 처리해줘야 함
Installations.installations().delete { error in
if let error = error {
print("Error deleting installation: \(error)")
return
}
print("Installation deleted");
}
'⭐️ 개발 > iOS & Swift' 카테고리의 다른 글
[iOS] 20221012 TIL (0) | 2022.10.13 |
---|---|
[iOS] Method Swizzling이 뭔가? (feat. 인스턴스/타입 메소드) (3) | 2022.10.13 |
[iOS] 다국어 지원 i18n, l10n (1) | 2022.09.06 |
[iOS] 안간단한 MVVM 안간단하게 톺아보기 (3) | 2022.08.31 |
[iOS] URLSession(1) (0) | 2022.08.30 |