웹 푸시 구현 예제
npm install @nativify/notifications firebase
// hooks/useNotification.js
import { useState, useEffect, useCallback } from 'react';
import { getNotificationService } from '@nativify/notifications';
export function useNotification() {
const [service, setService] = useState(null);
const [notifications, setNotifications] = useState([]);
const [token, setToken] = useState(null);
const [permission, setPermission] = useState('default');
// Firebase 설정
const initFirebase = useCallback(() => {
window.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,
vapidKey: process.env.REACT_APP_FIREBASE_VAPID_KEY
};
}, []);
// 메시지 수신 처리
const handleMessage = useCallback((message) => {
setNotifications(prev => [{
id: Date.now(),
title: message.notification?.title || '알림',
body: message.notification?.body || '',
timestamp: new Date()
}, ...prev]);
}, []);
// 서비스 초기화
useEffect(() => {
const initialize = async () => {
try {
initFirebase();
const notificationService = getNotificationService();
await notificationService.initialize();
// 메시지 리스너 등록
notificationService.onMessageReceived(handleMessage);
setService(notificationService);
} catch (error) {
console.error('초기화 실패:', error);
}
};
initialize();
return () => {
if (service) {
service.onMessageReceived(null);
}
};
}, [initFirebase, handleMessage]);
// 권한 요청
const requestPermission = useCallback(async () => {
if (!service) return;
try {
const perm = await service.requestPermission();
setPermission(perm);
if (perm === 'granted') {
const fcmToken = await service.getToken();
setToken(fcmToken);
console.log('FCM Token:', fcmToken);
// 서버에 토큰 등록
await service.registerUserToken(
'delivery_app_001',
'user123',
'https://your-server.com/api/notifications'
);
}
} catch (error) {
console.error('권한 요청 실패:', error);
}
}, [service]);
return { notifications, token, permission, requestPermission };
}
// App.jsx
import { useNotification } from './hooks/useNotification';
import './App.css';
function App() {
const { notifications, token, permission, requestPermission } = useNotification();
return (
<div className="app">
<h1>웹 푸시 알림 데모</h1>
{/* 권한 요청 버튼 */}
{permission !== 'granted' && (
<button onClick={requestPermission} className="btn-primary">
알림 권한 요청
</button>
)}
{/* FCM 토큰 표시 */}
{token && (
<div className="token-display">
<strong>FCM Token:</strong>
<code>{token}</code>
</div>
)}
{/* 알림 목록 */}
<div className="notifications">
<h2>받은 알림</h2>
{notifications.length === 0 ? (
<p className="empty">받은 알림이 없습니다.</p>
) : (
notifications.map(notif => (
<div key={notif.id} className="notification-item">
<h3>{notif.title}</h3>
<p>{notif.body}</p>
<small>{notif.timestamp.toLocaleString()}</small>
</div>
))
)}
</div>
</div>
);
}
export default App;
.notification-item {
background: #f7fafc;
border-left: 4px solid #61dafb;
padding: 15px;
margin: 10px 0;
border-radius: 8px;
}
.token-display {
background: #ebf8ff;
padding: 15px;
border-radius: 8px;
margin: 20px 0;
}
.btn-primary {
background: #61dafb;
color: #282c34;
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
}
.btn-primary:hover {
background: #21a1c4;
}
.env 파일 생성:
REACT_APP_FIREBASE_API_KEY=your_api_key
REACT_APP_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
REACT_APP_FIREBASE_PROJECT_ID=your_project_id
REACT_APP_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
REACT_APP_FIREBASE_APP_ID=your_app_id
REACT_APP_FIREBASE_VAPID_KEY=your_vapid_key
.env 파일에 Firebase 설정 입력public/firebase-messaging-sw.js 생성npm install - 패키지 설치npm start - 개발 서버 실행