Skip to main content

Command Palette

Search for a command to run...

[트러블슈팅] 알림이 두 번 온다고 ?! 🔥

🚀 트러블슈팅

Updated
3 min readView as Markdown
[트러블슈팅] 알림이 두 번 온다고 ?! 🔥

😼 댕댕어디가 서비스 설명

댕댕어디가 서비스는 반려동물과 함께 갈 수 있는 장소만 확인할 수는 없을까?🧐
댕댕어디가는 반려동물과 함께 외출할 수 있는 시설 정보를 공유함으로써 , 견주들이 보다 편리하고 쾌적하게 외출을 즐길 수 있도록 돕는 서비스이며, 이를 통해 반려동물과 함께하는 활동의 범위가 넓어지고,외출 시의 부담을 줄여주는 서비스를 제공한다✨

🐾 주요기능

  • 땅따먹기

  • 장소 방문 예정 등록

  • 유저 맞춤 장소 추천

알림이 오는 경우

  1. 내가 땅의 주인이 되었을 때

  2. 방문 예정 등록을 했는데, 다른 유저들도 같은 장소와 시간에 등록했을 때

🛠️ 겪었던 문제

➡️ 백그라운드에서 알림이 두 번 오는 현상!

포그라운드에서는 정상적으로 한 번만 도착했지만, 백그라운드에서는 알림이 중복으로 오는 문제가 발생했다… 엄청난 구글링과 AI 도움을 받고자 했으나…

도움이 많이 안 되었다… 🤨 그래서 차근차근 문제를 해결해 나가는 방식으로 ,, ~

✨ 해결 방법

➡️ notification 대신 data로 전달!

➡️ 백그라운드 상태일 때 푸시 알림을 표시하지 않도록 처리

알림을 notification이 아닌 data 타입으로 주고받도록 변경하니 중복 문제가 해결되었다.

💡 왜 이런 현상이 문제가 발생했을까? 에 대한 생각을 했다

이유를 알기 위해서는 일단

notificationdata의 차이를 알아야 한다.

FCM에서 메시지를 보낼 때 두 가지 방식이 있는데

notification 메시지

  • FCM이 알아서 알림을 처리하고 표시함.

  • 앱이 백그라운드에 있을 때 자동으로 시스템 트레이에 알림이 뜸.

  • 개발자가 커스텀할 수 있는 게 거의 없음.

data 메시지

  • 앱에서 직접 알림을 처리해야 함.

  • 백그라운드에서도 알림이 자동으로 표시되지 않음.

  • 개발자가 원하는 대로 알림 UI를 만들거나 데이터를 가공할 수 있음.

의 특징이 있으며

내가 이러한 문제를 겪었던 이유

  1. notification으로 보내면, FCM이 자동으로 알림을 띄움.

  2. 그런데 앱에서도 같은 데이터를 받아서 push 알림을 추가로 띄우면, 중복 알림이 발생!

  3. 그래서 data로 변경하면, 앱이 직접 알림을 관리할 수 있어서 중복 문제를 해결할 수 있었다.


📍 알림 로직

firebase-messaging-sw.js

  • payload로 처리하기
export const setupOnMessageHandler = () => {
  onMessage(messaging, (payload) => {

      if (document.visibilityState === "hidden") {
        return; // 백그라운드 상태일 때 푸시 알림을 표시하지 않도록 !!! 꼭 해주기  
        }

    if (payload && payload.data) {
      const { title, body, image, icon} = payload.data;

      const notificationTitle = title || "알림";
      const notificationOptions = {
        body: body || "내용이 없습니다.",
        image: image || null,
        icon: icon || "/alarm-logo.png", //우리 플젝은 알림 로고도 제작했다 
      };

      const notification = new Notification(notificationTitle, notificationOptions);

      notification.onclick = function (event) {
        const url = payload.data.url; 
        event.preventDefault();

        if (url) {
          window.location.href = url; 
        } else {
          console.error("URL 데이터가 없습니다.");
        }
        notification.close();
      };
    } else {
      console.error("페이지가 백그라운드 상태입니다. 포그라운드 상태에서만 알림을 표시합니다.");
    }
  });
};

알림페이지에 들어가면

  • 백엔드에서 사용자의 알림 동의 여부를 확인

  • 서비스 워커를 등록하여 푸시 알림 기능 활성화

  •       useEffect(() => {
              const fetchNotificationConsent = async () => {
                try {
                  setIsLoading(true);
                  const response = await axiosInstance.get(
                    "/api/v1/notifications/consent",
                    { withCredentials: true }
                  );
    
                  if (response.status === 200) {
                    setIsSubscribed(response.data.data.isNotificationConsent);
                  } else {
                    console.error("알림 활성화 상태 확인 실패:", response);
                  }
                } catch (error) {
                  console.error("알림 활성화 상태 요청 중 오류:", error);
                } finally {
                  setIsLoading(false);
                }
              };
    
              fetchNotificationConsent();
    
              if ("serviceWorker" in navigator) {
                navigator.serviceWorker
                  .register("/firebase-messaging-sw.js")
                  .catch((error) => {
                    console.error("Service Worker 등록 실패:", error);
                  });
              } else {
                console.warn("이 브라우저는 Service Worker를 지원하지 않습니다.");
              }
            }, []);
    

