웹은 괜찮은데, 왜 앱에서만 알림이 세 번씩 올까? - FCM 중복 알림 해결기

keemsebeen·1일 전
0
post-thumbnail

문제 상황

FCM을 이용한 푸시 알림 기능은 웹에서는 정상적으로 한 번만 수신되었지만, 앱에서는 하나의 알림이 세 번 중복 수신되는 현상이 발생했습니다.

초기에는 프론트엔드 단에서 tag와 key를 활용한 중복 제어 로직을 추가해 해결을 시도했지만, 알림이 여전히 여러 번 표시되는 문제가 지속되었습니다.

이 문제를 해결하기 위해 서비스 워커와 PWA, FCM의 동작 원리를 살펴보았고, 이를 통해 얻은 인사이트와 해결 과정을 정리했습니다.

알람이 왜 세번씩이나 올까?

원인은 크게 두가지였습니다.
첫번째 원인은 FCM의 메시지 수신 중첩 구조였고 두번째 원인은 notification필드의 자동 표시 동작이었습니다.

기존 알람 수신 구조는 다음과 같습니다.

  1. onBackgroundMessage 이벤트 - 브라우저 탭이 열려 있을 때 Firebase SDK를 통해 작동
  2. push 이벤트 - 브라우저의 서비스 워커가 직접 푸시 이벤트를 수신

이 두 핸들러가 동시에 등록되어 있었고, 특히 서비스 워커 내부에서 onBackgroundMessageself.addEventListener('push')가 모두 showNotification() 를 호출하면서 하나의 메시지가 두 번 표시되는 현상이 발생했습니다.

게다가 FCM 메시지에 notification 필드가 포함되어 있으면, 브라우저가 이를 감지해 자동으로 시스템 알림을 표시합니다. 따라서 명시적으로 작성한 showNotification() 코드와 브라우저의 기본 알림이 중복 표시되는 문제까지 함께 발생한 것이었습니다.

해결 방법

  1. 중복 핸들러 제거

    서비스 워커 내부의 messaging.onBackgroundMessage() 이벤트 리스너를 제거하고, push 이벤트만 남겨 알림 수신을 경로를 단일화했습니다.

  2. notification 필드 제거

    서버에서 FCM 메시지를 전송할 때, notificaiton 객체를 제거하고, 대신 data 필드에 title, body를 포함하도록 서버 측에 요청했습니다.

문제를 해결하면서 자연스럽게 이런 의문이 생겼습니다.

“왜 onBackgroundMessage 이벤트를 남기면 안 되는 걸까?”
“왜 notification 객체를 사용하면 중복 알림이 발생할까?”

이 두 질문의 답을 찾는 과정에서 서비스 워커와 FCM의 구조를 더 깊이 이해할 수 있었고, 이에 대해 정리한 내용을 아래에 공유합니다.

왜 push 이벤트만 존재하고 Firebase 이벤트는 없어도 될까?

FCM은 브라우저의 푸시 서비스(Web Push API)를 이용해 메시지를 전달합니다.

즉, Firebase 서버 → 브라우저 벤더 푸시 서버(Chrome, Safari, Edge 등) → 서비스 워커의 push 이벤트 이 순서로 동작합니다. 결국 브라우저가 FCM 서버로부터 메시지를 수신하면, 서비스 워커 내부의 push 이벤트를 자동으로 호출해 알림을 표시합니다.

따라서 서비스 워커에서 이미 push 이벤트를 정의했다면, 브라우저는 FCM으로부터 온 메시지를 해당 핸들러로 바로 전달합니다. 결국 별도의 Firebase 이벤트가 없어도 문제없이 작동하는 것 입니다.

이에 대해 하나씩 설명해보도록 하겠습니다.

push는 Web Push API의 표준 이벤트

  • push 이벤트는 브라우저가 제공하는 표준 서비스 워커 API입니다.
  • FCM을 포함한 모든 푸시 서비스는 최종적으로 이 push 이벤트를 통해 서비스 워커에 메시지를 전달합니다.
  • Firebase SDK를 사용하든 안하든, 푸시 메시지는 항상 push 이벤트로 도착합니다.

onBackgroundMessage()는 헬퍼함수

Firebase SDK의 onBackgroundMessage()는 사실상 push 이벤트를 내부적으로 래핑한 헬퍼 함수입니다.

self.addEventListener('push', (event) => {
  // FCM payload parsing 및 showNotification 호출
});

