프로젝트/팀블로그

[FrontEnd] FCM을 이용해 웹 푸시 알림 적용하기

만두맨두 2023. 9. 5. 16:07
 

[FrontEnd] FCM을 이용해 웹 푸시 알림 적용하기

안녕하세요 : ) 텔링미의 프론트엔드 개발자 밍(Ming)입니다 !

medium.com

 

안녕하세요 : )
텔링미의 프론트엔드 개발자 밍(Ming)입니다 !!

 

저번 카카오 로그인 게시글 이후로 약 두 달 만인데, 잘 지내셨을까요 ~?
오늘은 웹 푸시 알림에 대해 설명해 드리려고 합니다.

 

그전에..!
텔링미에서 정식 출시되는 서비스에는 슬프게도 웹 푸시 알림은 제외하기로 결정하게 되었어요 ..🥲
그래도 지금까지 제일 어렵고 제일 헤맸던 기능인 푸시 알림에 대한 것들을 기록하고 설명해 드리고 싶어서 가져오게 되었습니다.

 

지금부터 저의 아픈 손가락,, 푸시 알림에 대해 알아보도록 할까요 ?!


설치 + 기본 세팅

푸시 알림을 구현하면서 제일 먼저 든 생각은 자료가 많이 없다는 것이었어요.
그래서 최대한 공식 문서를 참고했습니다.

 

자바스크립트 Firebase 클라우드 메시징 클라이언트 앱 설정

Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 자바스크립트 Firebase 클라우드 메시징 클라이언트 앱 설정 컬렉션을 사용해 정리하기 내 환경설정을 기준으로

firebase.google.com

 

( FCM 프로젝트 생성하는 과정은 생략할게요 ! )

 

1. 설치

프로젝트 생성 후에 앱 등록까지 마치면,
아래와 같이 설치 명령어와 SDK 코드를 제공해 줄 거예요.

그런데 저희는 약간 다른 명령어와 코드를 사용할 예정입니다.
왜냐하면 위에서는 파이어베이스 v9를 위한 방법을 소개한 건데,
v9를 사용하려고 했더니 계속 오류가 나더라구요...🥲
듣기로는 번들러 설정을 해야 되는 것 같았지만,
너무 시간을 많이 잡아먹어서 결국엔 v8로 변경해 진행하게 되었어요 ...!
( 혹시 v9로 설공하신 분이 계시다면,, 저에게 가르침을,, )

정확한 버전은 8.10.0을 사용했습니다 !

 

[ 명령어 ]

npm i firebase@8.10.0

package.json

 

2. SDK 추가

사실 이 과정은 붙여넣기만 하면 된답니다.

// src/firebase-messaging-sw.ts (파일명은 아무거나 해도 상관없습니다 !)

import firebase from 'firebase/app'
import 'firebase/messaging'

const firebaseConfig = {
  apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
  storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_FIREBASE_APP_ID,
  measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID
}

firebase.initializeApp(firebaseConfig)

사진에서의 코드와 비슷하지만 약간 다르죠 ?
이 코드가 v8에서 사용할 수 있는 코드입니다.
firebaseConfig는 보안상 문제가 될 수 있으므로, 환경변수로 관리해 주시는 게 좋아요.

 

그리고 위의 파일을 App.tsx에 import 해주면 SDK 추가는 끝이에요 !

// src/App.tsx

import './firebase-messaging-sw.ts'

 

Notification 권한 요청 + 토큰 받기

브라우저를 사용할 때, 위의 사진처럼 권한을 요청하는 알람이 뜬 적 있나요 ?
이 알람을 통해 푸시 알림 허가를 받을 수 있어요.

 

1. VAPID KEY 생성하기

FCM은 토큰을 통해 푸시 알림을 전송해요.
이때 토큰을 받아올 수 있도록 해주는 게 VAPID KEY입니다.

VAPID KEY 발급 과정을 아래와 같습니다.

 

● 해당 프로젝트 들어가기

● '프로젝트 개요' 옆의 설정 아이콘 > '프로젝트 설정' 들어가기

● '클라우드 메시징' 들어가기

● '웹 구성'에서 Generate key pair 버튼 누르기

 

키 쌍에 있는 게 VAPID KEY입니다.

