728x90
반응형
SMALL
목차
1. 배경
2. 개발 과정
3. 결과
1. 배경
사용자들에게 REracle 서비스의 업데이트 및 공지사항을 실시간으로 받아볼 수 있는 알림 기능을 제공하는 것이 필요했었습니다. 그래서 PWA의 기능인 PUSH 알림 기능을 구현하게된 내용을 소개해드리겠습니다.
제가 만든 REracle 서비스에서 push 알림을 코드를 참고할 수 있습니다.
2. 개발 과정
- PWA 구현
- service-worker.js 파일을 생성하여 PWA의 기본 기능을 구현하여 오프라인 지원, 앱 설치 기능 등 PWA의 핵심 기능을 추가했습니다.
- 푸시 알림 구현
- firebase-messaging-sw.js 파일을 생성하여 백그라운드 메시지 처리를 구현하였고, NotificationComponent를 만들어 포그라운드 알림 수신 및 권한 요청 로직을 구현하여 웹, 앱에 처음 들어갔을 때 Notification API 알림 수신 및 권한 요청 메시지가 요청되도록 했습니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="src/assets/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Recycle</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap"
rel="stylesheet"
/>
<link
rel="apple-touch-icon"
href="/apple-touch-icon-180x180.png"
sizes="180x180"
/>
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF" />
<meta name="theme-color" content="#ffffff" />
</head>
<body>
<div id="root"></div>
<script src="/firebase-messaging-sw.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
2.1 Service Worker 등록
// /public/service-worker.js
// 서비스 워커 등록 코드 예시
function registerServiceWorker() {
if (typeof window !== "undefined") {
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/firebase-messaging-sw.js")
.then((registration) => {
console.log("Service Worker Registered");
console.dir(registration);
});
}
}
}
registerServiceWorker();
- PWA로 웹/앱을 구현했다고 가정한 후 firebase-messaging-sw.js 파일을 생성하여 Firebase Cloud Messaging을 위한 서비스 워커를 등록해줍니다.
- **typeof window !== "undefined"**로 브라우저 환경인지 확인합니다.
- **"serviceWorker" in navigator**로 브라우저가 서비스 워커를 지원하는지 확인합니다.
- **navigator.serviceWorker.register()**를 사용하여 /firebase-messaging-sw.js 파일을 서비스 워커로 등록합니다.
- 등록이 성공하면 콘솔에 메시지를 출력하고 등록 객체의 상세 정보를 표시합니다.
2.2 Firebase 서비스 워커 구현
// /public/firebase-messaging-sw.js
importScripts(
"<https://www.gstatic.com/firebasejs/9.6.1/firebase-app-compat.js>"
);
importScripts(
"<https://www.gstatic.com/firebasejs/9.6.1/firebase-messaging-compat.js>"
);
const firebaseConfig = {
apiKey: "",
authDomain: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: "",
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.onBackgroundMessage((payload) => {
const title = payload.notification.title + " (onBackgroundMessage)";
const notificationOptions = {
body: payload.notification.body,
icon: "/REracle.svg",
};
self.registration.showNotification(title, notificationOptions);
});
self.addEventListener("notificationclick", function (event) {
event.notification.close();
const redirectUrl = event?.notification?.data?.redirectUrl;
event.waitUntil(
clients
.matchAll({
type: "window",
})
.then(function (clientList) {
for (const client of clientList) {
if (client.url === redirectUrl && "focus" in client) {
return client.focus();
}
}
if (clients.openWindow) {
return clients.openWindow(redirectUrl);
}
})
);
});
- 이 코드에서는 Firebase 앱과 메시징 서비스를 초기화합니다. **importScripts**를 사용하여 필요한 Firebase 스크립트를 가져오고, 설정 객체로 Firebase 앱을 초기화한 후 메시징 인스턴스를 생성합니다.
2.3 Firebase 설정
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import { getStorage } from "firebase/storage";
const firebaseConfig = {
// Firebase 설정 정보
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const storage = getStorage(app);
export { app, auth, db, storage };
2.4 Notification Component 작성
// /components/NotificationComponent
import { useEffect } from "react";
import { getMessaging, getToken, onMessage } from "firebase/messaging";
import { app, auth, db } from "@/firebase";
import { doc, setDoc } from "firebase/firestore";
const NotificationWebApi = () => {
useEffect(() => {
const messaging = getMessaging(app);
/**
* @description 알림 권한 요청
* @description Firestore에 유저의 FCM Token 저장 코드 추가
*/
const requestPermission = async () => {
const permission = await Notification.requestPermission();
if (permission === "granted") {
const token = await getToken(messaging, {
vapidKey:
".....", // 생성된 VAPID 키 사용
});
console.log("FCM Token:", token);
const user = auth.currentUser;
if (user) {
const userDoc = doc(db, "users", user.uid);
await setDoc(userDoc, { fcmToken: token }, { merge: true });
}
}
};
/**
* @description 포그라운드 알림 수신
*/
onMessage(messaging, (payload) => {
console.log("Message received. ", payload);
if (
payload.notification &&
payload.notification.title &&
payload.notification.body
) {
new Notification(payload.notification.title, {
body: payload.notification.body,
icon: "/icons/icon-96.png",
});
}
});
requestPermission();
}, []);
return <div></div>;
};
export default NotificationWebApi;
FCM 토큰 관리
- requestPermission 함수에서는 먼저 사용자로부터 알림 권한을 요청합니다. 권한이 부여되면, FCM 토큰을 생성합니다.
- 회원가입된 해당 사용자의 Firestore 에 FCM 토큰을 저장합니다.
포그라운드 메시지 처리
- onMessage 리스너를 설정하여 앱이 활성 상태일 때 수신되는 메시지 처리합니다.
- 메시지에 알림 정보(제목과 내용)가 포함되어 있다면, 브라우저의 Notification API를 사용하여 알림을 표시합니다.
import { useEffect } from "react";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import "@shoelace-style/shoelace/dist/themes/light.css";
// import Loading from "./pages/Loading";
import { routes } from "./router/routes";
import { saveWasteCategories } from "./lib/utils/firestoreService";
import NotificationComponent from "./components/NotificationComponent";
const router = createBrowserRouter(routes);
const App = () => {
useEffect(() => {
saveWasteCategories();
}, []);
return (
<>
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex flex-col w-full max-w-[440px] h-full max-h-[920px] bg-white">
<RouterProvider router={router} />
<NotificationComponent />
</div>
</>
);
};
export default App;
- App 컴포넌트에 **NotificationComponent**를 추가함으로써, 푸시 알림 기능을 전체 애플리케이션에 걸쳐 사용할 수 있게 됩니다.
3. 결과
Firebase Cloud Messaging 홈페이지에 들어가서 메시지를 보내면 PWA로 푸시 알림 시스템을 통해 사용자들은 REracle 서비스 주요 업데이트 및 공지사항을 실시간으로 받아볼 수 있습니다.
밑의 사진은 제가 test메시지를 푸시 알림으로 웹과 앱에 알림을 보낸 것을 확인할 수 있습니다.
참고
728x90
반응형
LIST
'FE' 카테고리의 다른 글
뷰포트 단위에서 rem, px, %, vh로 리팩토링한 이유 (0) | 2024.12.29 |
---|---|
REracle: 비용 효율적인 서비스 운영 (0) | 2024.12.29 |
Styled-components에서 Tailwind로 전환한 이유 (1) | 2024.11.04 |
[최적화] suspense, lazy로 초기로딩 개선 (1) | 2024.07.23 |
단위, 통합 테스트와 테스트 도구: 이론 (0) | 2024.07.13 |