Firebase Cloud Upstream Messaging

From Techotopia
Revision as of 17:44, 30 August 2017 by Neil (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
PreviousTable of ContentsNext
Managing Firebase Messaging Device Groups from an Android AppA Firebase Cloud Messaging Upstream XMPP App Server



Up until this point, all of the chapters covering Firebase Cloud Messaging have focused on so called downstream messaging (in other words the transmission of messages from either the Firebase console or a server to device-based client apps). Starting with this chapter, the concept of upstream messaging will be covered in detail. As the name suggests, upstream messaging involves sending a message from the app client. The reason for sending upstream messages depends on the requirements of the specific app, but can be used as a way either for a client app to communicate with the server, or for sending messages between clients.

This chapter will provide a relatively high level overview of upstream messaging in terms of the architecture, data formats and API calls. Subsequent chapters will present a functional client-to-client upstream messaging example including both client and server implementations.


Contents


Firebase Cloud Upstream Messaging Architecture

The preceding chapters have covered the concept of sending downstream messages to a device-based client app, using either the Firebase console, or a Node.js based server to send messages to the client. The situation changes considerably when upstream messaging is introduced. The diagram illustrated in Figure 30 1 outlines the basic architecture necessary to implement upstream messaging using Firebase Cloud Messaging:


Firebase messaging upstream diagram.png

Figure 30-1


Upstream messaging involves client apps, the Firebase Cloud Connection Server (CCS) and an application server. The sequence of events that occur when sending upstream messages can be broken down as follows (where the step numbers correlate to the arrows in the above architecture diagram):

1. The client app registers itself via the Firebase Cloud Messaging API using the same approach as that outlined in previous chapters.

2. Firebase provides the client app with a registration token that uniquely identifies that device/app combination within the Firebase messaging environment.

3. The client app sends an upstream message to the Firebase CCS. In addition to any message the payload also includes, by default, the registration token.

4. The Firebase CCS sends the request to the app server. The app server sends an acknowledgement to the CCS on receipt of the message and implements application specific logic to interpret the message and take appropriate action.

5. If the action involves the transmission of a message (for example sending a response to the original device or passing a message to a different device), this is sent from the app server to the CCS.

6. The CCS delivers the message to the client app on the device.

In this scenario, all communication between the clients and the app server is handled entirely by the CCS. This has the advantage that issues such as message delivery, error handling and message retries are all performed automatically and do not need to be addressed in either the client or app server code. From the point of view of the client, the transmission of an upstream message can be achieved with a single API call.

The connection between the CCS and the app server is a permanent connection and the app server must acknowledge (ACK) every message received from the CCS. In the absence of an acknowledgement, the CCS will assume that the app server is offline and will continue to resend the message until an acknowledgement is received. Similarly, the CCS will send acknowledgements in response to any messages received from the app server. In the event that the data received is in any way invalid, the CCS will typically respond with a negative-acknowledgement (NACK) indicating the nature of the problem.

The CCS and app server communicate with each other using the Extensible Messaging and Presence Protocol (XMPP). XMPP (originally named Jabber) is a protocol designed specifically as a foundation on which to build instant messaging services and allows for the exchange of structured data in near real-time over network connections. XMPP is an open standard and a range of open source libraries and frameworks exist to ease the implementation of XMPP-based communication.

When the app server first starts up, it is responsible for establishing the connection to the CCS. During this connection process, the app server uses the Firebase project server key and sender ID used in previous examples to authenticate with the Firebase messaging system. Once authenticated and connected, the app server simply waits to process incoming messages.

Implementing the App Server

As long as it is able to engage in a meaningful XMPP-based dialog with the CCS, the app server can be written using just about any programming language. Most programming languages have more than one open source library available for handling the XMPP communication protocol from which to choose. The app server can also run on just about any platform, ranging from a simple Java program running on just about any operating system, to a vast enterprise system running on a cloud-based server farm.

The logic within the app server is, of course, entirely dependent on the requirements of the client app. That being said, a typical app server will need to be able to interpret the content of incoming message packets and respond appropriately with outbound messages. It will also be a common requirement for the app server to maintain some form of database that maps user identities (such as usernames or email addresses) to device registration tokens. It is unlikely, for example, that the user of a chat app will know the 174-digit registration token of a friend’s device when sending a message. The app server will, therefore, need to be able to extract the registration token associated with the friend’s username from a database in order to be able to deliver the message.


Sending an Upstream Message from the Client

Once a client has registered and received a registration token, an upstream message is sent via a call to the send() method of the FirebaseMessaging object instance. The message is encapsulated within a Google Play services library RemoteMessage class instance. For convenience, RemoteMessage.Builder may be used when constructing the message.

In addition to a message payload consisting of key/value pairs, the message must also contain a unique message ID and a string that reads @gcm.googleapis.com prefixed with the sender ID associated with the Firebase project. The unique message ID takes the form of a string and can be any sequence of characters that uniquely identifies the message within the Firebase project.

The following code fragment demonstrates the use of RemoteMessage.Builder to create and send an upstream message from within an Android app:

FirebaseMessaging fm = FirebaseMessaging.getInstance();

fm.send(new RemoteMessage.Builder(SenderID + "@gcm.googleapis.com")
        .setMessageId(getMsgId())
        .addData("key1", "a value")
        .addData("key2", "another value")
        .build());

In addition to the setMessageId() and addData() methods, the setTtl() method may be used to specify the amount of time that the message should be queued if the device is not currently connected. This can be set to any duration up to four weeks (2419200 seconds). If this value is not specified the default is four weeks. If, on the other hand, the time to live value is set to 0 the message is discarded after the first attempt.

Similarly, the setCollapseKey() method may be used to identify a group of messages where only the most recent message is sent if multiple messages with the same key are waiting to be sent.

Once the message is sent it will arrive at the CCS where it will be passed to the app server. Any downstream messages sent to the client app will need to be handled within the onMessageReceived() method of the FirebaseMessagingService subclass as documented in the chapter entitled Firebase Cloud Messaging. If the onMessageSent() and onMessageError() callback methods are also overridden in the FirebaseMessagingService subclass, these will be called to notify the app of the status of the message transmission:

@Override
public void onMessageSent(String msgID) {
    Log.d(TAG, "onMessageSent: " + msgID );
}

@Override
public void onSendError(String msgID, Exception exception) {
    Log.d(TAG, "onSendError: " + exception.getMessage() );
}

Summary

An upstream message is a message that originates on the client app and is passed up through to the Firebase messaging cloud. Upstream messaging requires the presence of an app server connected directly to the Firebase Cloud Connection Server (CCS) using the XMPP protocol. The CCS passes upstream messages to the app server where the data is processed and appropriate actions taken. Any downstream messages sent by the app server are transmitted via the CCS.




PreviousTable of ContentsNext
Managing Firebase Messaging Device Groups from an Android AppA Firebase Cloud Messaging Upstream XMPP App Server