Firebase Cloud Messaging in Android App using Command Pattern

Upasana | July 28, 2018 | 4 min read | 195 views


Android FCM Notification

In this tutorial we will learn how to integrate Firebase Cloud Messaging in Andorid Project using Command Design Pattern.

First of all you need to integrate Firebase Cloud Messaging in your android project, so that you are able to receive data messages into your app.

Step 1. Adding required dependencies

You need to add the below dependeices to the top level build.gradle file.

top level build.gradle
buildscript {

    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'
        classpath 'com.google.gms:google-services:4.0.2'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

Also, add the below dependencies to the app level build.gradle file

app level build.gradle
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation 'com.android.support:animated-vector-drawable:27.1.1'
    implementation 'com.android.support:support-v4:27.1.1'
    implementation 'com.android.support:support-compat:27.1.1'

    implementation 'com.google.firebase:firebase-core:16.0.1'
    implementation 'com.google.firebase:firebase-iid:16.2.0'
    implementation 'com.google.firebase:firebase-messaging:17.1.0'
    implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
}

apply plugin: 'com.google.gms.google-services'

Step 2. Creating Command Objects for different types of messages

Now create a command interface that defines behavior when a FCM command is received. For each type of FCM message (sync, news, order_created, order_completed), an FcmCommand implementation should be provided.

public abstract class FcmCommand {

    /**
     * Defines behavior when FCM is received.
     */
    public abstract void execute(Context context, String type, String payload);
}

The below class diagram for different command objects illustrates the use of FcmCommand for handlign different type of command messages sent by FCM:

command pattern
Class Diagram for Command Pattern

For example, a TestCommand implementation will look like this:

public class TestCommand extends FcmCommand {
    private static final String TAG = makeLogTag("TestCommand");

    @Override
    public void execute(Context context, String type, String payload) { (1)
        LOGI(TAG, "Received FCM message: type=" + type + ", extraData=" + payload);
        Gson gson = new Gson();
        TestCommandModel model = gson.fromJson(payload, TestCommandModel.class);
        showNotification(context, model);
    }

    static class TestCommandModel {
        String format;
        String title;
        String messageBody;
    }
}
1 Each command will have a payload that can be converted into Model using Gson

Step 3. Extend FirebaseMessagingService to receive token and message

FirebaseMessagingService class provides two critical features - it gives us regsitration token for this user and it delivers new messages as and when they arrive.

public class MyFirebaseMsgService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    private static final String ACTION = "action";
    private static final String EXTRA_DATA = "extraData";
    private static final Map<String, FcmCommand> MESSAGE_RECEIVERS;

    static {
        // Known messages and their FCM message receivers
        Map<String, FcmCommand> receivers = new HashMap<>();
        receivers.put("test", new TestCommand());
//      receivers.put("feed_update", new FeedCommand());
        MESSAGE_RECEIVERS = Collections.unmodifiableMap(receivers);
    }

    /**
     * Called when message is received.
     */
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.d(TAG, "From: " + remoteMessage.getFrom());
        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
            // A map containing the action and extra data associated with that action.
            Map<String, String> data = remoteMessage.getData();
            // Handle received FCM data messages.
            String action = data.get(ACTION);
            String extraData = data.get(EXTRA_DATA);
            LOGD(TAG, "Got FCM message, " + ACTION + "=" + action + ", " + EXTRA_DATA + "=" + extraData);
            if (action == null) {
                LOGE(TAG, "Message received without command action");
                return;
            }
            //noinspection DefaultLocale
            action = action.toLowerCase();
            FcmCommand command = MESSAGE_RECEIVERS.get(action);
            if (command == null) {
                LOGE(TAG, "Unknown command received: " + action);
            } else {
                if (/* Check if data needs to be processed by long running job */ true) {
                    // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
                    scheduleJob();
                } else {
                    // Handle message within 10 seconds
                    command.execute(this, action, extraData);
                }
            }
        }
    }

    /**
     * Called if InstanceID token is updated. This may occur if the security
     * of the previous token had been compromised. Note that this is called
     * when the InstanceID token is initially generated so this is where you
     * would retrieve the token.
     */
    @Override
    public void onNewToken(String token) {
        Log.d(TAG, "Refreshed token: " + token);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(token);
    }

Finally, we need to register this service into AndroidManifest.xml class, as shown below:

AndroidManifest.xml
<service
    android:name=".fcm.MyFirebaseMsgService"
    android:stopWithTask="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

At any point, if you want to get the Fcm Token from inside of your activity, then you can get it like this:

Get Fcm Token from Activity
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( MyActivity.this,  new OnSuccessListener<InstanceIdResult>() {
     @Override
     public void onSuccess(InstanceIdResult instanceIdResult) {
           String newToken = instanceIdResult.getToken();
           Log.e("newToken", newToken);

     }
 });

Download Source Code

You can download source code for this tutorial from my GitHub repository:
https://github.com/cancerian0684/android-firebase-messaging

References


Top articles in this category:
  1. Retrofit Basic Authentication in Android
  2. Retrofit OAuth2 Bearer Token Authentication OkHttp Android
  3. Service vs Intent Service in Android
  4. FirebaseInstanceIdService is deprecated now
  5. Kotlin Coroutines with Retrofit
  6. iOS interview experience fresher
  7. iOS interview questions for 0-3 years experience

Recommended books for interview preparation:

Find more on this topic:
Buy interview books

Java & Microservices interview refresher for experienced developers.