Push 알림 — FCM과 로컬 알림 구현
푸시 알림은 사용자 리텐션의 핵심이며, 포그라운드/백그라운드/종료 상태를 구분해서 처리해야 합니다.
모바일 앱에서 알림은 가장 중요한 기능 중 하나입니다. FCM(Firebase Cloud Messaging)으로 원격 푸시를 보내고, Notifee로 로컬 알림을 표시하는 조합이 일반적입니다.
설치
# FCM
npm install @react-native-firebase/app @react-native-firebase/messaging
# 로컬 알림 (Notifee)
npm install @notifee/react-native
cd ios && pod install
권한 요청
import messaging from '@react-native-firebase/messaging';
import { Platform, PermissionsAndroid } from 'react-native';
async function requestNotificationPermission() {
if (Platform.OS === 'ios') {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
return enabled;
}
if (Platform.OS === 'android' && Platform.Version >= 33) {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
);
return granted === PermissionsAndroid.RESULTS.GRANTED;
}
return true;
}
FCM 토큰 관리
async function setupFCM() {
// 권한 요청
const hasPermission = await requestNotificationPermission();
if (!hasPermission) return;
// FCM 토큰 가져오기
const token = await messaging().getToken();
console.log('FCM Token:', token);
// 서버에 토큰 저장
await saveTokenToServer(token);
// 토큰 갱신 감지
messaging().onTokenRefresh(async (newToken) => {
await saveTokenToServer(newToken);
});
}
알림 수신 처리
import messaging from '@react-native-firebase/messaging';
import notifee from '@notifee/react-native';
// 1. 포그라운드 알림 처리
function useForegroundNotification() {
useEffect(() => {
const unsubscribe = messaging().onMessage(async (remoteMessage) => {
// 포그라운드에서는 알림이 자동으로 표시되지 않음
// Notifee로 직접 표시
const channelId = await notifee.createChannel({
id: 'default',
name: '기본 알림',
importance: 4, // HIGH
});
await notifee.displayNotification({
title: remoteMessage.notification?.title,
body: remoteMessage.notification?.body,
android: { channelId },
data: remoteMessage.data,
});
});
return unsubscribe;
}, []);
}
// 2. 백그라운드 알림 처리 (index.js에 등록)
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('백그라운드 메시지:', remoteMessage);
});
// 3. 알림 탭 처리
function useNotificationTap() {
useEffect(() => {
// 앱이 백그라운드일 때 알림을 탭한 경우
messaging().onNotificationOpenedApp((remoteMessage) => {
handleNotificationNavigation(remoteMessage.data);
});
// 앱이 종료된 상태에서 알림을 탭한 경우
messaging().getInitialNotification().then((remoteMessage) => {
if (remoteMessage) {
handleNotificationNavigation(remoteMessage.data);
}
});
}, []);
}
function handleNotificationNavigation(data: any) {
// 알림 데이터에 따라 화면 이동
if (data?.type === 'post') {
navigation.navigate('PostDetail', { id: data.postId });
} else if (data?.type === 'chat') {
navigation.navigate('ChatRoom', { roomId: data.roomId });
}
}
로컬 알림
import notifee, { TriggerType, TimestampTrigger } from '@notifee/react-native';
// 즉시 알림 표시
async function showLocalNotification(title: string, body: string) {
const channelId = await notifee.createChannel({
id: 'default',
name: '기본 알림',
});
await notifee.displayNotification({
title,
body,
android: {
channelId,
smallIcon: 'ic_notification',
pressAction: { id: 'default' },
},
ios: {
sound: 'default',
},
});
}
// 예약 알림
async function scheduleNotification(title: string, body: string, date: Date) {
const channelId = await notifee.createChannel({
id: 'reminders',
name: '리마인더',
});
const trigger: TimestampTrigger = {
type: TriggerType.TIMESTAMP,
timestamp: date.getTime(),
};
await notifee.createTriggerNotification(
{
title,
body,
android: { channelId },
},
trigger
);
}
알림 상태 정리
앱 상태별 알림 동작:
┌─────────────────────────────────────────────┐
│ 포그라운드 (앱 사용 중) │
│ → onMessage() 호출 │
│ → 알림 자동 표시 안됨 │
│ → Notifee로 수동 표시 필요 │
├─────────────────────────────────────────────┤
│ 백그라운드 (앱이 뒤에 있음) │
│ → 알림 자동 표시 │
│ → setBackgroundMessageHandler() 호출 │
│ → 탭 시 onNotificationOpenedApp() 호출 │
├─────────────────────────────────────────────┤
│ 종료 상태 (앱이 완전히 꺼짐) │
│ → 알림 자동 표시 │
│ → 탭으로 앱 실행 시 getInitialNotification()│
└─────────────────────────────────────────────┘
정리
- 푸시 알림은 포그라운드, 백그라운드, 종료 상태 를 각각 다르게 처리해야 합니다
- 포그라운드에서는 FCM이 알림을 자동 표시하지 않으므로 Notifee로 직접 표시 합니다
- FCM 토큰은 서버에 저장 하고, 갱신 이벤트 를 구독하세요
- 알림 탭 시 딥링크와 연동 하여 적절한 화면으로 이동시키세요
- Android 13+에서는 POST_NOTIFICATIONS 권한 을 명시적으로 요청해야 합니다
댓글 로딩 중...