이것도 보안상 문제가 될 수 있으므로 환경 변수로 관리해주세요 !


2. 권한 요청 알림창 띄우기

다시 src/firebase-messaging-sw.ts로 돌아가서 아래의 코드를 넣어주세요.

// src/firebase-messaging-sw.ts

// ...

const messaging = firebase.messaging()

export function requestPermission() {
  void Notification.requestPermission().then((permission) => {
    if (permission === 'granted') {
      messaging
        .getToken({ vapidKey: process.env.REACT_APP_FIREBASE_VAPID_KEY })
        .then((token: string) => {
          console.log(`푸시 토큰 발급 완료 : ${token}`)
        })
        .catch((err) => {
          console.log('푸시 토큰 가져오는 중에 에러 발생')
        })
    } else if (permission === 'denied') {
      console.log('푸시 권한 차단')
    }
  })
}

Notification.requestPermission()은 알림창을 띄울 수 있게 합니다.

그리고 사용자가 차단 또는 허용을 누르면 permission으로 그 값이 들어와요.

 

permission이 'granted'면 권한을 허락했다는 뜻입니다.
이때 토큰을 받아오면 되죠 !
토큰은 messaging.getToken()VAPID KEY를 보내면 받아올 수 있어요.

 

이 알림창은 약간 까다로운데요.
사용자가 한 번이라도 허용 또는 차단을 눌렀다면, permission 값은 변하지 않습니다.
사용자가 직접 브라우저의 설정을 건드리지 않는 이상 알림창을 다시 뜨게 할 수도 없죠.
즉, 개발적인 측면으로는 단 한 번의 알림창을 띄우는 것만 할 수 있다는 뜻이에요.

 

텔링미의 세팅 페이지 일부

" 잠깐 ! 텔링미에선 토글로 푸시 알림을 조절하는데요 ? "

 

맞아요 텔링미는 푸시 알림을 조절할 수 있습니다.
하지만, 조건이 하나 있어요.

 

사용자는 단 한 번의 알람창에서 '허용'을 눌러야 한다.

 

그럼 브라우저 푸시 알림 자체는 항상 허용이고, 서버 측에서 notification 여부를 확인해 토글이 on인 상태인 사용자들에게만 푸시를 보내는 원리입니다.

 

하지만, 차단을 눌렀다면 사용자가 직접 브라우저 설정에 들어가 변경하는 방법밖엔 없어요 ...ㅠㅠ

 

3. 테스트 푸시 보내기

아직 한 단계가 남았지만, 토큰만으로 테스트를 해볼 수 있어요.
과정을 아래와 같습니다.

 

●  해당 프로젝트 들어가기

●  왼쪽 메뉴의 '참여' > 'Messaging' 들어가기

●  '첫 번째 캠페인 만들기' 누르기

●  'Firebase 알림 메세지' 누르고 '만들기' 버튼 누르기

●  알림 내용 적어주고 '테스트 메세지 전송' 버튼 누르기

●  FCM 등록 토큰 추가하고 선택한 다음 '테스트' 버튼 누르기

 

그럼 아래와 같이 테스트 푸시가 올 거예요 ~!

 

서비스워커 생성하기

서비스워커는 백그라운드에서 실행되는 스크립트로, 서비스를 실행하지 않거나, 브라우저가 닫혀있을 때 등에도 푸시 알림을 받을 수 있도록 해요.

 

FCM의 서비스 워커는 파일명이 정말 정말 중요합니다.

"firebase-messaging-sw.js"으로 만드셔야 해요.
그리고 public에 파일을 둬야 합니다.

파일명파일 위치 잊으시면 안 돼요.

꼭이에요... 꼭... 😇

서비스워커는 위에 설명한 것만 알면 진짜 끝이에요.
그다음은 공식 문서에서 제공하는 코드 그대로 적어두면 됩니다.

// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here. Other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
const firebaseApp = firebase.initializeApp({
  apiKey: 'api-key',
  authDomain: 'project-id.firebaseapp.com',
  databaseURL: 'https://project-id.firebaseio.com',
  projectId: 'project-id',
  storageBucket: 'project-id.appspot.com',
  messagingSenderId: 'sender-id',
  appId: 'app-id',
  measurementId: 'G-measurement-id',
});

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();

