[flutter] Firebase 백그라운드 일 때 initializeApp

popolarburr·2023년 10월 24일
0
post-thumbnail

Future<void> main() async {

...
await FCMService().init();

FirebaseMessaging.onBackgroundMessage(
      _firebaseMessagingBackgroundHandler); //TOP-Level
     
....
}


Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);

  debugPrint('A background message just showed up :  ${message.messageId}');
  
}
...

이렇게 작성된 코드가 있는데, 이에 대해서 설명해줘. 무엇을 하기 위한 코드고 어떻게 동작하고 어떠한 원리를 갖고있는지 궁금했다.


나의 이해

내가 이해한것은 우선은 이러하다.

  • 우선 플러터의 진입점인 main()함수에서 await FCMService().init();를 통해 커스텀해놓은 FCM 앱을 초기화하고 설정한다.
    ( FCMService.init()안에는 당연하게도 Firebase.initializeApp코드가 존재. )

앱이 실행하면서 실행한 디바이스 및 기기에 대한 토큰값을 받아오고, FCM에 대한 초기화를 진행하는 코드라고 생각했다

  • 그러다 백그라운드(앱이 실행중이지만, 화면에 떠있지 않는 상태) 일 때 _firebaseMessagingBackgroundHandler를 실행한다

하지만 여기서부터 궁금했던 것이 생긴다.


궁금점

이미 초기화를 했는데, 왜 다시 백그라운드 일 떄 초기화할까?

에 대한 궁금점이 생겨서 좀 찾아봤다.

결론


Firebase 초기화를 백그라운드에서 다시 실행시키는 이유는 Firebase 앱을 백그라운드 상태에서도 제대로 동작하도록 보장하기 위한 조치입니다. Firebase는 앱이 시작될 때 초기화되어야 하지만, 앱이 백그라운드에서 푸시 알림을 수신하거나 백그라운드 작업을 수행할 때 Firebase 기능을 계속 사용해야 합니다. Firebase는 이러한 상황에서도 제대로 동작하려면 Firebase 앱을 백그라운드에서 다시 초기화해야 합니다.

일반적으로 앱이 포그라운드(화면이 표시되는 상태)일 때 Firebase가 초기화됩니다. 이때 Firebase는 사용자와 상호작용하며 푸시 알림을 표시하거나 데이터를 처리하는 등의 작업을 수행합니다. 그러나 앱이 백그라운드로 전환되면 일부 플랫폼에서 Firebase 초기화가 중지될 수 있습니다. 이때 백그라운드에서 Firebase 기능을 계속 사용하려면 Firebase를 백그라운드에서 다시 초기화해야 합니다.

따라서 await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); 코드는 백그라운드에서 Firebase를 다시 초기화하여 Firebase 기능을 계속 사용할 수 있도록 합니다. 이렇게 하면 백그라운드에서 푸시 알림을 정상적으로 수신하고 처리할 수 있으며, 필요한 경우 데이터 처리 및 작업을 수행할 수 있습니다.

즉, Firebase 초기화는 앱의 현재 상태에 따라 Firebase 서비스를 사용할 수 있도록 유지하는 데 필요한 조치입니다.


[10/26 추가]

백그라운드에서 메세지를 처리하는 프로세스는 네이티브(Android 및 Apple) 플랫폼과 웹 기반 플랫폼에서 다릅니다.

나는 보통 푸시 알람을 모바일 네이티브(Android 및 Apple)에서 사용하려고 하기 때문에, 웹은 배제하기로 한다.

이 Android 및 apple 플랫폼에서 사용하려면 , onBackgroundMessage 핸들러를 등록하여 백그라운드 메시지를 처리한다.

여기서 주의사항으로는

  1. 익명 함수가 아니어야 한다.
  2. 최상위 수준 함수여야 한다.
  3. Flutter 버전 3.3.0 이상을 사용하는 경우 메시지 핸들러는 함수 선언 바로 위에 `@pragma('vm:entry-point')로 주석을 달아야 한다(그렇지 않으면 출시 모드의 경우 트리 쉐이킹 중에 삭제 가능성이 있음)
('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  // If you're going to use other Firebase services in the background, such as Firestore,
  // make sure you call `initializeApp` before using other Firebase services.
  await Firebase.initializeApp();

  print("Handling a background message: ${message.messageId}");
}

void main() {
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());
}

왜 최상위 수준에서 함수를 작성해야하고 익명함수가 아니어야 할까?

❗ 핸들러는애플리케이션 컨텍스트 외부에서 독립적으로 실행되므로 애플리케이션 상태를 업데이트 하거나 UI에영향을 주는 로직을 실행할 수 없습니다. 그러나 HTTP요청과 같은 로직을 수행하고 IO작업(로컬스토리지업데이트)를 수행하며 다른 플러그인과 통신할 수 있다.

그렇기에 가능한 한 빨리 로직을 완료하는 것이 좋게, 집약적이로 오래 실행되는 태스크를 실행하면 기기 성능에 영향을 가기 때문에 30초가 넘게되면 자동으로 프로세스를 종료하는등, 애플리케이션의 Top-Level, 상위수준에서 로직이 이루어져야 한다.








[Firebase Docs] https://firebase.google.com/docs/cloud-messaging/flutter/receive?hl=ko

profile
차곡차곡

0개의 댓글