React-native-firebase: More than one FirebaseMessagingService subclass

Created on 24 May 2018  路  3Comments  路  Source: invertase/react-native-firebase

Hi and thanks for this great library.

I'm in the process of integrating RNFirebase into my project but I hit a roadblock.

I'm currently using another library that also depends on FirebaseMessagingService. Adding the <service> tags to my AndroidManifest.xml causes only one of these subclasses to get called.

What's a good way to handle two libraries that both need to listen to Firebase messages?

Most helpful comment

Hi @mahyarr @sercanov, I've got the same issue a few days ago and in our team, we used a slightly different approach which involves reflection.

In general, we use delegate class and provide context via reflection.

public class OwnPushService extends FirebaseMessagingService {

    private List<FirebaseMessagingService> messagingServices = new ArrayList<>(2);

    public GCPushService() {
        messagingServices.add(new AirshipFirebaseMessagingService());
        messagingServices.add(new TLFirebaseMessagingService());
    }

    @Override
    public void onNewToken(String s) {
        delegate(service -> {
            injectContext(service);
            service.onNewToken(s);
        });
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        delegate(service -> {
            injectContext(service);
            service.onMessageReceived(remoteMessage);
        });
    }

    private void delegate(GCAction1<FirebaseMessagingService> action) {
        for (FirebaseMessagingService service : messagingServices) {
            action.run(service);
        }
    }

    private void injectContext(FirebaseMessagingService service) {
        setField(service, "mBase", this);
    }
}

I've written an article on Medium about this approach: link

All 3 comments

I did some research and it turns out there is no way to have two FirebaseMessageService subclasses in the same project.

I solved my own problem by forking the other library and turning their FirebaseMessageService into a hook that I call from my own code.

My own code is a subclass of io.invertase.firebase.messaging.RNFirebaseMessagingService. Here's the sample:

import io.invertase.firebase.messaging.RNFirebaseMessagingService;

public class XXFirebaseMessageService extends RNFirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage message) {
        super.onMessageReceived(message);
        OtherLibraryWithHooks.getInstance().onMessageReceived(message, this);
    }
}

I encountered this case with a marketing tool which has their own notification handlers, so I needed to create another FirebaseMessagingService to handle pushes from that tool and let their SDK handle the payload.

I tried with following custom service but couldn't even see the Log. Only log I get is RNFMessagingService: onMessageReceived event received

public class XFirebaseMessagingService extends RNFirebaseMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        Log.d("X", "From: " + remoteMessage.getFrom());

        Map<String, String> data = remoteMessage.getData();

        if(data != null) {
            if(data.containsKey("source") && "X".equals(data.get("source"))) {
                XTool.get().receive(data);
            }
        }
    }
}

Related AndroidManifest.xml

        <service android:name="io.invertase.firebase.messaging.RNFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <service android:name="io.invertase.firebase.messaging.RNFirebaseInstanceIdService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>

        <service
            android:name=".XFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>

        <service
            android:name=".XFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>

Any idea why?

Hi @mahyarr @sercanov, I've got the same issue a few days ago and in our team, we used a slightly different approach which involves reflection.

In general, we use delegate class and provide context via reflection.

public class OwnPushService extends FirebaseMessagingService {

    private List<FirebaseMessagingService> messagingServices = new ArrayList<>(2);

    public GCPushService() {
        messagingServices.add(new AirshipFirebaseMessagingService());
        messagingServices.add(new TLFirebaseMessagingService());
    }

    @Override
    public void onNewToken(String s) {
        delegate(service -> {
            injectContext(service);
            service.onNewToken(s);
        });
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        delegate(service -> {
            injectContext(service);
            service.onMessageReceived(remoteMessage);
        });
    }

    private void delegate(GCAction1<FirebaseMessagingService> action) {
        for (FirebaseMessagingService service : messagingServices) {
            action.run(service);
        }
    }

    private void injectContext(FirebaseMessagingService service) {
        setField(service, "mBase", this);
    }
}

I've written an article on Medium about this approach: link

Was this page helpful?
0 / 5 - 0 ratings