Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐛] 🔥 Firebase notification is received but the callbacks are not triggered (workaround: opt out of google play services notification delegation) #8392

Open
3 of 10 tasks
kerimamansaryyev opened this issue Mar 6, 2025 · 20 comments
Labels
Needs Attention platform: android plugin: messaging FCM only - ( messaging() ) - do not use for Notifications type: bug New bug report

Comments

@kerimamansaryyev
Copy link

kerimamansaryyev commented Mar 6, 2025

[MAINTAINER NOTE: the problem is with the new "notification delegation" feature rolled out in Google Play Services. The workaround is to opt out. There is a link to the Google doc with instructions on how to opt out in this comment - the AndroidManifest style and the FCM android / proxy deny key methods are both confirmed working, choose what works for you]


Issue

This issue was detected specifically on Samsung Galaxy A14 (running on Android 14).

Steps to reproduce:

  1. Create a React Native application with the latest version of the react native community CLI. I've investigated the bug using 0.76 and 0.78 versions of React Native.
  2. Add @react-native-firebase/app and @react-native-firebase/messaging, follow corresponding SDK instructions.
  3. Add the reproducible (attached to the issue) code to: Request permissions, acquire the token, try getting the initial notification through getInitialNotification, listen to onMessage, onNotificationOpenedApp.
  4. While the application is visible, verify that you can receive notifications, check the logs from onMessage listener.
  5. Close the application (swipe it away from recents).
  6. Trigger the notification while the app is killed.
  7. Click on the received notification. Verify the application was launched upon the notification.
  8. While the app is visible, try triggering notifications again. Here is the outcome:
    • Now neither of the listeners will never be triggered from this point (onMessage, onNotificationOpenedApp)
    • A native notification will be triggered even if an application is in foreground and visible
    • getInitialNotification will always return null
    • Relaunching an application wouldn't help
    • A normal behavior can only be restored either by re-installing the app or clearing data.

From my investigation:
I tapped multiple locations from the source code of @react-native-firebase/messaging, and found out an issue with ReactNativeFirebaseMessagingReceiver and ReactNativeFirebaseMessagingService. Apparently, when you click on a native notification (received from background or quit state), it somehow affects on both the receiver and the service, so the receiver's onReceived method won't be called anymore nor the service's onMessageReceived will be triggered.

I suppose that Samsung Galaxy A14 terminates the receiver and the service after you click on a notification. It's believed that Samsung devices may have quite aggressive power management which restricts background tasks and activities, however, even after turning off the optimizations and the restrictions, the issue has still persisted.

Here are some related threads from the Flutter repository:

Sample App.tsx:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 */

import React, { useCallback, useEffect } from 'react';
import type {PropsWithChildren} from 'react';
import {
  PermissionsAndroid,
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  useColorScheme,
  View,
} from 'react-native';

import {
  Colors,
  DebugInstructions,
  Header,
  LearnMoreLinks,
  ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

import { getMessaging } from '@react-native-firebase/messaging';
import { getApp } from '@react-native-firebase/app';

type SectionProps = PropsWithChildren<{
  title: string;
}>;

function Section({children, title}: SectionProps): React.JSX.Element {
  const isDarkMode = useColorScheme() === 'dark';
  return (
    <View style={styles.sectionContainer}>
      <Text
        style={[
          styles.sectionTitle,
          {
            color: isDarkMode ? Colors.white : Colors.black,
          },
        ]}>
        {title}
      </Text>
      <Text
        style={[
          styles.sectionDescription,
          {
            color: isDarkMode ? Colors.light : Colors.dark,
          },
        ]}>
        {children}
      </Text>
    </View>
  );
}

const messaging = getMessaging(getApp());

function App(): React.JSX.Element {
  const isDarkMode = useColorScheme() === 'dark';

  const backgroundStyle = {
    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
  };

  const firebaseTestPipeline = useCallback(async () => {
    console.log('Requesting permissions...');
    try{
      await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
      );
      const token = await messaging.getToken();
  
      console.log(token);
  
      console.log('FCM initial:', await messaging.getInitialNotification());
  
      messaging.onMessage(async remoteMessage => {
        console.log('A new FCM message arrived!', JSON.stringify(remoteMessage));
      });
  
      messaging.onNotificationOpenedApp(message => {
        console.log('Notification opened when app was in background!', JSON.stringify(message));
      });
    } catch (error) {
      console.error('Error:', error);
    }
  }, []);

  useEffect(() => {
    firebaseTestPipeline();
  }, [firebaseTestPipeline]);

  return (
    <SafeAreaView style={backgroundStyle}>
      <StatusBar
        barStyle={isDarkMode ? 'light-content' : 'dark-content'}
        backgroundColor={backgroundStyle.backgroundColor}
      />
      <ScrollView
        contentInsetAdjustmentBehavior="automatic"
        style={backgroundStyle}>
        <Header />
        <View
          style={{
            backgroundColor: isDarkMode ? Colors.black : Colors.white,
          }}>
          <Section title="Step One">
            Edit <Text style={styles.highlight}>App.tsx</Text> to change this
            screen and then come back to see your edits.
          </Section>
          <Section title="See Your Changes">
            <ReloadInstructions />
          </Section>
          <Section title="Debug">
            <DebugInstructions />
          </Section>
          <Section title="Learn More">
            Read the docs to discover what to do next:
          </Section>
          <LearnMoreLinks />
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
  sectionTitle: {
    fontSize: 24,
    fontWeight: '600',
  },
  sectionDescription: {
    marginTop: 8,
    fontSize: 18,
    fontWeight: '400',
  },
  highlight: {
    fontWeight: '700',
  },
});

export default App;


Project Files

Javascript

Click To Expand

package.json:

{
  "name": "com.myissue.app",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "lint": "eslint .",
    "start": "react-native start",
    "test": "jest"
  },
  "dependencies": {
    "@react-native-firebase/app": "^21.12.0",
    "@react-native-firebase/messaging": "^21.12.0",
    "react": "18.3.1",
    "react-native": "0.76.3"
  },
  "devDependencies": {
    "@babel/core": "^7.25.2",
    "@babel/preset-env": "^7.25.3",
    "@babel/runtime": "^7.25.0",
    "@react-native-community/cli": "15.0.1",
    "@react-native-community/cli-platform-android": "15.0.1",
    "@react-native-community/cli-platform-ios": "15.0.1",
    "@react-native/babel-preset": "0.76.3",
    "@react-native/eslint-config": "0.76.3",
    "@react-native/metro-config": "0.76.3",
    "@react-native/typescript-config": "0.76.3",
    "@types/react": "^18.2.6",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.6.3",
    "eslint": "^8.19.0",
    "jest": "^29.6.3",
    "prettier": "2.8.8",
    "react-test-renderer": "18.3.1",
    "typescript": "5.0.4"
  },
  "engines": {
    "node": ">=18"
  }
}

firebase.json for react-native-firebase v6:

# N/A

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# N/A

AppDelegate.m:

// N/A


Android

Click To Expand

Have you converted to AndroidX?

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

android/build.gradle:

buildscript {
    ext {
        buildToolsVersion = "35.0.0"
        minSdkVersion = 24
        compileSdkVersion = 35
        targetSdkVersion = 35
        ndkVersion = "26.1.10909125"
        kotlinVersion = "1.9.24"
    }
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath("com.android.tools.build:gradle")
        classpath("com.facebook.react:react-native-gradle-plugin")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
        classpath 'com.google.gms:google-services:4.4.2'
    }
}

apply plugin: "com.facebook.react.rootproject"

android/app/build.gradle:

apply plugin: "com.android.application"
apply plugin: 'com.google.gms.google-services'
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"

/**
 * This is the configuration block to customize your React Native Android app.
 * By default you don't need to apply any configuration, just uncomment the lines you need.
 */
