A JBoss Project
Red Hat

Aerogear Guides Tutorials to help get you off and running.

FCM Push Notifications with AeroGear's UnifiedPush Server

The following step-by-step guides, give you an introduction on how to use the AeroGear UnifiedPush Server for sending Push Notifications to your own Android Apps. You will need a Google account to use Firebase services, and can use either a real Android device or the emulator to test. So, let’s get started:

Obtaining Firebase Cloud Messaging Credentials

Before the Android application is able to receive the notifications, you must set up access to Firebase Cloud Messaging. Luckily, this is both easy and free to do, and does not require much setup. As with iOS, you are only able to test out your push notifications in a real device. This section shows you how to obtain the credentials necessary to set up Firebase Cloud Messaging for your app, including:

  • the Server key

  • the Sender ID

  • the google-services.json file containing the credentials required to connect your app to Firebase and Google services.

Project Setup and App Registration using the Firebase Console

First, register with the Firebase Cloud Messaging (FCM) platform, formerly known as Google Cloud Messaging (GCM). You need a Google Account to do this. Start by opening the Firebase Console.

  1. If you haven’t created a project, click Create New Project:

    Create New Project

  2. Now give your new project a name:

    New Project Name

  3. Once the project has been created you will be taken to the Overview screen. From there click the Settings icon located next to the project name in the sidebar, and in the pop-up menu click Project Settings.

    Project Number

  4. On the Project Settings screen, switch to the Cloud Messaging tab, where you can find the Server key and Sender ID (known in GCM as Project Number).

    Retrieve Credentials

  5. As the final step of the setup procedure, you need to download the google-services.json file. To do this, first navigate to the Overview screen and click on Add App (If you have no apps connected to FCM yet, select the option to Add Firebase to your Android app).

    Add Firebase to your app

  6. In the pop-up window enter the Package name of your app and then click the Add app button. This generates the google-services.json file that needs to be built into your app binary. Download the JSON file and save it. To close the pop-up window, click Continue and then Finish on the following screen.

    Download google-services.json

To re-download the google-services.json file, navigate to the Project Settings screen, then switch to the General tab, choose the desired app and click the google-services.json download button.

Now that Google is ready to accept and deliver our messages, we are ready to setup the UnifiedPush server.

The AeroGear UnifiedPush Server

With all the Google work being done, we are now ready to setup the UnifiedPush Server, so that it can be used to connect to FCM for later message sending.

In the Wizard after you create a PushApplication, click the Add Variant button and fill out the Android options. You will want to use the Server Key and Sender ID obtained from the Firebase Console in their appropriate fields:

Android Variant Options

Afterwards you will see some code snippets, containing the Variant ID and Secret, that you can use in your Android application for the registration of the device, running your app:

Android Variant Details

Clicking on the appropriate tab, you can choose between Android and Cordova snippet!

Android Studio

The server is now configured. Let’s move to Android Studio and create an Android application that will use the AeroGear Android library to connect to the UnifiedPush server and start receiving notifications.

Your first Android/Push App

Now that the UnifiedPush server is up and running, time to create a sample application that will exercise AeroGear’s Android Push library support. For the purpose of the guide we will use the Android Studio with the ADT tools installed, but you are free to use any IDE that includes Android Gradle support.

Let’s get started!

Creating the application

Fire up Android Studio IDE and choose 'Start a new Android Studio project'. Fill the 'Application Name' field with the name 'PushApplication' and the 'Package Name' with com.push.pushapplication.

Android Studio - New Project

The Minimum SDK option for the AeroGear Android Push >= 2.0 is API 16 (Android 4.1 - Jelly Bean) so select this option if not selected.

Android Studio - New Project

Continue through the wizard by accepting the default options presented. Once finished, Android Studio would have generated a sample Android project with a default 'MainActivity' and the layout file for further editing.

Android Studio - Project Overview

We will use the TextView component that the wizard conveniently created for us to display the message payload. But in order to be able to be referenced in our code we need to give the component first an 'id'. Simple append in the 'TextView' declaration:

<TextView
	android:id="@+id/label"
	...

Before we start code, let’s add the AeroGear Android Push library as a dependency

Open the build.gradle app file and add the AeroGear Android Push dependency:

dependencies {
    ...
    compile 'org.jboss.aerogear:aerogear-android-push:4.+'
}