단, 여기서 process.env.REACT_APP_이 적용이 안될 텐데요.
위에서 보안 상의 문제로 환경 변수로 관리하는 게 좋을 것 같다고 말은 했지만,
크게 문제가 되지 않는다고 합니다 (?).
혹시 모를 상황에 대비하기 위함이었어요.

 

하지만, 적용이 되지 않는 상황에서는 그대로 올릴 수밖에 없습니다.
그래서 꼭 필요한 것들만 코드로 올려두었어요.
apiKey, projectId, messagingSenderId, appId만 올려주세요 !

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

const firebaseApp = firebase.initializeApp({
  apiKey: 'api-key',
  projectId: 'project-id',
  messagingSenderId: 'sender-id',
  appId: 'app-id',
})

const messaging = firebase.messaging()

 

이후에는 프로젝트마다 방향성이 다를 거예요.

텔링미는 토큰을 서버로 넘겨서 매일 12시마다 푸시 알림을 보낼 수 있도록 했습니다 !

 

추가 팁 !

텔링미에 합류하면서 처음으로 '크로스 브라우징'에 대한 문제를 겪어봤어요.
거기에 푸시 알림도 포함이 되는데요 ...

클라우드 메시징에서 iOS Safari와 Safari에 있는 저 아이콘이 보이시나요 ?
지원이 안 된다는 의미입니다...😇
그래서 사파리에서 텔링미에 들어가면 에러 때문에 흰 화면만 보였어요.

 

FCM에서도 이를 도와주기 위해서 FCM이 되는 브라우저인지 아닌 지를 확인할 수 있는 함수를 제공하고 있습니다.

firebase.messaging.isSupported() // true | false

이를 사용해서 false인 브라우저는 아예 실행이 되지 않도록 막을 수 있어요 !


마지막으로 웹에서 푸시 알림을 제거한 이유를 간단히 설명하려고 해요.
iOS 개발을 맡고 있는 미미의 글을 보면 텔링미의 푸시 알림 문제점을 잘 설명해 주었어요 !

https://medium.com/@tellingmetime/ios-%ED%85%94%EB%A7%81%EB%AF%B8-push-notification-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0-31832173d648

텔링미는 앱 최적화 프로젝트입니다.
베타 테스트에서는 대부분의 테스터분들이 핸드폰을 통해 서비스를 접속했어요.
특히 아이폰이 월등하게 많았죠.

 

그런데 위에서 보셨듯이 웹 푸시 알림은 아이폰은 물론 Safari를 지원하지 않아요.
그리고 만약 앱도 함께 베타 테스트를 진행했다면, 웹 사용은 현저히 줄어들었을 것입니다.

 

그래서 위와 같은 문제로 인해 시간을 소비하는 것보단 깔끔하게 웹 푸시 알림을 포기하는 쪽으로 의견이 모아졌습니다 !


지금까지 웹 푸시 알림에 대한 이야기였어요.

 

실제 서비스에서는 볼 수 없는 기능이지만, '이런 고민도 했었다.'라는 것을 보여드리고 싶어서 적게 되었어요 : )

TellingUs에서는 어떻게 하면 더 좋은 서비스를 제공할 수 있을지를 계속 생각하고 있으니까 곧 출시될 tellingme 서비스 많이 기대해 주세요 🫶

 

++ 현재는 출시가 되었어요 !

 

[ 웹 ]

 

텔링미 | 진정한 나에 가까워지는 저널링 다이어리

하루 한 번 나를 깨닫는 시간! 오직 나를 위한 질문이 배달되는 저널링 다이어리 ‘텔링미’와 함께하세요. 부담 없이 나를 찾아가는 질문에 솔직하게 답변하며 나만의 일기장을 만들어봐요.

tellingme.co.kr

[ iOS 앱 ]

 

‎텔링미 : 나를 깨닫는 시간

‎나의 진짜 꿈, 내가 정말 바랐던 것들, 온전한 가치관… 나를 잊어가진 않았나요? 우리에게 필요한 것은 오로지 나만을 위한 공간, 그리고 스스로를 온전히 탐색하는 시간입니다. [나를 위한

apps.apple.com