react {
    /* Folders */
    //   The root of your project, i.e. where "package.json" lives. Default is '../..'
    // root = file("../../")
    //   The folder where the react-native NPM package is. Default is ../../node_modules/react-native
    // reactNativeDir = file("../../node_modules/react-native")
    //   The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
    // codegenDir = file("../../node_modules/@react-native/codegen")
    //   The cli.js file which is the React Native CLI entrypoint. Default is ../../node_modules/react-native/cli.js
    // cliFile = file("../../node_modules/react-native/cli.js")

    /* Variants */
    //   The list of variants to that are debuggable. For those we're going to
    //   skip the bundling of the JS bundle and the assets. By default is just 'debug'.
    //   If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
    // debuggableVariants = ["liteDebug", "prodDebug"]

    /* Bundling */
    //   A list containing the node command and its flags. Default is just 'node'.
    // nodeExecutableAndArgs = ["node"]
    //
    //   The command to run when bundling. By default is 'bundle'
    // bundleCommand = "ram-bundle"
    //
    //   The path to the CLI configuration file. Default is empty.
    // bundleConfig = file(../rn-cli.config.js)
    //
    //   The name of the generated asset file containing your JS bundle
    // bundleAssetName = "MyApplication.android.bundle"
    //
    //   The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
    // entryFile = file("../js/MyApplication.android.js")
    //
    //   A list of extra flags to pass to the 'bundle' commands.
    //   See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
    // extraPackagerArgs = []

    /* Hermes Commands */
    //   The hermes compiler command to run. By default it is 'hermesc'
    // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
    //
    //   The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
    // hermesFlags = ["-O", "-output-source-map"]

    /* Autolinking */
    autolinkLibrariesWithApp()
}

/**
 * Set this to true to Run Proguard on Release builds to minify the Java bytecode.
 */
def enableProguardInReleaseBuilds = false

/**
 * The preferred build flavor of JavaScriptCore (JSC)
 *
 * For example, to use the international variant, you can use:
 * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
 *
 * The international variant includes ICU i18n library and necessary data
 * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
 * give correct results when using with locales other than en-US. Note that
 * this variant is about 6MiB larger per architecture than default.
 */
def jscFlavor = 'org.webkit:android-jsc:+'