Now that we have the project set up, time to configure it to receive Push notifications. We will start first with the registration of the application with the UnifiedPush server.

Registration with the UnifiedPush server

First of all, you need create a file push-config.json in app/src/main/assets folder with the Unified Push Informations

Ensure that you put valid values on those params, otherwise you would be unable to register and receive notifications from the UnifiedPush server. Invalid configuration params are a very common source of problems, so please revisit them if you are experiencing problems.
{
  "pushServerURL": "pushServerURL (e.g http(s)//host:port/context)",
  "android": {
    "senderID": "senderID (e.g Google Project ID only for android)",
    "variantID": "variantID (e.g. 1234456-234320)",
    "variantSecret": "variantSecret (e.g. 1234456-234320)"
  }
}

The entry point for registration is the RegistrarManager. This is a factory of different implementations of the PushRegistrar interface which contain the actual registration/unregistration methods.

By default, the method will return an implementation that supports registration with the UnifiedPush server. Having the flexibility of a factory method, allows us in the future to expand it to support other different message brokers under a common messaging interface.

Since the registration setup is an one-step process not bound to any Android 'Activity', let’s encapsulate it in a subclass of an Android Application.

Create a new class, name it PushApplication and paste the following code:

package com.push.pushapplication;

import android.app.Application;

import org.jboss.aerogear.android.unifiedpush.PushRegistrar;
import org.jboss.aerogear.android.unifiedpush.RegistrarManager;
import org.jboss.aerogear.android.unifiedpush.fcm.AeroGearFCMPushJsonConfiguration;

public class PushApplication extends Application {

    private static final String PUSH_REGISTAR_NAME = "myPushRegistar";

    @Override
    public void onCreate() {
        super.onCreate();

        RegistrarManager.config(PUSH_REGISTAR_NAME, AeroGearFCMPushJsonConfiguration.class)
                .loadConfigJson(getApplicationContext())
                .asRegistrar();

    }

    // Accessor method for Activities to access the 'PushRegistrar' object
    public PushRegistrar getPushRegistar() {
        return RegistrarManager.getRegistrar(PUSH_REGISTAR_NAME);
    }

}

The setup of the registration happens on the onCreate lifecycle method called when Android first initializes your application. It will create (and store) a PushRegistrar object based on push-config.json informations declared earlier. This object together with a name (it can be anything you choose) are passed as params on the config factory method to create the PushRegistrar object.

Don’t forget to configure the Application class in AndroidManifest.xml
<application
    android:name=".PushApplication"
    ...
/>

We are now ready to call PushRegistrar:register method to register our device in the UnifiedPush server. Switch to the MainActivity class and replace the existing onCreate method with the following code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    PushApplication application = (PushApplication) getApplication();
    PushRegistrar pushRegistar = application.getPushRegistar();
    pushRegistar.register(getApplicationContext(), new Callback<Void>() {
        @Override
        public void onSuccess(Void data) {
            Log.d(TAG, "Registration Succeeded");
            Toast.makeText(getApplicationContext(),
                    "Yay, Device registered", Toast.LENGTH_LONG).show();
        }

        @Override
        public void onFailure(Exception e) {
            Log.e(TAG, e.getMessage(), e);
            Toast.makeText(getApplicationContext(),
                    "Ops, something is wrong :(", Toast.LENGTH_LONG).show();
        }
    });
}

That is all what is needed to register with the UnifiedPush server!

That we didn’t have to write any code to register the device with FCM. The library takes care off all the plumbing to register the device with FCM, obtain the registrationId and submit it to the UnifiedPush server.
Push Application - Main Screen
If you don’t see the Registration Succeeded popup, means that an error has occurred during the registration. Switch to the LogCat console in Android Studio to locate the exception and act accordingly.

Receiving notifications

The standard practice for an Android application to be able to receive notifications, is the developer to edit App’s manifest to enable the appropriate FCM permissions and also implement an Android BroadcastReceiver that is called when a new notification arrives. Typically the receiver includes code that consumes the message and displays the payload in the Notification Manager. AeroGear library already provides an implementation of a broadcast receiver that a developer can use, AeroGearFCMMessageReceiver, but instead of displaying in the notification manager it delegates the consumption of the message to those that have expressed interest.

