Write a post

Real-time Notifications: Build a Firebase App-to-App Notification System

Published Jan 12, 2017Last updated Jan 18, 2017
Real-time Notifications: Build a Firebase App-to-App Notification System

This tutorial covers what it takes to develop a Firebase app with a custom real-time notification system. We will be building an app-to-app notification system using Firebase leveraging on its real-time capability.

What we want to achieve

We want to be able to directly notify another device of a new notification without having to implement a server-side backend to send push notifications. We will be using the Firebase database to achieve that.

What we're going to build

  • We are going to create a notifications node on our Firebase database.
  • Every user will listen to their notifications node for on child_added events. We will have /notifications/user_id/ (notification-objects).
  • Then write a service in our Android app that listens to the logged in user’s notification node for new data.
  • When a new notification is added against the user’s ID, we then show an Android notification to alert the user on the app.

firebase real-time notification

So lets start by creating a notification object and then a method that handles adding of notification to the notifications node. Please note let this method be accessible across your entire app to avoid duplication

public class Notification {

    String user_id;

    public String getUser_id() {
        return user_id;
    }

    public void setUser_id(String user_id) {
        this.user_id = user_id;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(long timestamp) {
        this.timestamp = timestamp;
    }

    public long getStatus() {
        return status;
    }

    public void setStatus(long status) {
        this.status = status;
    }

    String message;
    String description;
    String type;
    long timestamp,status;

    public Notification() {
    }


    @Exclude
    public Map<String, Object> toMap() {
        HashMap<String, Object> result = new HashMap<>();
        result.put("message", message);
        result.put("description", description);
        result.put("timestamp", ServerValue.TIMESTAMP);
        result.put("type",type);
        result.put("status",status);
        return result;
    }
}

And then we create the method as seen below:

  public static void sendNotification(String user_id,String message,String description,String type){
        DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("notifications").child(user_id);
        String pushKey = databaseReference.push().getKey();

        Notification notification = new Notification();
        notification.setDescription(description);
        notification.setMessage(message);
        notification.setUser_id(user_id);
        notification.setType(type);

        Map<String, Object> forumValues = notification.toMap();
        Map<String, Object> childUpdates = new HashMap<>();
        childUpdates.put(pushKey, forumValues);
        databaseReference.setPriority(ServerValue.TIMESTAMP);
        databaseReference.updateChildren(childUpdates, new DatabaseReference.CompletionListener() {
            @Override
            public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
                if(databaseError == null){

                }
            }
        });
    }

So we just called the method above and passed the necessary parameters.

And please note, verify that the logged in user is not the sender so as to avoid sending the notification to the same user.

 sendNotification(
            receiver_id, /*who the notification is meant for*/
            "Chat message from " /*Message to be displayed on the notification*/
            "New chat message", /*Message title*/
            "chat_view" /*Notification type, You can use this to determine what activities to stack when the receiver clicks on the notification item*/
   );

Implementing a Notification Service

What's next is to create our notification service. Please ensure this service is running at all time.

To avoid multiple notifications, we have to update the notification status to 1 after firing a notification.

public class FirebaseNotificationServices extends Service{

    public FirebaseDatabase mDatabase;
    FirebaseAuth firebaseAuth;
    Context context;
    static String TAG = "FirebaseService";

    @Override
    public void onCreate() {
        super.onCreate();
        context = this;



        mDatabase = FirebaseDatabase.getInstance();
        firebaseAuth = FirebaseAuth.getInstance();

        setupNotificationListener();
    }



    private void setupNotificationListener() {

        mDatabase.getReference().child("notifications")
                .child(firebaseAuth.getCurrentUser().getUid())
                .orderByChild("status").equalTo(0)
                .addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                if(dataSnapshot != null){
                    Notification notification = dataSnapshot.getValue(Notification.class);

                    showNotification(context,notification,dataSnapshot.getKey());
                }
            }

            @Override
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                Utilities.log("onChildChanged",dataSnapshot);
            }

            @Override
            public void onChildRemoved(DataSnapshot dataSnapshot) {
                Utilities.log("onChildRemoved",dataSnapshot);
            }

            @Override
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {
                Utilities.log("onChildMoved",dataSnapshot);

            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Utilities.log("onCancelled",databaseError);
            }
        });


    }

 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return Service.START_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    private void showNotification(Context context, Notification notification,String notification_key){
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(notification.getDescription())
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setContentText(Html.fromHtml(notification.getMessage()
                ))
                .setAutoCancel(true);

        Intent backIntent = new Intent(context, MainActivity.class);
        backIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        Intent intent = new Intent(context, FriendsView.class);

        /*  Use the notification type to switch activity to stack on the main activity*/
        if(notification.getType().equals("chat_view")){
            intent = new Intent(context, FriendsView.class);
        }


        final PendingIntent pendingIntent = PendingIntent.getActivities(context, 900,
                new Intent[] {backIntent}, PendingIntent.FLAG_ONE_SHOT);


        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addParentStack(MainActivity.class);

        mBuilder.setContentIntent(pendingIntent);


        NotificationManager mNotificationManager =  (NotificationManager)context. getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(1, mBuilder.build());

        /* Update firebase set notifcation with this key to 1 so it doesnt get pulled by our notification listener*/
        flagNotificationAsSent(notification_key);
    }

    private void flagNotificationAsSent(String notification_key) {
        mDatabase.getReference().child("notifications")
                .child(firebaseAuth.getCurrentUser().getUid())
                .child(notification_key)
                .child("status")
                .setValue(1);
    }

}

Wrapping up

Access the full project on this Github Repo.

And that’s it. We can now make an app-to-app notification using Firebase without implementing a server backend.

Discover and read more posts from Sunday Akinsete
get started
Enjoy this post?

Leave a like and comment for Sunday

3
6
Java Tips & Tricks: Building OSGi WABs with Gradle
Building a Real-time Chat App with Angular 2 and deepstream
Using If - Else Statement