Notice
Recent Posts
Recent Comments
Link
투케이2K
34. (TWOK/UTIL) [Ios/Swift] AppDelegate - 파이어베이스 푸시 토큰 및 알림 관리 본문
[설 명]
프로그램 : Ios / Swift
설 명 : 파이어베이스 푸시 토큰 및 알림 관리
[파이어베이스 푸시 알림 처리 로직 과정]
1. APN 인증 키(.p8) 발급
2. 파이어베이스 콘솔에서 프로젝트 생성 및 등록 필요
3. Xcode 프로젝트 실행 >> 파이어베이스 SDK 설치를 진행
4. Xcode 프로젝트 >> 파이어베이스 콘솔에서 다운받은 GoogleService-Info 파일을 프로젝트에 적용
5. Xcode 프로젝트 >> Push Notifications와 Background Modes 를 추가
6. AppDelegate 쪽에서 파이어베이스 푸시 알림 처리 소스 코드 작성 실시
7. (debug , release) , (enterprise) 빌드 환경에서 번들 아이디 (패키지명) 이 다른 경우 :
- 파이어베이스에서 iOS 프로젝트 다중 생성 (ex: testApp / testAppEnz) 및 각 환경에 맞는 p8 파일로 등록 (p8 파일 2개)
- Xcode 프로젝트 >> 파이어베이스 콘솔에서 다운받은 GoogleService-Info 파일 이름 변경 실시
(GoogleService-Info-Dug / GoogleService-Info-Enz)
- AppDelegate 에서 FirebaseApp.configure() 라이브러리 초기화 부분에서 빌드 환경 체크 >> 각 GoogleService-Info 파일 적용 실시
[소스 코드]
import UIKit
import AVFoundation
import Firebase
import FirebaseAnalytics
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// MARK: - [클래스 설명]
/*
// -----------------------------------------
1. 애플리케이션 딜리게이트
// -----------------------------------------
*/
// MARK: - [파이어베이스 푸시 알림]
/*
// -----------------------------------------
1. Swift Package Manager를 사용해 Firebase 종속 항목을 설치하고 관리
- https://github.com/firebase/firebase-ios-sdk
- [Up to Next Major Version 8.0.0 < 9.0.0]
2. FirebaseAnalytics를 추가 , 파이어베이스 메시징 추가
// -----------------------------------------
*/
// MARK: - [빠른 로직 찾기 : 주석 로직 찾기]
// -----------------------------------------
// [SEARCH FAST] : [프리퍼런스 값 초기화 실시]
// [SEARCH FAST] : [푸시 알림 뱃지 카운트 초기화]
// [SEARCH FAST] : [빌드 타입 확인 실시]
// [SEARCH FAST] : [파이어베이스 초기화]
// [SEARCH FAST] : [파이어베이스 등록 토큰 확인]
// [SEARCH FAST] : [푸시 알림 수신 확인]
// -----------------------------------------
// MARK: - [전역 변수 선언 실시]
var window: UIWindow? // [ios 13 미만 버전 제어 위해 선언]
// MARK: - [앱 프로세스 완료 및 앱 실행 실시]
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("")
print("====================================")
print("[AppDelegate >> didFinishLaunchingWithOptions]")
print("-------------------------------")
print("설 명 :: 앱 프로세스 완료 및 앱 실행 실시")
print("====================================")
print("")
// -----------------------------------------
// [SEARCH FAST] : [프리퍼런스 값 초기화 실시]
S_Preference().proccessCreateClear()
// -----------------------------------------
// -----------------------------------------
// [SEARCH FAST] : [푸시 알림 뱃지 카운트 초기화]
// UIApplication.shared.applicationIconBadgeNumber = 0
// -----------------------------------------
// -----------------------------------------
// [LaunchScreen 로딩화면 지연 실시 - 3초]
// Thread.sleep(forTimeInterval: 3.0)
// -----------------------------------------
// -----------------------------------------
// [SEARCH FAST] : [빌드 타입 확인 실시]
// [SEARCH FAST] : [파이어베이스 초기화]
#if DEBUG
print("")
print("====================================")
print("[AppDelegate >> didFinishLaunchingWithOptions]")
print("-------------------------------")
print("설 명 :: ", "빌드 타입 확인 실시")
print("-------------------------------")
print("빌드 타입 :: ", "DEBUG 실행")
print("====================================")
print("")
let fireBaseConfigFile = Bundle.main.path(forResource: "GoogleService-Info-Dug", ofType: "plist")!
let firOptions = FirebaseOptions(contentsOfFile: fireBaseConfigFile)!
FirebaseApp.configure(options: firOptions)
#elseif ENTERPRISE
print("")
print("====================================")
print("[AppDelegate >> didFinishLaunchingWithOptions]")
print("-------------------------------")
print("설 명 :: ", "빌드 타입 확인 실시")
print("-------------------------------")
print("빌드 타입 :: ", "ENTERPRISE 실행")
print("====================================")
print("")
let fireBaseConfigFile = Bundle.main.path(forResource: "GoogleService-Info-Enz", ofType: "plist")!
let firOptions = FirebaseOptions(contentsOfFile: fireBaseConfigFile)!
FirebaseApp.configure(options: firOptions)
#else
print("")
print("====================================")
print("[AppDelegate >> didFinishLaunchingWithOptions]")
print("-------------------------------")
print("설 명 :: ", "빌드 타입 확인 실시")
print("-------------------------------")
print("빌드 타입 :: ", "RELEASE 실행")
print("====================================")
print("")
let fireBaseConfigFile = Bundle.main.path(forResource: "GoogleService-Info-Dug", ofType: "plist")!
let firOptions = FirebaseOptions(contentsOfFile: fireBaseConfigFile)!
FirebaseApp.configure(options: firOptions)
#endif
// -----------------------------------------
// -----------------------------------------
Messaging.messaging().delegate = self // [메시징 딜리게이트 지정]
UNUserNotificationCenter.current().delegate = self // [노티피케이션 알림 딜리게이트 지정]
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // [푸시 알림 권한]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { (success, error) in // [푸시 알림 권한 요청]
// [success 부분에 권한을 허락하면 true / 권한을 허락하지 않으면 false 값이 들어갑니다]
if let error = error {
print("")
print("====================================")
print("[AppDelegate >> requestAuthorization() :: 노티피케이션 권한 요청 에러]")
print("error :: \(error.localizedDescription)")
print("====================================")
print("")
}
else {
print("")
print("====================================")
print("[AppDelegate >> requestAuthorization() :: 노티피케이션 권한 요청 응답 확인]")
print("success :: \(success)")
print("====================================")
print("")
}
}
application.registerForRemoteNotifications() // [원격 알림 앱 등록 : APNS 등록]
print("")
print("====================================")
print("[AppDelegate >> didFinishLaunchingWithOptions]")
print("설 명 :: ", "파이어베이스 초기화 수행 실시")
print("====================================")
print("")
// -----------------------------------------
// -----------------------------------------
return true
// -----------------------------------------
}
// MARK: - [Scene 만들기 위한 구성 객체 반환 : 스토리보드 , info]
@available(iOS 13.0, *)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
print("")
print("====================================")
print("[AppDelegate >> configurationForConnecting]")
print("-------------------------------")
print("설 명 :: Scene 만들기 위한 구성 객체 반환 : 스토리보드 , info")
print("====================================")
print("")
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
// MARK: - [Scene 구성 객체 해제 실시]
@available(iOS 13.0, *)
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
print("")
print("====================================")
print("[AppDelegate >> didDiscardSceneSessions]")
print("-------------------------------")
print("설 명 :: Scene 구성 객체 해제 실시")
print("====================================")
print("")
}
// MARK: - [애플리케이션 사용자가 작업 태스크 날린 이벤트 감지]
func applicationWillTerminate(_ application: UIApplication) {
print("")
print("====================================")
print("[AppDelegate >> applicationWillTerminate]")
print("-------------------------------")
print("설 명 :: 애플리케이션 사용자가 작업 태스크 날린 이벤트 감지")
print("====================================")
print("")
// -----------------------------------------
// [SEARCH FAST] : [프리퍼런스 값 초기화 실시]
// -----------------------------------------
// [앱 종료 시 프리퍼런스 데이터 초기화]
S_Preference().mainFinishClear()
// -----------------------------------------
// [프로세스 종료 시 프리퍼런스 데이터 초기화]
S_Preference().proccessFinishClear()
// -----------------------------------------
}
// MARK: - [디바이스 화면 세로 모드 고정 실시]
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
print("")
print("====================================")
print("[AppDelegate >> supportedInterfaceOrientationsFor]")
print("-------------------------------")
print("설 명 :: 디바이스 화면 세로 모드 고정 실시")
print("====================================")
print("")
// [세로 방향 고정]
return UIInterfaceOrientationMask.portrait
}
// MARK: - [원격 알림 앱 등록 : APNS 등록 후 >> apnsToken 매핑]
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)}) // hex 데이터 확인
print("")
print("====================================")
print("[AppDelegate >> didRegisterForRemoteNotificationsWithDeviceToken]")
print("-------------------------------")
print("설 명 :: 원격 알림 앱 등록 : APNS 등록 후 >> apnsToken 매핑")
print("-------------------------------")
print("deviceToken :: \(deviceToken)")
print("====================================")
print("")
// -----------------------------------------
// [APNS 토큰 매핑]
Messaging.messaging().apnsToken = deviceToken
// -----------------------------------------
}
// MARK: - [푸시 알림 전달 받음 상태 확인]
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]){
// [switch 문을 사용해서 분기 처리 실시]
switch UIApplication.shared.applicationState {
case .active:
print("")
print("====================================")
print("[AppDelegate >> didReceiveRemoteNotification]")
print("설 명 :: 포그라운드 상태에서 푸시알림 전달받음")
print("====================================")
print("")
break
case .background:
print("")
print("====================================")
print("[AppDelegate >> didReceiveRemoteNotification]")
print("설 명 :: 백그라운드 상태에서 푸시알림 전달받음")
print("====================================")
print("")
break
case .inactive:
print("")
print("====================================")
print("[AppDelegate >> didReceiveRemoteNotification]")
print("설 명 :: 푸시 클릭 접속 확인")
print("====================================")
print("")
break
default:
print("")
print("====================================")
print("[AppDelegate >> didReceiveRemoteNotification]")
print("설 명 :: default")
print("====================================")
print("")
break
}
}
} // [클래스 종료]
// MARK: - [노티피케이션 알림 딜리게이트 추가]
extension AppDelegate: UNUserNotificationCenterDelegate {
// -----------------------------------------
// [SEARCH FAST] : [푸시 알림 수신 확인]
// -----------------------------------------
// MARK: [앱이 foreground 상태 일 때, 알림이 온 경우]
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print("")
print("====================================")
print("[AppDelegate >> willPresent]")
print("-------------------------------")
print("설 명 :: 앱 포그라운드 상태 푸시 알림 확인")
print("-------------------------------")
print("userInfo :: \(notification.request.content.userInfo)") // [푸시 정보 가져옴]
print("-------------------------------")
print("title :: \(notification.request.content.title)") // [타이틀]
print("-------------------------------")
print("body :: \(notification.request.content.body)") // [내용]
print("-------------------------------")
print("sound :: \(notification.request.content.sound!)") // [소리]
print("-------------------------------")
print("data [keys] :: \(notification.request.content.userInfo.keys)") // [커스텀 json 데이터]
print("-------------------------------")
print("data [sort] [푸시 타입] :: \(String(describing: notification.request.content.userInfo["sort"] ?? ""))") // [무음, 진동, 소리 발생 여부]
print("-------------------------------")
print("data [msgType] [메시지 타입] :: \(String(describing: notification.request.content.userInfo["msgType"] ?? ""))") // [메시지 타입]
print("-------------------------------")
print("data [messageId] [메시지 아이디] :: \(String(describing: notification.request.content.userInfo["messageId"] ?? ""))") // [메시지 아이디]
print("====================================")
print("")
// [프리퍼런스에 저장된 타입이 있는지 확인]
var checkPushType = S_Preference().getString(_sKey: S_FinalData.PRE_PUSH_SORT)
if checkPushType != nil && checkPushType.count>0 && checkPushType.equals(_string: "") == false { // [프리퍼런스 값이 널이 아닌 경우]
let type = checkPushType
if type == "0" || type == "1" || type == "2" {
// [정상적으로 값을 포함한 경우]
}
else {
checkPushType = "\(String(describing: notification.request.content.userInfo["sort"] ?? ""))"
if checkPushType == "0" || checkPushType == "1" || checkPushType == "2" {
// [프리퍼런스에 데이터 저장]
S_Preference().setString(_sKey: S_FinalData.PRE_PUSH_SORT, _sValue: checkPushType)
}
else {
checkPushType = "2" // [기본 값 설정 : 소리 + 진동]
}
}
}
else { // [프리퍼런스 값이 널인 경우]
checkPushType = "\(String(describing: notification.request.content.userInfo["sort"] ?? ""))"
if checkPushType == "0" || checkPushType == "1" || checkPushType == "2" {
// [프리퍼런스에 데이터 저장]
S_Preference().setString(_sKey: S_FinalData.PRE_PUSH_SORT, _sValue: checkPushType)
}
else {
checkPushType = "2" // [기본 값 설정 : 소리 + 진동]
}
}
print("")
print("====================================")
print("[AppDelegate >> willPresent]")
print("-------------------------------")
print("설 명 :: 노티피케이션 알림 타입 확인")
print("-------------------------------")
print("checkPushType :: ", checkPushType)
print("====================================")
print("")
// [푸시 알림 타입별 분기 처리 실시]
let sort = checkPushType
if sort == "0" { // [무음]
print("")
print("====================================")
print("[AppDelegate >> willPresent]")
print("설 명 :: 노티피케이션 알림 [무음] 모드")
print("====================================")
print("")
// [알림 표시 수행]
completionHandler([.alert, .badge])
}
else if sort == "1" { // [진동]
print("")
print("====================================")
print("[AppDelegate >> willPresent]")
print("설 명 :: 노티피케이션 알림 [진동] 모드")
print("====================================")
print("")
// [진동 기능 활성]
UIDevice.vibrate()
// [알림 표시 수행]
completionHandler([.alert, .badge])
}
else if sort == "2" { // [소리 + 진동]
print("")
print("====================================")
print("[AppDelegate >> willPresent]")
print("설 명 :: 노티피케이션 알림 [소리 + 진동] 모드")
print("====================================")
print("")
// [진동 기능 활성]
UIDevice.vibrate()
// [알림 표시 수행]
completionHandler([.alert, .badge, .sound])
}
else { // [기본 : 소리 + 진동]
print("")
print("====================================")
print("[AppDelegate >> willPresent]")
print("설 명 :: 노티피케이션 알림 [기본 : 소리 + 진동] 모드")
print("====================================")
print("")
// [알림 표시 수행]
completionHandler([.alert, .badge, .sound])
}
// [AppDelegate 포그라운드 푸시 메시지 송신]
DispatchQueue.main.async {
// [포그라운드 메시지 전송 데이터 결합 실시]
var sendDic : Dictionary<String, Any> = [String : Any]()
sendDic["title"] = "\(String(describing: notification.request.content.title))" // [제목]
sendDic["message"] = "\(String(describing: notification.request.content.body))" // [내용]
sendDic["msgType"] = "\(String(describing: notification.request.content.userInfo["msgType"] ?? ""))" // [커스텀 : 메시지 타입]
sendDic["messageId"] = "\(String(describing: notification.request.content.userInfo["messageId"] ?? ""))" // [커스텀 : 메시지 아이디]
print("")
print("====================================")
print("[AppDelegate >> willPresent]")
print("-------------------------------")
print("설 명 :: 노티피케이션 포그라운드 알림 전달 실시")
print("-------------------------------")
print("message :: ", sendDic.description)
print("====================================")
print("")
// [브로드 캐스팅 포그라운드 상태 푸시 알림 메시지 전달]
NotificationCenter.default.post(
name: NSNotification.Name(rawValue: S_FinalData.NOTI_RECEIVE_PUSH_MESSAGE), // [알림을 식별하는 태그]
object: nil, // [발송자가 옵저버에게 보내려고 하는 객체]
userInfo: ["message" : sendDic] // [객체의 저장소 [AnyHashable: Any] 형태]
)
}
}
// -----------------------------------------
// MARK: [앱이 살아있고 background 상태 일 때, 알림이 온 경우 >> 포그라운드 전환 상태]
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
print("")
print("====================================")
print("[AppDelegate >> didReceive]")
print("-------------------------------")
print("설 명 :: 앱 백그라운드 >> 포그라운드 상태 푸시 알림 확인")
print("-------------------------------")
print("response :: \(response)") // [응답 전체]
print("-------------------------------")
print("title :: \(response.notification.request.content.title)") // [타이틀]
print("-------------------------------")
print("body :: \(response.notification.request.content.body)") // [내용]
print("====================================")
print("")
// [completionHandler : 푸시 알림 상태창 처리]
completionHandler()
}
// -----------------------------------------
}
// MARK: - [MessagingDelegate 딜리게이트 추가]
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("")
print("====================================")
print("[AppDelegate >> messaging]")
print("-------------------------------")
print("설 명 :: 파이어베이스 푸시 토큰 등록 확인")
print("-------------------------------")
print("로 직 :: ", "프리퍼런스에 푸시 토큰 값 저장 실시")
print("-------------------------------")
print("fcmToken :: \(String(describing: fcmToken ?? ""))")
print("====================================")
print("")
// -----------------------------------------
// [SEARCH FAST] : [파이어베이스 등록 토큰 확인]
// -----------------------------------------
// -----------------------------------------
// [프리퍼런스에 푸시 토큰 저장 실시]
S_Preference().setString(_sKey: S_FinalData.PRE_PUSH_TOKEN, _sValue: "\(String(describing: fcmToken ?? ""))") // 파이어베이스 푸시 토큰
// -----------------------------------------
// -----------------------------------------
/*
print("")
print("====================================")
print("[AppDelegate >> messaging]")
print("-------------------------------")
print("설 명 :: 파이어베이스 푸시 토큰 등록 확인")
print("-------------------------------")
print("로 직 :: ", "푸시 토큰 생성 브로드 캐스트 알림 전달 실시")
print("-------------------------------")
print("fcmToken :: \(String(describing: fcmToken ?? ""))")
print("====================================")
print("")
NotificationCenter.default.post(
name: NSNotification.Name(rawValue: S_FinalData.NOTI_PUSH_TOKEN_CREATE), // [알림을 식별하는 태그]
object: nil, // [발송자가 옵저버에게 보내려고 하는 객체]
userInfo: nil // [객체의 저장소 [AnyHashable: Any] 형태]
)
// */
// -----------------------------------------
}
}
반응형
'투케이2K 유틸파일' 카테고리의 다른 글
Comments