Skip to content

[Work 58] FCM 등록을 설치 ID 방식으로 전환해 푸시 발송 대상이 저장되지 않던 문제를 해결했습니다. - #28

Merged
sangYuLv merged 2 commits into
WORK-57from
WORK-58
Oct 1, 2026
Merged

sangYuLv merged 2 commits into
WORK-57from
WORK-58

Conversation

@sangYuLv

Copy link
Copy Markdown
Collaborator

JIRA

⚠️ WORK-57 브랜치를 기준으로 만든 PR입니다. WORK-57이 먼저 머지된 뒤에 머지합니다

📝 작업 내용

📌 요약

  • 앱 재실행·재로그인 시 푸시 발송 대상이 서버에 저장되지 않던 문제 해결
  • 푸시 발송 대상을 FCM 토큰 → Firebase 설치 ID로 전환
  • Firestore 유저 문서 필드 fcmToken → fcmInstallationID
  • Firebase 12.19.2 · NMapsMap 3.24.0 패키지 업데이트

🔍 상세

[1] 저장·삭제 흐름

  1. 앱 실행(로그인 상태) / 로그인 직후: APNs 등록 → Messaging.register() 호출 → 대리자 didReceiveRegistration으로 설치 ID 수신 → Firestore 저장
  2. 로그아웃, 알림 권한 거부 상태로 포그라운드 진입: Firestore에서 삭제 (기존과 동일)

[2] 이름 변경 (토큰 → 설치 ID)

  • FCMTokenRepository / FirestoreFCMTokenRepository → FCMInstallationIDRepository / FirestoreFCMInstallationIDRepository
  • FCMTokenService / DefaultFCMTokenService → FCMInstallationIDService / DefaultFCMInstallationIDService
  • AppDelegate: 메모리에 토큰을 들고 있던 latestFCMToken 제거, 대리자 didReceiveRegistrationToken → didReceiveRegistration

[3] 설정·패키지

  • Info.plist: FirebaseMessagingInstallationIdEnabled = YES (설치 ID 방식 활성화)
  • Firebase 12.18.0 → 12.19.2, NMapsMap 3.23.3 → 3.24.0 (일괄 업데이트로 함께 올라감, 지도 정상 확인)

💬 리뷰 노트

문제: 푸시 대상이 저장되지 않았습니다

9/20 이후 로그인 상태로 앱을 켜도, 재로그인해도 Firestore에 푸시 대상이 저장되지 않았습니다.

기존 코드는 FCM이 대리자(didReceiveRegistrationToken)로 토큰을 알려줄 때 저장했습니다. 그런데 이 대리자는 토큰이 처음 생기거나 바뀔 때만 SDK가 알아서 호출하고, 앱이 "다시 알려줘"라고 요청할 방법이 없었습니다.
그래서 "토큰이 처음 생긴 그 실행 + 로그인 상태"에서만 저장됐고, 그 뒤로 앱을 다시 켜면 대리자가 오지 않아 저장되지 않았습니다. (기기 로그로 확인: APNs 토큰 수신까지 정상, 대리자는 한 번도 호출되지 않음)

👉 결론: 원할 때 대리자를 다시 부를 수 있는 새 방식(register())으로 전환

개념: 토큰과 설치 ID

푸시를 보내려면 서버가 "어느 앱 설치로 보낼지" 주소를 알아야 합니다. 앱은 이 주소를 Firestore에 저장하고, 서버는 그걸 읽어 보냅니다.

FCM 토큰 (기존) 설치 ID (변경)
정체 설치 ID를 바탕으로 FCM이 따로 발급한 발송 주소 Firebase가 앱 설치마다 붙이는 식별자를 그대로 발송 주소로 사용
단위 앱 설치 앱 설치 (같음)
앱에서 값 받기 대리자(SDK가 알아서 호출) 또는 token()(반환값으로 직접 받음) register() 호출 → 대리자로 받음
서버 발송 필드 token — deprecated, 제거 예정 fid — 권장

단위는 같고, 중간에 토큰을 따로 발급하던 단계가 없어진 것입니다. 실제로 같은 기기의 토큰(cRvbYBJxek3D…)과 설치 ID(cRvbYBJx…)는 앞부분이 같습니다.

register()와 대리자의 관계

  • register()의 완료 블록은 성공·실패만 알려주고, 설치 ID는 항상 대리자 didReceiveRegistration으로 옵니다.
  • 대리자는 등록이 새로 생기거나 바뀔 때도 오지만, 이미 등록된 상태에서 register()를 불러도 기존 설치 ID로 다시 호출됩니다. (SDK 헤더 FIRMessaging.h: "Calling this method when already registered will still invoke the delegate method … with the existing FID.")
  • 그래서 APNs 등록 직후 매번 register()를 부릅니다. APNs 등록은 앱 실행과 로그인 직후 모두 일어나므로, 두 경우 모두 저장됩니다.
  • 로그인 전에 대리자가 오면 유저 ID가 없어 저장을 건너뛰고, 로그인 직후 다시 저장됩니다.

기기 확인 (에뮬레이터 유저 문서): 로그아웃 시 삭제, 로그인 상태로 앱 재실행 시 설치 ID 저장 확인

토큰 방식을 고치지 않고 전환한 이유

토큰 방식에서도 token()으로 직접 받아 저장하면 버그는 해결됩니다(기기에서 확인). 그래도 전환한 이유는 이렇습니다.

  • token()과 기존 대리자는 deprecated(SDK 12.18.0)라 새 경고가 생깁니다.
  • 서버 발송의 token 필드도 제거 예정입니다.
  • 푸시를 보내는 서버 코드(Functions)가 아직 없어서, 지금 바꾸면 서버 쪽 비용이 없습니다.

참고할 변경점

  • Firebase 12.19.2: 설치 ID 방식을 켰을 때 기기 언어 변경으로 등록이 잘못 무효화되던 버그가 12.19.x에서 수정됐습니다.
  • Firestore 필드 이름 변경: 이 필드를 읽는 서버 코드가 아직 없고 기존 값도 저장되지 않던 상태라, 데이터 이전은 필요 없습니다.

추후 작업

  • 3단계 서버 푸시 구현 시 fcmInstallationID를 Admin SDK 메시지의 fid 필드로 발송
  • 한 달 이상 접속 없는 등록 정리 방식은 서버 설계 때 결정

참고 문서

Firebase 문서 한국어판은 업데이트가 늦어 설치 ID 내용이 없습니다. 아래는 영어 원문 링크입니다.

📸 영상 / 이미지

@sangYuLv
sangYuLv requested a review from snughnu September 28, 2026 15:57
@sangYuLv sangYuLv self-assigned this Sep 28, 2026
@sangYuLv
sangYuLv added this pull request to stack #29 September 28, 2026 15:57
@sangYuLv sangYuLv changed the title [WORK-58] FCM 등록을 설치 ID 방식으로 전환해 푸시 발송 대상이 저장되지 않던 문제를 해결했습니다. [Work 58] FCM 등록을 설치 ID 방식으로 전환해 푸시 발송 대상이 저장되지 않던 문제를 해결했습니다. Sep 29, 2026

@snughnu snughnu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확인했습니다 🙊

@sangYuLv
sangYuLv merged commit 06d5630 into develop Oct 1, 2026
5 checks passed
@sangYuLv
sangYuLv deleted the WORK-58 branch October 1, 2026 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants