Push Notifications – a bigger picture

Many applications we create require the ability to send push notifications. Sometimes we are the ones who made the client and the backend side as well. The available tutorials are helpful but not always entirely clear; we met quite a few challenges. Let’s look at a specific example.

–          We’d like to send a push notification from our own backend.

–          To our users one by one, not to channels.

–          Many notifications

Now, I’m going to show you an example that has every piece in its place for us to be able to send push notifications in this scenario.

push notifications

Tech used

First, let’s take a look at the service provider and the technologies we decided to use.

Firebase is pretty straight forward; it’s Google’s own, it is compatible with both iOS and Android, and it is capable of sending a large number of messages. Plus, many service providers use Firebase in the background.

We connected to Firebase with XMPP. It has many advantages over HTTP API, for us the most important is its ability to handle a large number of messages.

On the backend we used Akka with Java. Akka helps coping with the challenges that surface when writing multithreaded parallel applications, e.g. things that occur when resending a notification.

First, we created the mobile app. You can send test messages from the FCM console, so we can check whether receiving the messages works. After that we will write the backend according to the demands Firebase makes (look at the backend section to see more).

So we will write „Trusted environment” and the android app of this figure.


If you have a Google account, you can register with it onto Firebase. It’s pretty simple and straightforward, so I’m not gonna dive into the details.


After we’ve created a new app with Android studio, we need to add the FCM dependencies to it. Google helps us with this step as well, we only need our app’s package name. With the package name, we need to create a project in Firebase, then we need to follow the steps written in there.

  1. Dowload the google-services.json and copy it
  2.  Add the dependencies, can do this in the gradle file.

  • Implement the android service that receives the push notifications. here is the simplest implementation:

  • Register the service within the AndroidManifest.xml. It’s important that it’s within the <application> XML tag.

  • Before the Android app can receive a message, it needs to have a token. This token functions like an address, and to this address can we send a message from the backend. The token is provided by the FirebaseInstanceIdService class. We need to create a subclass and that will send the token to the proper location. In our example that place will be a text box on the screen. Getting the token:

We use an observer design pattern, because our token will arrive in an asynchronous way.

  • We subscribe as an observer in MainActivity, it displays the token, too.

With that, our Android app is ready to receive the Push notification. We can try it from the FCM console: starting the Android app, it displays the token, in the FCM console, we can send a push notification by clicking on GROW / Notifications / NEW MESSAGE. Choose single device and copy the FCM token in:



There are some examples online, but these all end after the message is recieved on the Android device. Google, however, has more expectations from the backend.

Before you can write client apps that use Firebase Cloud Messaging, you must have a server environment that meets the following criteria:


  • Able to communicate with your client.
  • Able to send properly formatted message requests to the FCM server.
  • Able to handle requests and resend them using exponential back-off.
  • Able to securely store the server key and client registration tokens. Note: never include the server key in any client code.
  • For XMPP, the server must be able to generate message IDs to uniquely identify each message it sends (FCM HTTP connection server generates message IDs and returns them in the response). XMPP message IDs should be unique per sender ID.

There are some more limitations in the documentation:

–          There is a maximum number for pending messages: 100. If we reach this number, we have to wait until they are finished to send more.

–          You have to manage CONNECTION_DRAINING. FCM can signal you anytime that it will terminate the connection. In this case, we have to open a new one, and not attempt to send any more messages on the connection in question.


Violating theses rules can get you excluded from FCM. Unfortunately the tutorials online do not discuss how to implement these limitations. This is what I am hoping to fix with this post, hope it will be useful!

I have mentioned in the beginning that we will be dealing with Akka. The actors that need to be created are listed in this figure:


We divide the limitations between the components. It’s their responsibility to abide by the rules.

  • CcsClient: communicates with the FCM server using appropriately formatted messages. We use the lib called smack for this.
  • FcmActor: dealing with CONNECTION_DRAINING. If a connection is closing to an end, it opens a new connection. Makes sure there is always one active connection open.
  • CcsMessageStagingActor: makes sure we have at most 100 pending push notifications. And, if there is a new space open, sends the next message in line.
  • PushNotificationErrorHandlerActor: involved in resending. However many times we have tried to send a push notification, we keep in a persistent place (eg. database). Accordingly, it schedules resending exponentially:  2^n seconds later (wheren n equals the number of times we have tried to send this specific message.)
  • PushNotificationStepDoneActor: Saves about a push notification that it was sent successfully.
  • AkkaScheduler: According to FCM’s documentation, we should receive a response within 30 seconds (ACK or NACK) to a sent push notification. If that doesn’t happen though, we don’t wait longer. This is why we use a scheduler: it signals to CcsMessageStagingActor every 30 seconds to clean out of the line any push notifications that are stuck.


Let’s look at the backend’s implementation. The entire implementation can be downloaded, we only look at the important or interesting points here.


Let’s create an akka project with the sbt new command. We need to add the akka and smack dependencies to the build.sbt.

With the FCM, we communicate with json messages sent through the XMPP. This means that the json we want to send needs to be embedded in the XML. Creating this XML, sending it to the FCM and processing the FCM’s response is the job of CcsClient.

Then follows the implementation of the FcmActor. The important method here is handleControlMessage(), this handles CONNECTION_DRAINING. In case of this message, we open a new active FCM connection.

In CcsMessageStagingActor we collect the push notifications that are waiting to be sent or are pending. We keep sending them until we reach 100 pending ones.

And finally, let’s look at the code handling the exponential backoff resend function. This can be found in PushNotificationErrorHandlerActor. So we know when to try to resend a message, we need to take note of how many times we’ve already tried to send it.

It is not advised to choose a number greater than 15 for MAX_RETRIES, because 2^15 sec is about 18 hours. If this is not enough time for the FCM server to accept the message, there is a good chance it won’t ever do it.

My Github links:




Similar, though a bit outdated blog post:


Concrete backend implementation, though not as comprehensive (e.g missing „resend with exponential back-off”)


Gábor Pap

Gábor Pap

I'm an Akkaountable guy. 🙂

Latest posts by Gábor Pap (see all)