A developer implements the MessageHandler interface and registers it with the library in order to be called when a new notification arrives. You can have multiple components listening for incoming notifications and the library will call each one in tandem upon arrival. To register a component, simple call the RegistrarManager:registerMainThreadHandler method if you want your component to be called on the main thread or Registrations:registerBackgroundThreadHandler method if you want to be called on a background thread. In the absence of any registered listeners, the library will call a default MessageHandler that you have defined in your app’s manifest.

Typically you register a default MessageHandler that displays the notification in the NotificationManager when your application is stopped or in the background and possible a MessageHandler that consumes the payload when your application is active.

Nothing prevents you to send a notification in the Notification Manager when your application is active; the mechanism is there for your convenience.

Let’s return to our example. We are going to register a default MessageHandler that will display the received notification and show in the Notification Manager. First we need to edit the app’s manifest.

Configuring App’s manifest

Open the AndroidManifest.xml file and below the <manifest> entry add the necessary permissions to enable our app to receive messages:

<manifest
....
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.GET_ACCOUNTS" />
...

Let’s register now our own MessageHandler inside of the <application> entry:

<application
...
    <meta-data android:name="DEFAULT_MESSAGE_HANDLER_KEY" android:value="com.push.pushapplication.NotifyingHandler"/>
</application>
Notice the DEFAULT_MESSAGE_HANDLER_KEY parameter is used to pass the name of the default MessageHandler class that will be called once the notification is received.

Handling notification

Create a new class, name it NotifyingHandler and paste the following code:

package com.push.pushapplication;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;

import org.jboss.aerogear.android.unifiedpush.MessageHandler;
import org.jboss.aerogear.android.unifiedpush.fcm.UnifiedPushMessage;

public class NotifyingHandler implements MessageHandler {

    public static final int NOTIFICATION_ID = 1;
    private Context context;

    public static final NotifyingHandler instance = new NotifyingHandler();

    public NotifyingHandler() {
    }

		@Override
    public void onMessage(Context context, Bundle bundle) {
        this.context = context;

        String message = bundle.getString(UnifiedPushMessage.ALERT_KEY);

        HelloWorldApplication application = (HelloWorldApplication) context.getApplicationContext();
        application.addMessage(message);

        notify(bundle);
    }

    private void notify(Bundle bundle) {

        NotificationManager mNotificationManager = (NotificationManager)
                context.getSystemService(Context.NOTIFICATION_SERVICE);

        String message = bundle.getString(UnifiedPushMessage.ALERT_KEY);

        Intent intent = new Intent(context, MainActivity.class)
                .addFlags(PendingIntent.FLAG_UPDATE_CURRENT)
                .putExtra(UnifiedPushMessage.ALERT_KEY, message);

        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
                .setAutoCancel(true)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(context.getString(R.string.app_name))
                .setStyle(new NotificationCompat.BigTextStyle().bigText(message))
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
                .setContentText(message);

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }

}

AeroGear calls the onMessage callback method when a new notification arrives. Here we simply extract the message payload and we use the platform’s notification manager to display it.

Since we also want the MainActivity to be able to receive the notification and update the TextView with the payload, we need to register it with the library. To do so the Activity, as with the NotifyingHandler class we saw earlier, must implement the MessageHandler interface. In the declaration of the Activity simple append the following:

public class MainActivity extends Activity implements MessageHandler {

and paste the following code:

@Override
protected void onResume() {
    super.onResume();
    RegistrarManager.registerMainThreadHandler(this); // 1
    RegistrarManager.unregisterBackgroundThreadHandler(NotifyingHandler.instance);
}

@Override
protected void onPause() {
    super.onPause();
    RegistrarManager.unregisterMainThreadHandler(this); // 2
    RegistrarManager.registerBackgroundThreadHandler(NotifyingHandler.instance);
}

@Override
public void onMessage(Context context, Bundle bundle) {
    // display the message contained in the payload
    TextView text = (TextView) findViewById(R.id.label);
    text.setText(bundle.getString(UnifiedPushMessage.ALERT_KEY)); // 3
}

@Override
public void onDeleteMessage(Context context, Bundle message) {
    // handle GoogleCloudMessaging.MESSAGE_TYPE_DELETED
}

@Override
public void onError() {
    // handle GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
}

Notice that we use the standard Activity life-cycle methods onResume to register[1] and onPause to unregister[2] itself for handling the notification. Finally, in the onMessage callback method[3] we simple extract the message payload and update the TextView.

Push Application - Message received

Metrics

Optionally the Android SDK supports sending metrics to UPS. Metrics can be used to view how many users have received/readed/opened the message. This can be important information if you want to know how well your messages are received by your application users.

UPS sends an unique ID for every push message by default all we have to do is send this ID back to UPS when the app was opened using the message:

@Override
public void onMessage(Context context, Bundle bundle) {
    // Do something with the message
    String message = bundle.getString(UnifiedPushMessage.ALERT_KEY);
    ...

    // Send metrics about the message received
    PushApplication application = (PushApplication) getApplication();
    AeroGearFCMPushRegistrar pushRegistar = (AeroGearFCMPushRegistrar) application.getPushRegistar();

    String pushMessageId = bundle.getString(UnifiedPushMessage.PUSH_MESSAGE_ID);
    UnifiedPushMetricsMessage pushMetricsMessage = new UnifiedPushMetricsMessage(pushMessageId);

    pushRegistar.sendMetrics(pushMetricsMessage, new Callback<UnifiedPushMetricsMessage>() {
        @Override
        public void onSuccess(UnifiedPushMetricsMessage unifiedPushMetricsMessage) {
            Log.d(TAG, "Metrics for : " + unifiedPushMetricsMessage.getMessageId() + " successfully sent");
        }

        @Override
        public void onFailure(Exception e) {
            Log.d(TAG, e.getMessage(), e);
        }
    });
}

Now that we have our application up an running time to send messages using the AeroGear UnifiedPush Server!

Send a Push Notification

Now that we have the sample application running, it is time to use the AeroGear UnifiedPush Server for delivering a Push Notification message.

Simple Sender

Log into the administration console of the UnifiedPush server and click on the "Send Notification" button on the desired PushApplication and write a message in the text field. Once done, hit the 'Send Push Notification':

Send Notification

If all goes well, you should see the message payload being displayed on screen:

Message Receiced-Active

Now click the 'Home' button to return to Android Home Screen and send another push message. You should see the notification being displayed in the Notification Manager:

Message Receiced-InActive

You are done

That’s all you need to use the AeroGear project for sending and receiving Push Notifications from Android.

Last-Minute Notes

Since we interface with the Android devices via Firebase Cloud Messaging, we still have a few things to keep in mind regarding the messages we send:

  • Messages can be maximum 4kb

  • Messages can be throttled

  • Google will hold messages in queue for 28 days if the intended device is unavailable for delivery, after which they will be discarded

For a more thorough explanation of the FCM system and queue, check out the Firebase Cloud Messaging Documentation.

Android Troubleshooting

This troubleshooting guide takes as a pre-requesite that you have carefully followed the instructions in the Android tutotial.

We’ve documented some of the common configuration failures in this guide. If you are having issues which we don’t cover or otherwise need help, feel free to post to our link:user list.

Issue: Registration fails with the error "SERVICE_NOT_AVAILABLE"

Problem description

When you call PushRegistrar.register onFailure is called with the exception message "SERVICE_NOT_AVAILABLE".

Answer

There are several causes for this issue. The easiest solution is that the FCM registration service had an error and you should retry at a later date. However, there are also several code/environment issues to check.

  1. You do not have Google Play Services installed on your device.
    If you are running an emulator, make sure you are using a Google APIs Target higher than Android 4.2. If you are using a device, make sure you are using a Google experience device and not an Amazon Fire or AOSP device.

  2. Make sure the permission and uses-permission tags in AndroidManifest.xml have the correct package.

    <permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE"
           android:protectionLevel="signature" />
    <uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
  3. Make sure you have the correct permissions available.

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    
    <permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE"
           android:protectionLevel="signature" />
    <uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
  4. Make sure your device’s clock is set correctly. Some people on Stack Overflow have reported this issue.

Issue: Registration fails with INVALID_SENDER

Problem description

When you call PushRegistrar.register onFailure is called with the exception message "INVALID_SENDER".

Answer

Make sure the SenderID matches the project number from the Google API Console. This will be an all numeric string.

I have another Issue

If you are having issues which we don’t cover or otherwise need help, feel free to post to our mailing list. Also, messages in logcat may give useful results from Google or StackOverflow.

redhatlogo-wite