// // FirebasePushTokenService.swift // Malinka // // Created by Nut.Tech on 21.02.2023. // Copyright © 2023 NUT.Tech. All rights reserved. // import Firebase import FirebaseMessaging import Combine import WalletFoundation final class FirebasePushTokenService: NSObject, ObservableObject, MessagingDelegate { private enum Constants { static let tokenLifetimeKey = "Firebase.service.pushToken.lifetime" static let tokenUpdateQueue = "Firebase.service.pushToken.queue.update" } @Published private (set) var token: String? private let firebaseTokenLifetime: ApplicationEnvironmentRecord.FirebaseLifetime private let tokenQueue = DispatchQueue(label: Constants.tokenUpdateQueue, qos: .background) init(tokenLifetime: ApplicationEnvironmentRecord.FirebaseLifetime) { self.firebaseTokenLifetime = tokenLifetime super.init() FirebaseApp.configure() Messaging.messaging().delegate = self self.updateTokenIfNeeded() } func updateAPNS(token: Data) { Messaging.messaging().apnsToken = token } private func updateTokenIfNeeded() { Task { let lastUpdate = UserDefaults.standard.value(forKey: Constants.tokenLifetimeKey) as? Date if !lastUpdate.isExist { await self.updateFirebaseToken() return } guard let lastUpdate, Date().timeIntervalSince(lastUpdate) >= Double(self.firebaseTokenLifetime.rawValue) else { return } await self.updateFirebaseToken() } } private func updateFirebaseToken() async { let error = await withCheckedContinuation { (continuation: CheckedContinuation) in Messaging.messaging().deleteToken { error in continuation.resume(returning: error) } } guard !error.isExist else { return } let token = try? await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in Messaging.messaging().token { token, error in if let error { continuation.resume(throwing: error) } else { continuation.resume(returning: token) } } } guard token.isExist else { return } UserDefaults.standard.set(Date(), forKey: Constants.tokenLifetimeKey) } // MARK: - MessagingDelegate func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { self.token = fcmToken } }