Push Notifications with Fcm and Java Admin sdk for firebase

Push Notifications with Fcm and Java Admin sdk for firebase

According to wikipedia Push notifications[1] are small messages that can reach audiences anywhere and anytime. While pop-ups appear only when audiences are on the site they belong to, push messages are independent of sites. They are associated with web browsers and apps.

Push technology, or server push, is a style of Internet-based communication where the request for a given transaction is initiated by the publisher or central server). It is contrasted with pull/get, where the request for the transmission of information is initiated by the receiver or client).

Almost all applications out in the world have a notification requirement. There are numerous providers of push notification service but isn’t it great to use the tools provided by the developers of the android OS? yes that’s it so lets brace ourselves for some cool coding session.

Getting started

In order to follow along with this piece you will need the following 1.A firebase project. 2. A java web project (I will use springboot app hosted in heroku) 3. Android app project

Assumptions 1. You have basic understanding of android applications. 2. You have understanding of java web apps.

Android App Setup

  1. create a new android project or use existing project.
  2. Add firebase to the project and configure fcm dependencies (here is a guide )
  3. Upto this point you have an app configured with fcm dependencies and an fcm service to handle notification events.

Java web app

This is where we are going to handle connection to the firebase project, storage of device generated tokens (used in identifying of a device in order to send notification to a specific phone), sending of actual messages.

connect to firebase project

On your firebase project console go to settings and click on service accounts tab. Notice the admin sdk section select Java as your language of choice. click on generate new private key. (you want to keep this file safely because any unauthorized access to it can cause significant damage to your account).

we will use this file to authorize our java web app to communicate with the firebase project .

In your springboot project root create a directory files. add the downloaded file to this folder . we want initiate google authentication only once when our project is started so do as below .

In the main file extend commandline runner and initiate the authentication.

@SpringBootApplication
public class FcmDemo implements CommandLineRunner {

   public static void main(String[] args) {
      SpringApplication._run_(FcmDemo.class, args);
   }

   @Override
   public void run(String... args) throws Exception {
      try {
         Init._initAdminSdk_();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}</span>

initAdminSdk is a static function in the Init public class

public class Init {

    public static void initAdminSdk() throws IOException {

        String filepath = "files/your file name.json";
        GoogleCredentials credentials = GoogleCredentials._fromStream_(new FileInputStream(filepath));
        FirebaseOptions options = new FirebaseOptions.Builder()
                .setCredentials(credentials)
                .setDatabaseUrl("your firebase db url")
                .build();

        FirebaseApp._initializeApp_(options);
    }
}</span>

We have now connected our server to our firebase project.

Creating and saving device tokens

When a user installs your app fcm will generate a device token that is used to identify this device in order to send notifications . You have 2 ways to access this token . I will go with getting it when it is first created. in the Fcm service you created while setting up you can get this by overriding onNewToken.

In this code snippet I am getting the token and saving it temporarily on the app . Assuming a user has just installed the app and we dont have their Id or any other detail to know them.

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    public MyFirebaseMessagingService() {
    }</span><span id="4422" class="de js ig bo jt b fp jx jy jz ka kb jv r jw">_/**
 * 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) {
    Data._setFcmToken_(getSharedPreferences(HomeActivity._PREFS_FCM_, HomeActivity._MODE_PRIVATE_), token);

}</span>

After a user has completed sign up and we have given them our apps identification we can use this to store their ids . so lets send this app defined userId and fcm device Id and store to our server.

Here is a springboot controller that recieves and stores the ids on our database

@RestController
@RequestMapping("/fcm")
public class FcmController {

    @Autowired
    private FcmService fcmService;

    @PostMapping("/save-token")
    private ResponseEntity<String> saveToken(@RequestBody  UserToken userToken){
        UserToken userToken = fcmService.saveDeviceToken(userToken);</span> <span id="a49a" class="de js ig bo jt b fp jx jy jz ka kb jv r jw">return ResponseEntity._status_(200).body("token saved successfully");
    }</span>

Sending notifications from our backend

For our use cases we want to send targeted notifications to a specific user . so we will first get the userId defined by the app then get the registered device token associated with this ID .

for my case DataMessage is my own defined object holding the various notification attributes that I want to send. on success this returns a string pointing to our fcm message location.

public  String sendMessage(DataMessage dataMessage) throws FirebaseMessagingException {

    Notification.Builder builder = Notification._builder_();
    Message message = Message._builder_()
            .setNotification(builder.build())
            .putData("title", dataMessage.getTitle())
            .putData("body", dataMessage.getMessage())
            .setToken(dataMessage.getDeviceToken())
            .build();
    return FirebaseMessaging._getInstance_().send(message);
}</span>

Recieving and Showing Notifications on The app

The last step is to show the notification to the user and this is done from the fcm Service earlier created. Here NotificationData is my own defined object to setup the notification data. From android 8 you will need to use notification channels in order to successfully show the notifications.

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    public MyFirebaseMessagingService() {
    }</span><span id="2bca" class="de js ig bo jt b fp jx jy jz ka kb jv r jw">// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {

    NotificationData notificationData = new NotificationData();
    notificationData.setNotificationId(nId);
    notificationData.setChannelId("nChanell");
    notificationData.setIcon(R.drawable._notification_icon_);
    notificationData.setNotificationTitle(remoteMessage.getData().get("title"));
    notificationData.setNotificationContent(remoteMessage.getData().get("body"));
    notificationData.setActivityIntent(new Intent(getApplicationContext(), Notification.class));
    NotificationUtil._showNotification_(getApplicationContext(), notificationData);

}
}</span><span id="dc66" class="de js ig bo jt b fp jx jy jz ka kb jv r jw">// Utility class to show the notifications 
public class NotificationUtil {

  public static void showNotification(Context context, NotificationData notificationData){

      // Create an explicit intent for an Activity in your app
      PendingIntent contentIntent =PendingIntent._getActivity_(context,0,notificationData.getActivityIntent(),0);

      NotificationCompat.Builder builder = new NotificationCompat.Builder(context, notificationData.getChannelId())
              .setSmallIcon(notificationData.getIcon())
              .setContentTitle(notificationData.getNotificationTitle())
              .setDefaults(Notification._DEFAULT_SOUND_)
              .setContentText(notificationData.getNotificationContent())
              .setPriority(NotificationCompat._PRIORITY_MAX_)
              .setContentIntent(contentIntent)
              .setAutoCancel(true);

      NotificationManagerCompat notificationManager = NotificationManagerCompat._from_(context);
      notificationManager.notify(notificationData.getNotificationId(), builder.build());

   }</span>

Image for post

Image for post

We have successfully sent a notification from our server to a user using fcm and springboot.

Next Steps

  1. Learn more about message types and how fcm and firebase handles them.
  2. Learn more on securing your google credentials and springboot apps
  3. send topic messages, create subscription messages e.tc