Skip to content

[🐛] Duplicate FCM messages delivered after app process restart on Android #8670

@hongdonghyun

Description

@hongdonghyun

Issue

I'm experiencing an issue where FCM messages get duplicated after my Android app process gets killed and restarted. When using data-only FCM messages, I'm seeing all previously processed messages getting re-delivered along with new ones.

Expected: Each FCM message should only be delivered once to setBackgroundMessageHandler.

What's happening: After the app process restarts, I get all previous messages again plus the new message that triggered the restart. Even though my handler returns Promise.resolve() properly.

How to reproduce:

  1. Set up setBackgroundMessageHandler with data-only FCM messages
  2. Receive a few messages normally (this works fine)
  3. Kill the app process (either manually or let Android do it)
  4. Send another FCM message
  5. Watch all the old messages come back along with the new one

What I can see in the logs:

  • Same message IDs getting delivered again
  • All messages hit my handler within the same millisecond
  • Takes about 100ms for ExpoModulesCore to initialize after process start
  • This only happens when the process actually dies, not just backgrounding
// Basic setup in index.js
import messaging from '@react-native-firebase/messaging';

messaging().setBackgroundMessageHandler(async remoteMessage => {
    console.log('📱 Background message received:', remoteMessage?.messageId);
    
    if (!remoteMessage.notification && remoteMessage.data) {
        try {
            // Handle data-only message with Notifee
            console.log('✅ Message processed successfully');
            return Promise.resolve();
        } catch (error) {
            console.error('❌ Error handling message:', error);
            return Promise.reject(error);
        }
    }
    return Promise.resolve();
});

Project Files

Javascript

Click To Expand

package.json:

{
  "dependencies": {
    "@react-native-firebase/app": "22.2.0",
    "@react-native-firebase/messaging": "22.2.0",
    "@notifee/react-native": "9.1.8",
    "expo": "~53.0.0",
    "react-native": "0.77.x"
  }
}

firebase.json for react-native-firebase v6:

# Using v22.2.0

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# Standard Expo managed workflow setup

AppDelegate.m:

// Standard Expo managed workflow setup


Android

Click To Expand

Have you converted to AndroidX?

  • my application is an AndroidX application?
  • I am using android/gradle.properties jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

// Standard Expo managed workflow setup

android/app/build.gradle:

// Standard Expo managed workflow setup  

android/settings.gradle:

// Standard Expo managed workflow setup

MainApplication.java:

// Standard Expo managed workflow setup

AndroidManifest.xml:

<!-- Standard Expo managed workflow setup with FCM permissions -->


Environment

Click To Expand

react-native info output:

React Native Environment Info:
  System:
    OS: macOS 14.x
    CPU: (x) arm64
  Binaries:
    Node: 18.x.x
    Yarn: 1.x.x
    npm: 9.x.x
    Watchman: 2023.x.x
  SDKs:
    iOS SDK:
      Platforms: iOS 17.x, DriverKit 23.x, macOS 14.x, tvOS 17.x, watchOS 10.x
    Android SDK:
      API Levels: 28, 29, 30, 31, 32, 33, 34
      Build Tools: 30.0.3, 31.0.0, 33.0.0, 34.0.0
      System Images: android-31 | Google APIs ARM 64 v8a, android-34 | Google APIs ARM 64 v8a
  IDEs:
    Android Studio: 2024.x.x
    Xcode: 15.x.x
  Languages:
    Java: 17.x.x
    Ruby: 2.x.x
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • 22.2.0
  • Firebase module(s) you're using that has the issue:
    • @react-native-firebase/messaging
  • Are you using TypeScript?
    • Y & 5.x


Detailed log evidence from adb logcat:

# Process 14848 - Normal message processing over time
948|19:39:37.318 14848 14885 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859176456941%c8c2fb28f9fd7ecd'
951|19:39:47.246 14848 14885 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859186737605%c8c2fb28f9fd7ecd'
954|19:39:49.483 14848 14885 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859189022312%c8c2fb28f9fd7ecd'
961|19:40:01.939 14848 14885 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859201550987%c8c2fb28f9fd7ecd'
963|19:40:03.637 14848 14885 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859203272299%c8c2fb28f9fd7ecd'
965|19:40:03.890 14848 14885 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859203539048%c8c2fb28f9fd7ecd'
967|19:40:04.185 14848 14885 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859203854927%c8c2fb28f9fd7ecd'

# Process killed (14848) → New process started (15260)
969|19:40:12.863 15260 15292 I ExpoModulesCore: ✅ AppContext was initialized
970|19:40:13.060 15260 15293 I ExpoModulesCore: ✅ JSI interop was installed
971|19:40:13.062 15260 15293 I ExpoModulesCore: ✅ Constants were exported

# ALL previous messages re-delivered simultaneously!
972|19:40:13.160 15260 15293 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859176456941%c8c2fb28f9fd7ecd'
973|19:40:13.161 15260 15293 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859186737605%c8c2fb28f9fd7ecd'
974|19:40:13.161 15260 15293 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859189022312%c8c2fb28f9fd7ecd'
975|19:40:13.161 15260 15293 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859201550987%c8c2fb28f9fd7ecd'
976|19:40:13.162 15260 15293 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859203272299%c8c2fb28f9fd7ecd'
977|19:40:13.162 15260 15293 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859203539048%c8c2fb28f9fd7ecd'
978|19:40:13.162 15260 15293 I ReactNativeJS: '📱 Background/Kill Message received (index.js):', '0:1755859203854927%c8c2fb28f9fd7ecd'

# Multiple duplicate processing (all within same millisecond)
979|19:40:13.183 15260 15293 I ReactNativeJS: ✅ Message processed successfully
980|19:40:13.185 15260 15293 I ReactNativeJS: ✅ Message processed successfully
982|19:40:13.188 15260 15293 I ReactNativeJS: ✅ Message processed successfully
986|19:40:13.194 15260 15293 I ReactNativeJS: ✅ Message processed successfully
987|19:40:13.195 15260 15293 I ReactNativeJS: ✅ Message processed successfully
988|19:40:13.195 15260 15293 I ReactNativeJS: ✅ Message processed successfully
989|19:40:13.195 15260 15293 I ReactNativeJS: ✅ Message processed successfully

What seems to be happening:

From what I can see in the logs, it looks like:

  1. Android kills my app process
  2. New FCM message comes in and wakes up the app
  3. JavaScript takes ~100ms to initialize (ExpoModulesCore setup, JSI bridge, etc.)
  4. Once JS is ready, FCM dumps all the old messages plus the new one
  5. My handler processes the same message IDs multiple times

Some observations:

  • Only happens when the process actually dies (not normal backgrounding)
  • Same message IDs show up again, so definitely duplicates
  • Foreground messaging works fine, no duplicates there
  • All the re-delivered messages come in at exactly the same time
  • JS engine needs about 100ms to get ready after process start

Questions:

  • Is this a known issue with React Native Firebase messaging?
  • Any way to register the background handler earlier at the native level?
  • What's the recommended approach for handling this?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions