Skip to content

Topic Messaging with Firebase Cloud Messaging on Android

Topic Messaging is used for sending messages to people subscribed to well, topics. Perfectly suited for publicly available information like news, weather, and the sort.

As such, we need to provide a way for users to subscribe before anything else.

Subscribing to the Topic

FirebaseMessaging.getInstance().subscribeToTopic("news")
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                String msg = getString(R.string.msg_subscribed);
                if (!task.isSuccessful()) {
                    msg = getString(R.string.msg_subscribe_failed);
                }
                Log.d(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

Doesn’t get any simpler than that. A subscribeToTopic method passing in the topic name, and a listener.

Unsubscribing from the Topic

FirebaseMessaging.getInstance().unsubscribeFromTopic("news")

Do I really need to say more?

Receiving Messages

If you’ve seen my Getting Started with Cloud Messaging post, you should have already created a class that extends FirebaseMessagingService to receive messages, as well as edited your manifest. In that class, you want to override the onMessageReceived calllback.

onMessageReceived

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(LOG_TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(LOG_TAG, "Message data payload: " + remoteMessage.getData());

        if (LONG_RUNNING_JOB) {
            scheduleJob();
        } else {
            handleNow();
        }
    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(LOG_TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }
}

Here, you want to check if the incoming message has a data payload (for example, the ID of a news article) and a notification payload, and handle them both accordingly.

Just note that data from the data payload may only be available for 10 seconds. If you have operations that may require more than 10 seconds of (hopefully) asynchronous processing time, you can use a FirebaseJobDispatcher to handle the data for longer.

Firebase Job Dispatcher

If you’re handling data payload for more than 10 seconds, you’ll be using Firebase Job Dispatcher which is another library. You’ll have to import it (You can skip this otherwise).

implementation 'com.firebase:firebase-jobdispatcher:0.8.5'

Add this to your app-level build.gradle file.

<service
    android:exported="false"
    android:name=".MyJobService">
    <intent-filter>
        <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
    </intent-filter>
</service>

After that, create a service that extends JobService and then add it to your manifest. This service should implement the onStartJob and onStopJob methods where you’ll handle scheduled jobs.

private void scheduleJob(String payload) {
        Bundle bundle = new Bundle();
        bundle.putString("payload", payload);

        FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));
        Job myJob = dispatcher.newJobBuilder()
                .setService(MyJobService.class)
                .setExtras(bundle)
                .build();

        dispatcher.mustSchedule(myJob);
    }

Back in your FirebaseMessagingService , you can schedule a job like this, passing in the data from your payload in a bundle. Then in the onStartJob method, you can retrieve your bundle from the provided JobParameters object.

(For more on Firebase Job Dispatcher, check out https://github.com/firebase/firebase-jobdispatcher-android)

Sending Topic Messages

Finally, everything’s set up, users receive and handle messages. We’re now ready to send the messages.

Firstly, there’s the easy way of using the Firebase Console to quickly compose and send messages, complete with custom data and all that.

Or you can use a POST HTTP request to perform the operation.

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
  "message":{
    "topic" : "foo-bar",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message"
      }
   }
}

Example of a POST HTTP request sending a message to a single topic

You can also use POST HTTP requests to send messages to multiple topics using simple logic.

'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)

For more on building POST HTTP requests for sending messages to topics, check out the official documentation.

Conclusion

As with most of my other posts, this is a watered-down version of the official docs tutorial on the same topic (no pun intended), built for the simple minds. Many of the code excerpts were taken from that page. Just a little disclaimer.

Check out the other parts of my Firebase Cloud Messaging series:

1. Getting Started with Firebase Cloud Messaging on Android

3. Device Group Messaging with Firebase Cloud Messaging

4. Constructing POST HTTP Firebase Cloud Messages for dummies and YOU