본문 바로가기
📁 기타/Etc.

웹에서 Firebase Cloud Messaging(FCM) 푸시 알림 적용하기

by d0bby 2025. 8. 20.

 

 

 

웹에서 푸시 알림을 붙여야 하는 일이 생겼습니다.
앱에서는 흔히 쓰던 FCM이지만, 웹은 처음이라 문서를 보면서 하나씩 적용해봤습니다.
생각보다 놓치기 쉬운 포인트가 있어서 정리해둡니다.

 


 

1. 사전 준비

  • HTTPS 환경에서만 동작합니다. (개발은 http://localhost 허용)
  • Firebase 콘솔 → Project settings → Cloud Messaging → Web configuration에서 VAPID Key를 생성하고 Public Key를 복사해둡니다.
  • iOS Safari는 iOS 16.4 이상, 그리고 홈 화면에 추가된 PWA 환경이어야 알림이 옵니다.

👉 여기서 첫 번째 깨달음: 서비스워커, HTTPS, VAPID 키 이 세 가지가 없으면 진행이 안 됩니다.

 


2. Firebase 초기화

먼저 Firebase SDK를 초기화합니다.
공용으로 불러다 쓰기 위해 firebase.ts라는 파일을 만들어뒀습니다.

import { initializeApp, getApps } from "firebase/app";
import { getMessaging, isSupported } from "firebase/messaging";

const firebaseConfig = {
  apiKey: "...",
  authDomain: "...",
  projectId: "...",
  messagingSenderId: "...",
  appId: "...",
};

export const app = getApps().length ? getApps()[0] : initializeApp(firebaseConfig);

export const messagingPromise = isSupported().then((ok) =>
  ok ? getMessaging(app) : null
);

 


3. 서비스 워커

FCM은 백그라운드 메시지를 서비스워커에서 받아 처리합니다.
반드시 public/ 폴더에 두어야 하며, 경로는 /firebase-messaging-sw.js가 됩니다.

importScripts('https://www.gstatic.com/firebasejs/10.12.2/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/10.12.2/firebase-messaging-compat.js');

firebase.initializeApp({
  apiKey: "...",
  authDomain: "...",
  projectId: "...",
  messagingSenderId: "...",
  appId: "...",
});

const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  const { title, body } = payload.notification || {};
  self.registration.showNotification(title || '알림', { body });
});

👉 여기서 한 번 막혔습니다.
처음에 src/ 아래에 두고 import하려 했는데, 서비스워커는 오직 public/에 두어야 최상위 경로로 배포됩니다.

 


4. 권한 요청 + 토큰 발급 + 포그라운드 수신

권한을 요청하고 토큰을 발급받는 부분은 클라이언트 컴포넌트에서 처리합니다.
Next.js Pages Router를 쓰고 있어서 \_app.tsx에 전역으로 추가했습니다.

'use client';

import { useEffect } from 'react';
import { messagingPromise } from '@/app.modules/util/firebase';
import { getToken, onMessage } from 'firebase/messaging';

const VAPID_PUBLIC_KEY = 'Firebase 콘솔에서 복사한 Public Key';

export default function FcmInit() {
  useEffect(() => {
    (async () => {
      const reg = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
      const messaging = await messagingPromise;
      if (!messaging) return;

      const perm = await Notification.requestPermission();
      if (perm !== 'granted') return;

      const token = await getToken(messaging, {
        vapidKey: VAPID_PUBLIC_KEY,
        serviceWorkerRegistration: reg,
      });
      console.log('[FCM] token:', token);

      onMessage(messaging, (payload) => {
        console.log('[FCM] foreground message:', payload);
      });
    })();
  }, []);

  return null;
}

 

그리고 \_app.tsx에서 한 번만 실행되도록 추가합니다.

import type { AppProps } from 'next/app';
import FcmInit from '@/app.components/FcmInit';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <FcmInit />
      <Component {...pageProps} />
    </>
  );
}

export default MyApp;

 


5. 서버 연동은 어떻게?

여기까지는 클라이언트 세팅입니다.
실제로 알림을 발송하려면 서버에서 토큰을 저장하고, Firebase Admin SDK로 푸시를 전송해야 합니다.
프론트 단에서는 토큰을 발급받아 서버에 전달하는 것까지만 담당합니다.

서버 개발이 준비되기 전에는 Firebase 콘솔에서 직접 토큰을 입력해 테스트 메시지를 보내 확인할 수 있습니다.
이 방법으로 브라우저에서 정상적으로 알림이 오는 걸 확인했습니다.

 


6. 마무리

정리하자면:

  1. Firebase 프로젝트 생성 및 VAPID Key 준비
  2. 초기화 코드 작성 (firebase.ts)
  3. 서비스워커 배치 (public/firebase-messaging-sw.js)
  4. 권한 요청 + 토큰 발급 + 포그라운드 수신 (FcmInit.tsx)
  5. 서버와 연동하여 토큰 저장/푸시 발송 구조로 확장

👉 웹에서 FCM을 적용하는 건 문서만 보면 단순해 보이지만, 막상 해보면 놓치기 쉬운 포인트가 많습니다.
이 글이 같은 작업을 준비하는 분들께 도움이 되길 바랍니다.

 

반응형