Downstream Communication in Android - Server to Client

Contacting the server from your app is simple, all you got to do is make an API call to your backend server using a library like Retrofit or Volley and get/send the required information.

Downstream Communication in Android - Server to Client

Contacting the server from your app is simple, all you got to do is make an API call to your backend server using a library like Retrofit or Volley and get/send the required information.

But are you aware of how your backend server can inform the app of any state change, for instance, notify your app that a new message has been received? In this article, let's discuss different ways to implement downstream (server-to-client) communication.

An illustration to help you understand the difference b/w upstream vs downstream communication. 

Wikipedia defines downstream communication as data sent from a network service provider to a client. When we translate this to our use case, the backend server sends signals (or information) to our Android app, which our app then processes as per our requirements.

Now, let's look at a few different ways to implement downstream communication.

Polling

This is a very crude way, and definitely not recommended, but one way to solve our requirement is to keep requesting the server for any updates at fixed intervals (maybe say every 5 or 10 seconds).

HTTP/HTTPS Long Polling

Similar to the above case, the client (android app) polls the server requesting any new information. The server then holds the request open until it has any new data available and only then sends a response to the client. Once a response is received, the app makes another request, which the server holds open till it has new data and this process repeats.

Long Polling is a decent solution for small and hobby projects, but we recommend staying away from this architecture if you want to build something scalable.

Top Disadvantages of Long Polling

  • Overhead - This creates a new HTTP or HTTPS connection each time, which is expensive for your infrastructure. Modern methods, use proxies to avoid this, but this is still very relevant.
  • Connection Status - How do you know if your client is still waiting for the response or if it is disconnected? You will need to check this after every fixed interval (i.e. heartbeats), which again adds overhead.

If you'd still like to implement Long Polling, CometD is the most popular library for Long Polling, so do check it out.

MQTT

MQTT is a lightweight, publisher-subscriber model for communication between server and client devices. Since this is extremely lightweight, it allows for bi-directional communication between the server and the client i.e. you can use this architecture even to send data from your app to your backend server.

MQTT has been tested in environments having millions of client devices, has multiple levels of reliable message delivery guarantees, is secure, and to top it all, it claims to work with slow/unreliable cellular networks.

Image Source - MQTT

This architecture includes having an MQTT Broker, who receives and publishes messages, from and to MQTT clients. In this protocol, the backend server, which serves as an MQTT Client, connects to an MQTT Broker and sends the message to the broker, who then publishes the message to the respective client (our Android app).

Prior to setting up a connection, the app should request your backend for credentials to connect to the broker, through an API call. To make your life simpler, you should be making use of services like RabbitMQ in your backend to help you implement this MQTT architecture.

The most popular library for Android to help you set up an MQTT client on your app, Paho MQTT has not been updated for quite a while now (2 years at the time of writing this article). It has hundreds of pending issues, while the maintainers have moved on to other projects. If you're willing to live with this, maybe fork it and fix the issues yourself, this is a pretty good architecture to help you with downstream communication.

We have personally used Paho for quite a while with one of our projects which had over 1 million DAU before we moved to something more scalable and cost-efficient (discussing this soon, please be patient).

Web Sockets - Socket.io

WebSocket is a communication protocol that provides full-duplex communication over a single TCP connection.

Source - Wikipedia

This provides lesser overheads than other methods of communication like HTTL polling and HTTP Long Polling. This is mainly made possible by keeping a connection open, thereby allowing easy back-and-forth transfer of messages from the client to the server.

Socket.IO is an open-source library that enables low-latency, bidirectional and event-based communication between a client and a server. It is built on top of the WebSocket protocol and provides additional guarantees like a fallback to HTTP long-polling or automatic reconnection.

This is extremely simple to use with their library available for Android, having multiple articles online to help you with the same. There are libraries available for your server as well, supporting all major languages. This also provides a clean admin UI to help you monitor and track your communication infrastructure.

The only disadvantage with sockets is that keeping a connection open comes at a cost, which is a call you'll have to take based on your requirements.

Firebase Cloud Messaging - FCM

Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably send messages at no cost. Yes, your read that right, there's no cost.

Using FCM, you can notify your app that new data/ information updates are available to sync. You can send notifications to drive user engagement and retention, and a lot more.

If you're working with apps for multiple platforms like Android, ios and the web, thankfully even this is handled by FCM.

Read up more about FCM's Architecture - https://firebase.google.com/docs/cloud-messaging/fcm-architecture

Key Functionalities

  • Send notifications and data messages (without triggering a notification i.e. silently communicate) to the client app.
  • Target a single device, a group of devices, or devices subscribed to a specific topic.
  • Send messages from the client app to the server.

Firebase Cloud Messaging is extremely simple to implement, using the guide available over here and since this is developed by Google, this provides a very high message delivery percentage. FCM documentation is a good place to get started for implementing downstream communication to your app.

Disadvantages

FCM does have restrictions on the number of (high-priority) messages that can be sent to the app per minute/hour/day based on how the users interact with your app. You can read more about this over here.

End Words

We previously employed MQTT in our app to deliver messages from our backend. Using firebase events and backend logs, we noticed that we were getting a message delivery rate of around 60% in production, indicating that over 40% of all messages sent to the broker were lost and not delivered to the app.

To avoid this, we did a POC on using FCM for downstream communication and noticed that our delivery rate jumped to over 80% within the first few days. We're still working on improvements to make this more robust, but from our tests, we see that FCM is the way to go with Android, especially since this is developed and recommended by Google.

The cherry 🍒 on the cake is that moving to FCM meant $0 to AWS to maintain our MQTT broker.

Hope you liked this article, if you have any questions please do not hesitate to reach out in the comments. Thanks ✌️

Citations

  1. MQTT. (2022, October 25). In Wikipedia. https://en.wikipedia.org/wiki/MQTT
  2. WebSocket. (2022, November 6). In Wikipedia. https://en.wikipedia.org/wiki/WebSocket