76. FCM 푸시 알림 서비스 기능 분석
푸시 알림 서비스 필요 기능
1. 푸시 알림 구독
- Notification : 푸시 알림 수신 승인
- Service Worker :
- 푸시 알림을 받을 구독자 정보 생성
- 푸시 알림 구독자 정보를 서버(Backend)에 전송
- 푸시 알림 수신 및 표시
2. 푸시 알림 보내기
- Backend에 푸시 알림 요청
3. Backend
- Client의 Service Worker로부터 푸시 알림 구독자 정보를 받아 DB에 저장
- 푸시 알림 요청을 받으면 Backend에서 FCM이 구독자에게 푸시 알림 보냄
ChatGPT가 시키는 대로 했습니다.
1. service-worker.js
2. 서비스 워크 등록
프로젝트 만들기를 통해 기본적으로 설치된 registerServiceWorker.js 사용
3. src/notifications.js
4. src/views/SubscribeView.vue
5. 실행
- Notification permission granted.
푸시 알림 수신을 승인하였습니다. - User is subscribed: PushSubscription {endpoint: . . . }
푸시 알림 구독을 위한 구독자 정보를 생성하였습니다. - Failed to send subscription to server:
구독자 정보를 서버로 전송하는 것을 실패하였습니다.
6. Source Code
sw.js - Service Worker
// sw.js - Service Worker
self.addEventListener('push', function(event) {
const data = event.data.json();
console.log('[Service Worker] Push Received.', data);
const title = data.title || 'Notification Title';
const options = {
body: data.body || 'Notification Body',
icon: "/img/push-noti-icon.png",
badge: "/img/push-badge-icon.png",
image: "/img/push-news.jpg",
};
event.waitUntil(
self.registration.showNotification(title, options)
);
});
self.addEventListener('notificationclick', function(event) {
console.log('[Service Worker] Notification click Received.');
event.notification.close();
event.waitUntil(
clients.openWindow('https://velog.io/@inetsos/posts')
);
});
src/notifications.js
// src/notifications.js
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
export async function subscribeUserToPush() {
try {
const registration = await navigator.serviceWorker.ready;
const permission = await Notification.requestPermission();
if (permission === 'granted') {
console.log('Notification permission granted.');
const vapidPublicKey = "'YOUR_VAPID_PUBLIC_KEY'";
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(vapidPublicKey)
});
console.log('User is subscribed:', subscription);
// Send subscription to server to store it
await sendSubscriptionToServer(subscription);
return subscription;
} else {
console.warn('Notification permission not granted.');
}
} catch (error) {
console.error('Failed to subscribe the user: ', error);
}
}
async function sendSubscriptionToServer(subscription) {
try {
const response = await fetch('/api/subscribe', {
method: 'POST',
body: JSON.stringify(subscription),
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Failed to send subscription to server.');
}
console.log('Subscription sent to server successfully.');
} catch (error) {
console.error('Failed to send subscription to server:', error);
}
}
src/views/SubscribeView.vue
Copy<!-- src/views/SubscribeView.vue -->
<template>
<v-container>
<v-card>
<v-card-title>
Push Notifications
</v-card-title>
<v-btn color="primary" @click="subscribeToNotifications" dark>
Subscribe to Notifications
</v-btn>
</v-card>
</v-container>
</template>
<script>
import { subscribeUserToPush } from '@/notifications';
export default {
name: 'NotificationButton',
methods: {
async subscribeToNotifications() {
const subscription = await subscribeUserToPush();
if (subscription) {
console.log('User subscribed successfully:', subscription);
}
}
}
};
</script>
'PWA' 카테고리의 다른 글
ChatGPT와 FCM 개발 - Serverless (0) | 2024.09.20 |
---|---|
ChatGPT와 FCM 개발 - 구독자 정보 저장 (2) | 2024.09.19 |
ChatGPT와 FCM 개발 - Subscription (1) | 2024.09.17 |
ChatGPT와 FCM 개발 - Notification (0) | 2024.09.17 |
ChatGPT와 FCM 개발 - Service Worker (0) | 2024.09.15 |