Skip to content

Commit ed3f71a

Browse files
authored
[#608] Mac에서 앱이 온그라운드 상태가 될 때 FCM 토큰이 과도하게 업데이트되는 현상을 해결한다 (#668)
* fix: 온그라운드로 되면 fcm 토큰을 업데이트 하는 트리거 제거 * fix: FCM token 중복 저장 방지 * fix: FCM token 세션 전이 처리 * test: TodoList 취소 테스트 동기화 보강
1 parent 92510e0 commit ed3f71a

7 files changed

Lines changed: 274 additions & 22 deletions

File tree

Application/App/Sources/App/Assembler/AppLayerAssembler.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ final class AppLayerAssembler: Assembler {
1212
func assemble(_ container: any DIContainer) {
1313
container.register(FCMTokenSyncHandler.self) {
1414
FCMTokenSyncHandler(
15+
authService: container.resolve(AuthService.self),
1516
messagingService: container.resolve(PushMessagingService.self),
16-
userService: container.resolve(UserService.self)
17+
userService: container.resolve(UserService.self),
18+
store: container.resolve(UserDefaultsStore.self)
1719
)
1820
}
1921
container.register(UserTimeZoneSyncHandler.self) {

Application/App/Sources/App/Delegate/AppDelegate.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
3232
_ = container.resolve(UserTimeZoneSyncHandler.self)
3333
_ = container.resolve(WidgetSyncEventHandler.self)
3434
_ = container.resolve(WidgetSessionSyncHandler.self)
35-
NotificationCenter.default.addObserver(
36-
self,
37-
selector: #selector(handleSceneDidActivate),
38-
name: UIScene.didActivateNotification,
39-
object: nil
40-
)
4135
NotificationCenter.default.addObserver(
4236
self,
4337
selector: #selector(handleRemoteNotificationRegistrationRequest),
@@ -73,10 +67,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
7367
return true
7468
}
7569

76-
@objc private func handleSceneDidActivate() {
77-
NotificationCenter.default.post(name: .didRequestFCMTokenSync, object: nil)
78-
}
79-
8070
@objc private func handleRemoteNotificationRegistrationRequest() {
8171
Task { @MainActor in
8272
UIApplication.shared.registerForRemoteNotifications()

Application/App/Sources/App/Handler/FCMTokenSyncHandler.swift

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,44 @@
77

88
import Combine
99
import Core
10+
import CryptoKit
1011
import Data
1112
import Foundation
13+
import Infra
1214

1315
final class FCMTokenSyncHandler {
16+
private enum Key {
17+
static let fcmTokenHash = "FCMTokenSyncHandler.fcmTokenHash"
18+
}
19+
20+
private let authService: AuthService
1421
private let messagingService: PushMessagingService
1522
private let userService: UserService
23+
private let store: UserDefaultsStore
1624
private let notificationCenter: NotificationCenter
1725
private let logger = Logger(category: "FCMTokenSyncHandler")
1826
private var cancellables = Set<AnyCancellable>()
1927

2028
init(
29+
authService: AuthService,
2130
messagingService: PushMessagingService,
2231
userService: UserService,
32+
store: UserDefaultsStore,
2333
notificationCenter: NotificationCenter = .default
2434
) {
35+
self.authService = authService
2536
self.messagingService = messagingService
2637
self.userService = userService
38+
self.store = store
2739
self.notificationCenter = notificationCenter
2840

41+
authService.observeSignedIn()
42+
.removeDuplicates()
43+
.sink { [weak self] isSignedIn in
44+
self?.handleSessionUpdate(isSignedIn: isSignedIn)
45+
}
46+
.store(in: &cancellables)
47+
2948
notificationCenter.publisher(for: .didRefreshFCMToken)
3049
.compactMap { $0.userInfo?["fcmToken"] as? String }
3150
.sink { [weak self] fcmToken in
@@ -49,12 +68,19 @@ final class FCMTokenSyncHandler {
4968
}
5069

5170
private extension FCMTokenSyncHandler {
71+
func handleSessionUpdate(isSignedIn: Bool) {
72+
guard isSignedIn else {
73+
store.setString(nil, forKey: Key.fcmTokenHash)
74+
return
75+
}
76+
77+
requestFCMTokenSync()
78+
}
79+
5280
func requestFCMTokenSync() {
5381
Task { [weak self] in
5482
guard let self else { return }
55-
guard await messagingService.isNotificationAuthorized() else {
56-
return
57-
}
83+
guard await messagingService.isNotificationAuthorized() else { return }
5884
notificationCenter.post(name: .didRequestRemoteNotificationRegistration, object: nil)
5985
await syncCurrentFCMToken()
6086
}
@@ -69,10 +95,8 @@ private extension FCMTokenSyncHandler {
6995

7096
func syncCurrentFCMToken() async {
7197
do {
72-
guard let fcmToken = try await messagingService.fetchFCMToken() else {
73-
return
74-
}
75-
try await userService.updateFCMToken(fcmToken)
98+
guard let fcmToken = try await messagingService.fetchFCMToken() else { return }
99+
try await syncFCMTokenIfNeeded(fcmToken)
76100
} catch {
77101
logger.error("Failed to sync current FCM token", error: error)
78102
}
@@ -81,10 +105,33 @@ private extension FCMTokenSyncHandler {
81105
func syncFCMToken(_ fcmToken: String) {
82106
Task { [weak self] in
83107
do {
84-
try await self?.userService.updateFCMToken(fcmToken)
108+
try await self?.syncFCMTokenIfNeeded(fcmToken)
85109
} catch {
86110
self?.logger.error("Failed to sync refreshed FCM token", error: error)
87111
}
88112
}
89113
}
114+
115+
func syncFCMTokenIfNeeded(_ fcmToken: String) async throws {
116+
guard let uid = authService.uid else {
117+
store.setString(nil, forKey: Key.fcmTokenHash)
118+
logger.info("Skipping FCM token update because no authenticated user exists")
119+
return
120+
}
121+
122+
let tokenHash = makeTokenHash(uid: uid, fcmToken: fcmToken)
123+
guard store.string(forKey: Key.fcmTokenHash) != tokenHash else {
124+
logger.info("Skipping FCM token update because token hash is unchanged")
125+
return
126+
}
127+
128+
try await userService.updateFCMToken(fcmToken)
129+
store.setString(tokenHash, forKey: Key.fcmTokenHash)
130+
}
131+
132+
func makeTokenHash(uid: String, fcmToken: String) -> String {
133+
let value = "\(uid)|\(FirebaseConfiguration.databaseID)|\(fcmToken)"
134+
let digest = SHA256.hash(data: Data(value.utf8))
135+
return digest.map { String(format: "%02x", $0) }.joined()
136+
}
90137
}

0 commit comments

Comments
 (0)