- 아래와 같이 App.tsx 파일이 실행되었을때, 앱에 있는 상태(foreground) 상태에서 메시지를 받기 위해 messaging().onMessage() 메서드를 사용하였고, 앱을 벗어난 상태(background) 상태에서 메시지를 받기 위해 messaging().setBackgroundMessageHandler()를 메서드를 사용하여 구성하였습니다.
상태 별 확인
동작상태
foreground 상태 푸시메시지 수신
정상 동작
inactive 상태 푸시메시지 수신
정상 동작
background 상태 푸시메시지 수신
비 정상 동작 : 2개 메시지 전송
import messaging, { FirebaseMessagingTypes } from'@react-native-firebase/messaging';
import { useEffect, useRef } from'react';
const App = () => {
const messageListener = useRef<(() =>void) | null>(null);
/**
* FCM 메시지 리스너 등록 관련 처리
*/
useEffect(() => {
// foreground의 리스너가 존재하는지 여부를 체크하고 존재하면 제거합니다.if (messageListener.current) {
messageListener.current();
}
console.log("[+] FCM 메시지 리스너가 등록되었습니다.!")
// forground 상태일때, FCM 메시지 수신
messageListener.current = messaging().onMessage(async remoteMessage => await onMessageReceived(remoteMessage));
messaging().setBackgroundMessageHandler(async remoteMessage => await onMessageReceived(remoteMessage));
return() => {
console.log("[-] FCM 메시지 리스너가 사라졌습니다!")
messageListener.current?.(); // 옵셔널 체이닝으로 안전하게 실행
}
}, []);
/**
* FCM 메시지 수신 리스너를 등록합니다. (Foreground, Background 상태)
* @param {FirebaseMessagingTypes.RemoteMessage}message
* @return {Promise<void>}
*/const onMessageReceived = async (message: FirebaseMessagingTypes.RemoteMessage): Promise<void> => {
const { title, body } = message.notification!;
if (!title || !body) {
console.warn('알림에 제목 또는 내용이 없습니다.');
return;
}
console.log(`[+] 알림 수신: ${title} - ${body}`);
// 중복 알림 방지를 위한 고유 ID 생성const notificationId = message.messageId || Date.now().toString();
// 기존 알림 취소await notifee.cancelNotification(notificationId);
// 채널 생성const channelIdConfig = await notifee.createChannel({
id: `important`,
name: 'Important Notifications',
importance: AndroidImportance.HIGH, // 채널 생성시 중요도를 설정해줍니다.
});
console.log(`notificationId :: `, notificationId);
// 디바이스에 알림을 표시합니다.await notifee.displayNotification({
id: notificationId,
title: title,
body,
android: {
channelId: channelIdConfig,
smallIcon: 'ic_launcher',
importance: AndroidImportance.HIGH,
visibility: AndroidVisibility.PUBLIC,
},
});
}
}
💡 onMessage 메서드 확인 - FCM 페이로드를 수신할 때마다 콜백 리스너가 RemoteMessage와 함께 호출됩니다. - 해당 메서드는 앱이 활성화 상태(forground) 일 때만 호출이 됩니다.메시지 수신 중단을 위한 unsubscribe 함수를 반환합니다.
/**
* When any FCM payload is received, the listener callback is called with a `RemoteMessage`.
*
* Returns an unsubscribe function to stop listening for new messages.
*
* #### Example
*
* ```js
* const unsubscribe = firebase.messaging().onMessage(async (remoteMessage) => {
* console.log('FCM Message Data:', remoteMessage.data);
*
* // Update a users messages list using AsyncStorage
* const currentMessages = await AsyncStorage.getItem('messages');
* const messageArray = JSON.parse(currentMessages);
* messageArray.push(remoteMessage.data);
* await AsyncStorage.setItem('messages', JSON.stringify(messageArray));
* });
*
* // Unsubscribe from further message events
* unsubscribe();
* ```
*
* > This subscriber method is only called when the app is active (in the foreground).
*
* @param listener Called with a `RemoteMessage` when a new FCM payload is received from the server.
*/
onMessage(listener: (message: RemoteMessage) =>any): () =>void;
1.2. setBackgroundMessageHandler 메서드 확인
💡 setBackgroundMessageHandler 메서드 확인
- 앱이 백그라운드 상태이거나 종료된 상태일 때 호출되는 메시지 핸들러 함수를 설정하는 메서드입니다. - Android에서는 헤드리스 태스크(headless task)가 생성되어 React Native 환경에 접근할 수 있습니다. 이를 통해 로컬 스토리지 업데이트나 네트워크 요청과 같은 작업을 수행할 수 있습니다. - 이 메서드는 반드시 애플리케이션 라이프사이클 외부에서 호출되어야 합니다. 예를 들어, 애플리케이션 코드의 진입점에서 AppRegistry.registerComponent() 메서드 호출과 함께 사용해야 합니다.
/**
* Set a message handler function which is called when the app is in the background
* or terminated. In Android, a headless task is created, allowing you to access the React Native environment
* to perform tasks such as updating local storage, or sending a network request.
*
* This method must be called **outside** of your application lifecycle, e.g. alongside your
* `AppRegistry.registerComponent()` method call at the the entry point of your application code.
*
*
* #### Example
*
* ```js
* firebase.messaging().setBackgroundMessageHandler(async (remoteMessage) => {
* // Update a users messages list using AsyncStorage
* const currentMessages = await AsyncStorage.getItem('messages');
* const messageArray = JSON.parse(currentMessages);
* messageArray.push(remoteMessage.data);
* await AsyncStorage.setItem('messages', JSON.stringify(messageArray));
* });
* ```
*
*/
setBackgroundMessageHandler(handler: (message: RemoteMessage) =>Promise<any>): void;
- 결론적으로 setBackgroundMessageHandler() 메서드의 경우는 애플리케이션 코드의 진입점에서 AppRegistry.registerComponent() 메서드 호출과 함께 사용해야 합니다. - React Native 앱의 메인 컴포넌트나 useEffect 등 React 컴포넌트 내부가 아닌, 앱의 시작점(entry point)인 index.js 또는 App.js 파일의 최상위 레벨에서 설정해야 합니다. - 이렇게 하는 이유는 앱이 백그라운드나 종료 상태일 때도 메시지를 안정적으로 처리하기 위해서입니다. - React 컴포넌트 내부에서 설정하면 컴포넌트가 언마운트될 때 핸들러도 함께 제거될 수 있기 때문입니다.