즉, onBackgroundMessage 는 ****서비스 워커에 직접 push 이벤트 핸들러를 작성하기 어려운 개발자를 위해 Firebase가 대신 등록해주는 편의용 함수입니다.

따라서 self.addEventListener('push')를 직접 작성했다면 Firebase의 onBackgroundMessage()는 불필요하며, 오히려 중복 알림 문제를 만들 수 있습니다.

요약

구분push 이벤트onBackgroundMessage()
기본 동작 주체브라우저 표준 Push APIFirebase Web SDK (내부적으로 push 이벤트 사용)
실행 위치Service WorkerService Worker
의존성없음 (Firebase SDK 없어도 가능)Firebase SDK 필요
사용 목적커스텀 알림 처리 (정제된 payload, 클릭 제어 등)간단한 알림 수신 시 편의용
중복 가능성단독 사용 시 안전push와 병행 시 중복 발생 가능

결론적으로, FCM은 결국 브라우저의 Web Push API 위에서 동작하기에 self.addEventListener('push')만으로도 메시지를 완전히 수신하고 처리할 수 있습니다. onBackgroundMessage()는 단순히 Firebase SDK가 제공하는 “편의용 래퍼”이기 때문에, 두 이벤트를 함께 쓰면 중복 알림이 발생할 수 있습니다.

data와 Notification은 어떤 차이일까?

두 필드는 크게 발생 주체, 동작 방식, 제어 가능 여부에서 차이가 있습니다.

notification 필드 사용 시

  • FCM이 notification 필드를 감지하면 브라우저(또는 OS)가 자동으로 알림을 표시합니다.
  • 개발자가 서비스 워커에서 showNotification()을 호출하지 않아도 알림이 표시됩니다.
  • 간단한 알림에는 편리하지만, 앱에서 중복 표시 문제가 발생할 수 있습니다.

data 필드 사용 시

  • 브라우저나 OS는 자동으로 알림을 표시하지 않습니다.
  • 서비스 워커의 push 이벤트나 onBackgroundMessage()에서 개발자가 직접 처리해야 합니다.
  • 중복 제어, 클릭 액션, 알림 그룹화 등 세밀한 커스터마이징이 가능합니다.

비교표

구분notification 필드data 필드
주체브라우저/OS개발자(Service Worker 코드)
동작 방식FCM이 이 필드를 감지하면, 브라우저/OS가 자동으로 알림 표시브라우저는 자동으로 표시하지 않음. self.addEventListener('push') 또는 onBackgroundMessage()에서 직접 처리 필요
알림 제어 가능 여부제한적 - 표시 시점, 클릭 동작 등 제어 어려움완전 제어 - 표시 여부, 클릭 동작, 그룹화 등 모두 커스텀 가능
표시 위치브라우저/OS가 직접 표시개발자가 registration.showNotification()으로 직접 표시
의도된 용도간단한 알림 (즉시 표시)복잡한 동작이 필요한 알림 (딜레이, 상태, 트래킹 등)

(번외) 왜 웹에서는 정상인데 앱에서만 중복되었을까?

웹에서는 알림 수신의 주체가 브라우저 하나뿐입니다. 따라서 onBackgroundMessagepush 이벤트 중 하나만 유효하게 작동하고, 결과적으로 알림이 한 번만 표시됩니다.

반면, 앱은 수신 경로가 여러 계층으로 나뉘어 있어 중복 수신이 발생합니다.

  1. OS 레벨의 FireBase SDK(Android/iOS)가 먼저 메시지를 수신
  2. OS SDK가 notification 필드를 감지 → OS가 자체로 알림 표시
  3. 앱 내부 웹뷰에서도 동일한 FCM 메시지가 전달되어 SDK + 서비스 워커가 추가로 알림 표시

정리하자면, 웹은 FCM 수신과 표시가 전부 브라우저 내에서 일어나지만, 앱은 OS의 Firebase SDK웹뷰의 서비스 워커라는 서로 다른 계층에서 같은 메시지를 동시에 처리하기 때문에 중복 알림이 발생했습니다.

참고링크

https://stackoverflow.com/questions/66697332/firebase-web-push-notifications-is-triggered-twice-when-using-onbackgroundmessag

https://www.reddit.com/r/PWA/comments/1im6o5p/duplicate_push_notifications_on_web_version_and/

profile
프론트엔드 공부 중인 김세빈입니다. 👩🏻‍💻

0개의 댓글