# Firebase Messaging Service overrides

## The problem

The `@stream-io/react-native-callingx` package provides its own `FirebaseMessagingService` implementation (`StreamMessagingService`) and registers it in its manifest.

**Android FCM only delivers each push to a single `FirebaseMessagingService` per app.** If your merged manifest declares more than one — typically because another push SDK registers its own, or because your app ships a custom service — only the one PackageManager resolves first actually fires. Depending on which service wins the merge, you'll see either Stream ringing pushes stop showing or the other SDK stop receiving its pushes.

<admonition type="note">

The manifest merger doesn't flag this as an error — declaring multiple `MESSAGING_EVENT` services is legal and the build succeeds. There is just no fan-out at runtime.

</admonition>

## How to detect the conflict

In Android Studio, open `AndroidManifest.xml` and switch to the **Merged Manifest** tab. Search for `MESSAGING_EVENT` and count the `<service>` entries that declare it. More than one means you have a conflict.

Two patterns resolve this — pick based on whether you can subclass `StreamMessagingService` or need to host your own service.

## Option 1 — Subclass `StreamMessagingService`

Pick this when you don't need to inherit from another SDK's service. Subclassing handles Stream's `call.ring` push notifications automatically, keeps the React Native Firebase background-message flow intact, and gives you a hook for custom forwarding.

```kotlin title="android/app/src/main/java/.../AppMessagingService.kt"
package com.example.app

import com.google.firebase.messaging.RemoteMessage
import io.getstream.rn.callingx.StreamMessagingService

class AppMessagingService : StreamMessagingService() {

  override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // Stream call.ring + React Native Firebase JS background handler
    super.onMessageReceived(remoteMessage)

    // Optional — short-circuit other forwarders for Stream pushes.
    // `isStreamCallRing` is provided for flexibility; Stream's `call.ring`
    // has already been handled by `super.onMessageReceived(...)`.
    if (StreamMessagingHelper.isStreamCallRing(remoteMessage)) return

    // forward non-Stream pushes to other SDKs
    ExampleSDK.passRemoteMessage(applicationContext, remoteMessage)
  }
}
```

## Option 2 — Forward via `StreamMessagingHelper`

Pick this when your app already hosts its own `FirebaseMessagingService`. Remove Stream's service from the manifest and forward `call.ring` payloads via `StreamMessagingHelper` from your own service.

```kotlin title="android/app/src/main/java/.../AppMessagingService.kt"
package com.example.app

import com.google.firebase.messaging.RemoteMessage
import io.getstream.rn.callingx.StreamMessagingHelper
import io.invertase.firebase.messaging.ReactNativeFirebaseMessagingService

class AppMessagingService : ReactNativeFirebaseMessagingService() {

  override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // pass remote message to React Native Firebase JS background handler
    super.onMessageReceived(remoteMessage)

    // Optional gate — provided for finer control over the forwarding flow.
    // `handleMessage` is also safe to call unconditionally; it no-ops for
    // payloads that aren't a Stream `call.ring`.
    if (StreamMessagingHelper.isStreamCallRing(remoteMessage)) {
      StreamMessagingHelper.handleMessage(applicationContext, remoteMessage)
    } else {
      // forward to other SDKs
      ExampleSDK.passRemoteMessage(applicationContext, remoteMessage)
    }
  }
}
```

<admonition type="important">

Your custom service **must extend `ReactNativeFirebaseMessagingService` and chain `super.onMessageReceived(...)`** — otherwise React Native Firebase's JS background handler (`setBackgroundMessageHandler()`) stops firing.

</admonition>

The helper exposes two methods:

| API                                                           | Purpose                                                                                                                             |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `StreamMessagingHelper.isStreamCallRing(remoteMessage)`       | Returns `true` if the payload is a Stream Video `call.ring`. Useful when you want to short-circuit other SDK forwarders.            |
| `StreamMessagingHelper.handleMessage(context, remoteMessage)` | Handles a Stream `call.ring` payload (starts the incoming call flow). No-op for non-Stream payloads — safe to call unconditionally. |

## Register your service in the manifest

Both options need the same change in `android/app/src/main/AndroidManifest.xml` — remove the default `StreamMessagingService` and register yours in its place:

```xml title="android/app/src/main/AndroidManifest.xml"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
  <application>
    <service
        android:name="io.getstream.rn.callingx.StreamMessagingService"
        tools:node="remove" />

    <service
        android:name=".AppMessagingService"
        android:exported="false">
      <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
      </intent-filter>
    </service>
  </application>
</manifest>
```


---

This page was last updated at 2026-05-25T15:27:30.969Z.

For the most recent version of this documentation, visit [https://getstream.io/video/docs/react-native/incoming-calls/advanced/firebase-messaging-conflicts/](https://getstream.io/video/docs/react-native/incoming-calls/advanced/firebase-messaging-conflicts/).