들어가기 전
- 먼저
.env
파일에 VAPID PUBLIC KEY
가 필요합니다.
VAPID_PUBLIC_KEY='BAQYVETELyf6ErKyL6sd-K3o-09bcJE_oPGQcualSXO4i0y0sMK9flEGljqDkwj-0zA25ckb56IPIAd969YFTfk'
순서도
graph TD
A[사용자가 로그인] --> B[구독 버튼 클릭]
B --> C[Notification과 serviceWorker 지원 여부 확인]
C --> D{알림 권한 요청}
D -->|허용| E[서비스 워커 등록 가져오기]
E --> F{FCM 푸시 알림 구독 VAPID_PUBLIC_KEY 사용}
F -->|허용| G[서버로 구독 정보 전송]
G --> H['푸시 알림 구독 완료!' 메시지 표시]
D -->|거부| I['알림 권한 거부됨.' 메시지 표시]
F -->|거부| J[구독 실패 처리]
요약 예시 코드
구독시
// 버튼을 이용한 구독 서비스일때
subscribeBtn.addEventListener('click', async () => {
if ('Notification' in window && navigator.serviceWorker) {
try {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlB64ToUint8Array(
VAPID_PUBLIC_KEY
),
});
const response = await fetch(
'<https://juchum.info/api/push/subscribe>',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription),
credentials: 'include',
},
);
if (response.ok) {
subscribeMessage.textContent =
'Subscribed to push notifications!';
}
} else {
subscribeMessage.textContent = 'Notification permission denied.';
}
} catch (error) {
subscribeMessage.textContent = 'Subscription failed.';
}
}
});
// 직렬화 코드
const urlB64ToUint8Array = (base64String) => {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
.replace(/-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0)));
}
service worker
//service-worker.js
self.addEventListener('push', (event) => {
const data = event.data
? event.data.json()
: { title: '알림', body: '내용 없음' };
self.registration.showNotification(data.title, {
body: data.body,
icon: 'icon.png', // 기본 아이콘 설정
});
});
상세 설명
api/push/subscribe - 파라미터
{
"endpoint": "string", //현재 디바이스의 FCM 서비스 엔드포인트
"keys": {
"p256dh": "string", // base64로 인코딩된 푸시 메시지 암호화용 키
"auth": "string" // base64로 인코딩된 인증키
}
}
파라미터 생성 방법
//FCM 서비스 구독을 위한 클라이언트 사이드 코드
//이 subscribe를 그대로 /api/push/subscribe에 보내면 됩니다.
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlB64ToUint8Array(
VAPID_PUBLIC_KEY,
),
});
// 직렬화 코드
const urlB64ToUint8Array = (base64String) => {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
.replace(/-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0)));
}