✍🏻 트러블슈팅하며 배운 점

이번 문제를 해결하면서, 문제 처리 방식에 대한 깊은 이해가 필요하다는 것을 다시 한 번 느꼈다. 무조건적으로 AI에 의존하지 말자

notificationdata 메시지의 차이를 알게 된 후 FCM을 더 효과적으로 활용할 수 있다는 것을 깨달았다.

특히 백그라운드 상태에서의 알림 처리가 얼마나 중요한지 + 처리 방식에 따라 사용자 경험에 큰 영향을 미칠 수 있다는 점도 배웠다.✨

More from this blog

[React] 클라이언트에서 이미지를 압축해보자

우리는 서버 비용을 직접 부담하고 있기 때문에 항상 최적화와 비용 절감 방법을 고민하게 된다. 현재 자유게시판이 활성화가 많이 되지는 않았지만 사용자들이 업로드하는 이미지가 평균 5MB 이상일 경우를 대비해서 클라이언트에서 이미지 압축을 진행했다. 웹에서는 크게 두 가지 방법이 있었는데 Canvas API를 직접 사용하는 방법 browser-image-compression 라이브러리를 활용하는 방법 이 있다. 여러 장점을 고려해 brow...

Oct 8, 20252 min read
[React] 클라이언트에서 이미지를 압축해보자

[책 추천] 프론트엔드 개발자라면 반드시 알아야 할 '웹 접근성' 이야기

내가 생각하는 프론트엔드 개발자는 단순히 보이는 화면만 구현하는 것을 넘어서 누구나 접근할 수 있는 웹을 만드는 데 중요한 역할을 해야 한다고 생각한다. 실무에 바로 적용하는 웹 접근성 가이드북 이번에 이 책을 받고 프엔들이 읽기에 너무 좋다고 생각해서 블로그에 추천 글까지 적게 되었다 ! 목차 Chatper1. 쉽게 이해하는 접근성 Chapter2. 웹 접근성의 기초 Chapter3. HTML 태그, 의미 있게 사용하기 Chpater4...

Jul 27, 20255 min read
[책 추천] 프론트엔드 개발자라면 반드시 알아야 할 '웹 접근성' 이야기

[Next.js] 나만의 학습 블로그 만들기#3-다국어 지원 (Feat.next-i18next)

오늘은 다국어 지원 가능한 기능 구현 과정을 적어보려고 한다. 원래는 댓글기능보다 먼저 구현하려고 했는데 ,, 갑자기 댓글기능 알아보다가 재밌어서 먼저 끝내버렸다,,,🙄 시작하기 전에 정말 어려웠다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 어려움이 많아서 기능 적용하는 데 시간이 꽤 걸렸다 ,,, 다국어 지원 기능 나는 영어랑 일본어를 추가해줬다 ! (해외취업도 관심 있기 때문에 나중에 이력서 낼 때 도움이 되지 않을까? ..🤭) 다국어 구현 방법 구현 방...

Jul 15, 20254 min read
[Next.js] 나만의 학습 블로그 만들기#3-다국어 지원 (Feat.next-i18next)

[Next.js] 나만의 학습 블로그 만들기#4 - 댓글 기능(Feat. Giscus)

댓글기능이 있으면 무조건 재밌을 거 같아서 넣어보려고 한다🤭 아무래도 개발에 관련된 학습 블로그라서 개발자들이 많을 것으로 예상했다 ! 그래서 깃허브 이슈 기반 댓글 시스템을 기반으로 기능을 구현해보려고 한다. 👉🏻 도움이 많이 된 블로그 ! 방법 Giscus | (https://giscus.app) utterances | (https://utteranc.es) 알아봤을 때는 이렇게 두 개가 유명하다고 한다. 그럼 각각의 특징과 장...

Jul 14, 20253 min read
[Next.js] 나만의 학습 블로그 만들기#4 - 댓글 기능(Feat. Giscus)

[React] React + localStorage로 하루에 한 번만 보이는 팝업 만들기

이번 프로젝트에 설문조사 배너를 제작했는데… 흠… 뭔가 별로라는 의견이 많았다! (팀원들 의견) 🙄 디자인이 문제일까? 해서 래퍼런스를 많이 찾아봤는데 … ! 일반 웹사이트는 설문조사 배너 자체를 안 만들어요,,,🤭 충격 그 자체 ( 난 아직 멀었음 ) 그리고 알아보니깐.. 설문조사 배너는 사용자 경험을 해치기 쉬워 잘 쓰이지 않는다고 한다! 그래서 나는 모달 팝업 방식으로 전환하기로 결정했고 실무에서 자주 사용하는 패턴으로 구현했다. 방...

Jul 9, 20253 min read
[React] React + localStorage로 하루에 한 번만 보이는 팝업 만들기
S

subin-dev-blog

27 posts

끊임없이 배우기 위해 노력합니다. 🌱