android {
    ndkVersion rootProject.ext.ndkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
    compileSdk rootProject.ext.compileSdkVersion

    namespace "com.myissue.app"
    defaultConfig {
        applicationId "com.myissue.app"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
}

dependencies {
    // The version of react-native is set by the React Native Gradle Plugin
    implementation("com.facebook.react:react-android")

    if (hermesEnabled.toBoolean()) {
        implementation("com.facebook.react:hermes-android")
    } else {
        implementation jscFlavor
    }
}

android/settings.gradle:

pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
rootProject.name = 'com.myissue.app'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')

MainApplication.java:

package com.myissue.app

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader

class MainApplication : Application(), ReactApplication {

  override val reactNativeHost: ReactNativeHost =
      object : DefaultReactNativeHost(this) {
        override fun getPackages(): List<ReactPackage> =
            PackageList(this).packages.apply {
              // Packages that cannot be autolinked yet can be added manually here, for example:
              // add(MyReactNativePackage())
            }

        override fun getJSMainModuleName(): String = "index"

        override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

        override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
        override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
      }

  override val reactHost: ReactHost
    get() = getDefaultReactHost(applicationContext, reactNativeHost)

  override fun onCreate() {
    super.onCreate()
    SoLoader.init(this, OpenSourceMergedSoMapping)
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      load()
    }
  }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme"
      android:supportsRtl="true">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
    </application>
</manifest>


Environment

Click To Expand

react-native info output:

 info Fetching system and libraries information...
(node:52050) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
System:
  OS: macOS 14.6.1
  CPU: (10) arm64 Apple M2 Pro
  Memory: 151.22 MB / 16.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 23.6.0
    path: /opt/homebrew/bin/node
  Yarn:
    version: 1.22.22
    path: /opt/homebrew/bin/yarn
  npm:
    version: 10.9.2
    path: /opt/homebrew/bin/npm
  Watchman:
    version: 2024.12.02.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods: Not Found
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 24.0
      - iOS 18.0
      - macOS 15.0
      - tvOS 18.0
      - visionOS 2.0
      - watchOS 11.0
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.2 AI-242.23339.11.2421.12700392
  Xcode:
    version: 16.0/16A242d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.12
    path: /usr/bin/javac
  Ruby:
    version: 3.1.0
    path: /Users/ka3487/.rvm/rubies/ruby-3.1.0/bin/ruby
npmPackages:
  "@react-native-community/cli":
    installed: 15.0.1
    wanted: 15.0.1
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.76.3
    wanted: 0.76.3
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: true
iOS:
  hermesEnabled: Not found
  newArchEnabled: false

info React Native v0.78.0 is now available (your project is running on v0.76.3).
info Changelog: https://github.com/facebook/react-native/releases/tag/v0.78.0
info Diff: https://react-native-community.github.io/upgrade-helper/?from=0.76.3&to=0.78.0
info For more info, check out "https://reactnative.dev/docs/upgrading?os=macos".
  • 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:
    • 21.12.0
  • Firebase module(s) you're using that has the issue:
    • @react-native-firebase/messaging
  • Are you using TypeScript?
    • Y & 5.0.4


@soutua
Copy link

soutua commented Mar 7, 2025

We have started getting similar reports from our Android users during the past week where notifications that they press on, just open the app and don't go where they are supposed to. We did update the react-native-firebase from version 21.4.0 to version 21.7.1 on last week's Monday so my initial thought was that it would be related to the update, but not sure if this is happening suddenly for other apps too 🤔

@mikehardy
Copy link
Collaborator

I believe this may be duplicate, and I have a comment here detailing how to go a little deeper with the investigation --> #8112 (comment)

@soutua are you also seeing this from Samsung A14 users specifically, or all users? The message I link seems to be related to Android14+ not just Samsung A14 users (confusingly similar names, but hopefully I'm communicating clearly)

My hypothesis is that this may be the new google play services version and notification proxy stuff. Note that this may be disabled with an AndroidManifest.xml tweak to test that hypothesis (@kerimamansaryyev if you have a good reproduction case for it, trying that AndroidManifest change to disable google play services notification proxy would be the first thing I'd check, followed by instrumenting the code in the areas I mention in the comment I link)

@soutua
Copy link

soutua commented Mar 7, 2025

@soutua are you also seeing this from Samsung A14 users specifically, or all users? The message I link seems to be related to Android14+ not just Samsung A14 users (confusingly similar names, but hopefully I'm communicating clearly)

Hi! We have gotten this feedback from users with the following devices:
SM-S921B (Samsung Galaxy S24) with Android 14
CPH2465 (OnePlue Nord CE 3 Lite) with Android 15
moto g54 5G (Motorola G54 5G) with Android 15
SM-A336B (Samsung Galaxy A33) with Android 14
SM-S906B (Samsung Galaxy S22+) Android 14
Nokia X30 5G with Android 14

So it seems to be Android 14+ users at least by the feedback we have gotten. We haven't been able to reproduce this ourselves though.

So in theory if we add this to our AndroidManifest.xml:

<meta-data android:name="firebase_messaging_notification_delegation_enabled"
android:value="false"/>

It would prevent it from using the new delegation system and avoid the problem? We could try that 🤔 We have around 1 million users who almost all use notifications so we'll see by the feedback if it fixes it or not 😅

@mikehardy
Copy link
Collaborator

So in theory if we add this to our AndroidManifest.xml:

It would prevent it from using the new delegation system and avoid the problem?

Yes - that is my hypothesis. I haven't reproduced this personally so I cannot say one way or the other. But it will be a quick way to either focus in immediately on this specific area (notification proxy/delegate stuff from google play services) or the opposite to realize it isn't going to be the root cause and so focus effort somewhere else.

Any results you get if you run that experiment on a population that will give a pretty certain answer, or if you reproduce the issue yourself and the change fixes it - would be very informative

@matthesjh
Copy link

We have this issue on some Android 15 devices too. I was able to fix this problem on a Pixel 6 device with the above meta data entry in AndroidManifest.xml. The callbacks are triggered successfully again.

Another approach, as stated in the Google docs, can be to set the proxy key to DENY in the AndroidNotification object for the send request. But we haven't tried that yet.

@mikehardy
Copy link
Collaborator

Really useful information @matthesjh thank you! I think we should be able to handle notifications that come in with the proxy stuff in use, but as mentioned above simply having some observed data that this is the area to focus on is really critical information, thanks

So more experiment results are always useful to make sure the result is conclusive - anyone else experiencing this, if you add that key in AndroidManifest (requires a new build), or in your FCM body (just change your notification send logic server side), please chime in until we're certain we know this is it, and that there are good mitigation strategies

@kerimamansaryyev
Copy link
Author

I believe this may be duplicate, and I have a comment here detailing how to go a little deeper with the investigation --> #8112 (comment)

@soutua are you also seeing this from Samsung A14 users specifically, or all users? The message I link seems to be related to Android14+ not just Samsung A14 users (confusingly similar names, but hopefully I'm communicating clearly)

My hypothesis is that this may be the new google play services version and notification proxy stuff. Note that this may be disabled with an AndroidManifest.xml tweak to test that hypothesis (@kerimamansaryyev if you have a good reproduction case for it, trying that AndroidManifest change to disable google play services notification proxy would be the first thing I'd check, followed by instrumenting the code in the areas I mention in the comment I link)

I had already tried tapping the receiver and the services, the logcat didn't show any logs, hence I concluded that they are being ignored completely. I appreciate immediate attention to this issue. Seems like they rolled out the new Google Play services update on random Thursday :)

I still have the reproducible code and the test device, so I will test the hypothesis with tweaking the proxy feature in AndroidManifest. Once I do that, I will report updates here. Thank you!

@kerimamansaryyev
Copy link
Author

kerimamansaryyev commented Mar 7, 2025

@soutua are you also seeing this from Samsung A14 users specifically, or all users? The message I link seems to be related to Android14+ not just Samsung A14 users (confusingly similar names, but hopefully I'm communicating clearly)

Hi! We have gotten this feedback from users with the following devices: SM-S921B (Samsung Galaxy S24) with Android 14 CPH2465 (OnePlue Nord CE 3 Lite) with Android 15 moto g54 5G (Motorola G54 5G) with Android 15 SM-A336B (Samsung Galaxy A33) with Android 14 SM-S906B (Samsung Galaxy S22+) Android 14 Nokia X30 5G with Android 14

So it seems to be Android 14+ users at least by the feedback we have gotten. We haven't been able to reproduce this ourselves though.

So in theory if we add this to our AndroidManifest.xml:

<meta-data android:name="firebase_messaging_notification_delegation_enabled"
android:value="false"/>

It would prevent it from using the new delegation system and avoid the problem? We could try that 🤔 We have around 1 million users who almost all use notifications so we'll see by the feedback if it fixes it or not 😅

I confirm that the issue has been resolved by applying the meta tag. I believe that people will appreciate it if this new Google Play Services update will be mentioned in react-native-firebase docs.

@mikehardy
Copy link
Collaborator

Great news to get a second confirm on disabling the delegation being an effective workaround. Agreed a docs update can help, additionally at least until we understand how to handle the feature better I can add the ability to toggle the flag in firebase.json in the same way we allow the configuration of a few of the other tags, so at least this can be handled at build time, even for Expo folks who don't normally have access to that file.

Okay - so for anyone else seeing this no response from the listeners / firebase methods in response to a notification tap: Follow the instructions here and pick a method you can implement to opt out for now: https://firebase.google.com/docs/cloud-messaging/android/message-priority#proxy

@mikehardy mikehardy changed the title [🐛] 🔥 Firebase notification is received but the callbacks are not triggered [🐛] 🔥 Firebase notification is received but the callbacks are not triggered (workaround: opt out of google play services notification delegation) Mar 7, 2025
@kerimamansaryyev
Copy link
Author

kerimamansaryyev commented Mar 7, 2025

Great news to get a second confirm on disabling the delegation being an effective workaround. Agreed a docs update can help, additionally at least until we understand how to handle the feature better I can add the ability to toggle the flag in firebase.json in the same way we allow the configuration of a few of the other tags, so at least this can be handled at build time, even for Expo folks who don't normally have access to that file.

Okay - so for anyone else seeing this no response from the listeners / firebase methods in response to a notification tap: Follow the instructions here and pick a method you can implement to opt out for now: https://firebase.google.com/docs/cloud-messaging/android/message-priority#proxy

By the way, although one of the methods states:

On a per-message basis: Set the proxy key to DENY in the AndroidNotification object for the send request.>

There is no such a property in the firebase admin SDK. I checked out the source code of Python and Java admin SDKs. There is no proxy key on AndroidNotification model. Adding the key into the data property of AndroidConfig object yields no effect.

@kerimamansaryyev
Copy link
Author

@mikehardy Do you know any centralized way to submit a feature request to Firebase Admin SDK rather than filling issues per repository?

@mikehardy
Copy link
Collaborator

@kerimamansaryyev I'm not sure I follow. What issues would you be filing? Does firebase-admin-sdk not support sending that key and needs a fix to support sending the opt-out key in your FCM requests? Or, perhaps firebase-android-sdk to add some support somehow for whatever the notification Intent looks like when it comes from the delegation / proxy instead ? Or ?

@kerimamansaryyev
Copy link
Author

kerimamansaryyev commented Mar 7, 2025

@mikehardy

Does firebase-admin-sdk not support sending that key and needs a fix to support sending the opt-out key in your FCM requests?

Yes, it's not supported by the admin SDKs, even though it's supported via Firebase REST API. I am asking, just in case if you know, how to deliver this issue to Firebase team more conveniently than filing a feature request to each of the admin SDK repos.

@mikehardy
Copy link
Collaborator

Okay - understood @kerimamansaryyev - unfortunately, I am not aware of a way other than engaging via issues in the repositories for the specific things you need in each repository.

@austinwitherspoon
Copy link

I'm a flutter user, but I found this after weeks of troubleshooting. Thanks everybody in this thread.
Only a small subset of users had the issue and I couldn't reproduce it. All firebase notifications were coming in null.

The AndroidManifest.xml fix didn't work for me, but updating the payload on the server side to include proxy: "DENY" in the android notification property worked! All of the users that had the issue are reporting it's fixed now.

@MichaelVerdon
Copy link
Collaborator

Hey @kerimamansaryyev does the solution provided by @austinwitherspoon solve things for you?

@kerimamansaryyev
Copy link
Author

Hey @kerimamansaryyev does the solution provided by @austinwitherspoon solve things for you?

I haven't tested out that particular solution because I am not using Firebase REST API but the admin SDK on Python, which doesn't yet support applying proxy property to the request payload. However, as mentioned above, the workaround to opt out the delegation in AndroidManifest.xml solved the issue in my case.

Also, I'm curious if it's possible to support both the Google Play Services notification delegation and handling notifications normally because I believe the one should not disrupt the other. From my observations, notifications, delivered upon the Google Play Services delegation, wouldn't be reported to the broadcast receiver declared in AndroidManifest.xml of this package.

@mikehardy
Copy link
Collaborator

mikehardy commented Mar 11, 2025

I'm curious if it's possible to support both the Google Play Services notification delegation and handling notifications normally because I believe the one should not disrupt the othe

That's the only reason I've left the issue open - to investigate what the difference is in the Intent object the Android app receives for a delegated notification when tapped vs the non-delegated one.

The known workaround of opting out (however you manage to do so) is sufficient for now, but ideally yes, these delegated notifications should be handled as well

Alternatively, if there is no way to handle them then react-native-firebase needs a change to packages/messaging/android/AndroidManifest.xml to opt everyone out by default for the package so it doesn't require manual change from every module consumer

@LA-Johan
Copy link

Another data point, setting proxy to "DENY" in the http protocol immediately fixed the issue for us. Including the modified code if someone wants a pointer on what to change:

def format_fcm_notification(token)
    unread_chat_count = recipient.unread_chats_count
    unread_notification_count = unread_notification_count(token)

    {
      token:,
      notification: {
        title: title.truncate(200),
        body: message&.truncate(500) || ""
      },
      apns: {
        payload: {
          alert: {
            title: title.truncate(200),
            subtitle: subtitle&.truncate(200),
            body: body&.truncate(500) || ""
          },
          aps: {
            badge: unread_chat_count + unread_notification_count
          }
        }
      },
      android: {
        notification: {
          # suggested here: https://github.com/invertase/react-native-firebase/issues/8392
          proxy: "DENY"
        }
      },
      data: {
        dest: push_notification_destination || destination,
        badge_counts: {
          chats: unread_chat_count,
          notifications: unread_notification_count
        }.to_json
      }
    }
  end

@WillianMedeiros14
Copy link

Passar o proxy: "DENY" funcionou para mim.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Attention platform: android plugin: messaging FCM only - ( messaging() ) - do not use for Notifications type: bug New bug report
Projects
None yet
Development

No branches or pull requests

8 participants