Saturday, April 20, 2024
HomeAndroidAndroid Push Notifications using Firebase Cloud Messaging (FCM)

Android Push Notifications using Firebase Cloud Messaging (FCM)

-

In this tutorial, we are going to discuss about Implementing Android Push Notifications using Firebase Console. In the upcoming tutorials we will be discussing about more advanced features of FCM using our own server instead of Firebase Console.

The complete code for Android Push Notifications using FCM can be cloned/downloaded from Github Link

(Note: In order for the above code to work, you need to replace your google-services.json file generated when firebase proj is created.)

1.    Adding Firebase to our Android Push Notifications Project:

a. Firstly we will be adding Firebase to our Android Push Notifications Project. Head on to the Firebase Console and click on Create a New Project.android push notifications creating project

b. Next you will be shown the following Firebase Overview tab.android push notifications - firebase overview image

c.       Since we are trying Firebase to our Android App, we will be clicking on Add Firebase to Android App.

d.       Next you will be shown a screen which will be asking you for your Android Package name which can be obtained from the manifest file.

To get the SHA1 key directly from Android Studio, you can refer to the following answer in stack overflow.

e.      After entering the required info and clicking on ADD APP we will be getting a json file which we will be placing in our project’s app folder.

android push notifications- adding google-services.json

f.       Now open the Project’s build.gradle file and include the google-services classpath to dependencies.

Now your project’s build.gradle looks similar to this:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

g.       Then open your module’s build.gradle ( by default it is app module’s build.gradle which is located in app folder) and add the apply plugin line at the bottom of the file to enable the Gradle Plugin as shown in the code below:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.3"
    defaultConfig {
        applicationId "com.coderefer.firebasecloudmessagingtutorial"
        minSdkVersion 15
        targetSdkVersion 20
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'

    //adding fcm
    compile 'com.google.firebase:firebase-messaging:9.6.1'
}
apply plugin: 'com.google.gms.google-services'

h.  Next we will be extending two services for our Firebase Cloud Messaging Android Push Notifications:

1.    FirebaseInstanceIdService: When your app is started for the first time, Firebase SDK generates a token which can be accessed by extending the above service. It is used to send target messages to single / group of devices.

As this token changes in certain cases like clearing the data, reinstalling app etc., we can access the token by calling FirebaseInstanceId.getToken(). When the token is refreshed, onTokenRefresh() will be called where we can send the new token to our server to register the device.

In this project, I’ve created a Custom class called CustomFirebaseInstanceIdService.java which extends FirebaseInstanceIdService which is mentioned below:

package com.coderefer.firebasecloudmessagingtutorial;

import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;

/**
 * Created by vamsi on 12-Oct-16 for Android Push Notifications tutorial
 */

public class CustomFirebaseInstanceIdService extends FirebaseInstanceIdService {


    private static final String TAG = "CustomFIIS";

    /**
     * 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.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(refreshedToken);
    }
    // [END refresh_token]

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // TODO: You could Implement this method to send token to your app server
        //  we neglect this for our current project.
    }
}

2.       FirebaseMessagingService: required to handle registration tokens’ creation and updation. This is called when a message is received to set the custom icon, custom ringtone.

Here I will be placing my custom ringtone in res>raw folder and write the following code extending FirebaseMessagingService to receive the following notification with custom notification and custom icon:

package com.coderefer.firebasecloudmessagingtutorial;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

/**
 * Created by vamsi on 12-Oct-16 for Android Push Notifications
 */

public class CustomFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "CustomFMS";

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // [START_EXCLUDE]
        // There are two types of messages data messages and notification messages. Data messages are handled
        // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
        // traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
        // is in the foreground. When the app is in the background an automatically generated notification is displayed.
        // When the user taps on the notification they are returned to the app. Messages containing both notification
        // and data payloads are treated as notification messages. The Firebase console always sends notification
        // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
        // [END_EXCLUDE]

        // TODO(developer): Handle FCM messages here.
        // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
        Log.d(TAG, "From: " + remoteMessage.getFrom());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
        }

        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
        sendNotification(remoteMessage.getNotification().getBody());
    }
    // [END receive_message]

    /**
     * Create and show Android Push Notifications containing the received FCM message.
     *
     * @param messageBody FCM message body received.
     */
    private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);
        long[] pattern = {500,500,500,500,500};

        Bitmap icon = BitmapFactory.decodeResource(getApplicationContext().getResources(),
                R.drawable.ic_stat_ic_notification);
        Uri customUri = Uri.parse("android.resource://com.coderefer.firebasecloudmessagingtutorial/" + R.raw.pikachu);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
        notificationBuilder.setSmallIcon(R.drawable.ic_stat_ic_notification);
        notificationBuilder.setLargeIcon(icon)
                .setContentTitle("FCM Tutorial")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setSound(customUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}

i.       Next I will be declaring the above two services in my Android Manifest file which will now look like follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.coderefer.firebasecloudmessagingtutorial">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <service
            android:name=".CustomFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>

        <service
            android:name=".CustomFirebaseInstanceIdService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>
    </application>

</manifest>

Now we have successfully integrated Android Push Notifications in our Project using Firebase Cloud Messaging. Now open your Firebase console and click on Notifications in the left panel and click on New Message

Type the message you want to send and you would be successfully sending the push notifications via FCM.

In the upcoming tutorials, I would be mentioning the Advanced version of FCM using server implementation, etc.

3 COMMENTS

  1. I got this error
    D/AndroidRuntime: Shutting down VM
    E/AndroidRuntime: FATAL EXCEPTION: main
    Process: pdfdownload.acesoft.com.finalnoti1, PID: 2931
    java.lang.RuntimeException: Unable to instantiate service pdfdownload.acesoft.com.finalnoti1.MyFirebaseInstanceIDService: java.lang.ClassNotFoundException: Didn’t find class “pdfdownload.acesoft.com.finalnoti1.MyFirebaseInstanceIDService” on path: DexPathList[[zip file “/data/app/pdfdownload.acesoft.com.finalnoti1-2/base.apk”],nativeLibraryDirectories=[/data/app/pdfdownload.acesoft.com.finalnoti1-2/lib/x86, /vendor/lib, /system/lib]]
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:2862)
    at android.app.ActivityThread.-wrap4(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    Caused by: java.lang.ClassNotFoundException: Didn’t find class “pdfdownload.acesoft.com.finalnoti1.MyFirebaseInstanceIDService” on path: DexPathList[[zip file “/data/app/pdfdownload.acesoft.com.finalnoti1-2/base.apk”],nativeLibraryDirectories=[/data/app/pdfdownload.acesoft.com.finalnoti1-2/lib/x86, /vendor/lib, /system/lib]]
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
    at android.app.ActivityThread.handleCreateService(ActivityThread.java:2859)
    at android.app.ActivityThread.-wrap4(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    Suppressed: java.lang.ClassNotFoundException: Didn’t find class “pdfdownload.acesoft.com.finalnoti1.MyFirebaseInstanceIDService” on path: DexPathList[[dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-support-annotations-24.0.0_f1922869db228c702239fe54488501c67353de9d-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_9-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_8-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_7-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_6-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_5-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_4-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_3-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_2-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_1-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-slice_0-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-internal_impl-24.0.0_ea347b886ce00961cde97a2865177ebe7de7c2bb-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-com.google.firebase-firebase-messaging-9.6.1_ffababe805b07d86a128682100e7838c215a47a6-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-com.google.firebase-firebase-iid-9.6.1_9f3815dd9987147a909c29bac63fb3ccae9ff29b-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-com.google.firebase-firebase-common-9.6.1_d015261773f8d76080ce7baa6145c3234197bb5c-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-com.google.firebase-firebase-analytics-impl-9.6.1_490a2947b198709d6f7eafca6c666d2a30e33e4e-classes.dex”, dex file “/data/data/pdfdownload.acesoft.com.finalnoti1/files/instant-run/dex/slice-com.google.
    I/art: WaitForGcToComplete blocked for 29.950ms for cause Background
    Application terminated.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.

LATEST POSTS

SOLID Principles in Android with Kotlin Examples

Recently I had an interview experience where I went blank when the interviewer posed an Interesting Question - Explain SOLID Principles and how they are...

Building a Multi Module App in Android | Modularization in Android #1

Recently, I was in requirement for developing a Multi Module app in Android and I was going through this great lecture on it. This article...

Lambda function in Kotlin with Examples

Lambda function is powerful feature in any Programming language and Lambda function in Kotlin is no exception. In this article, we will look at how...

Higher Order Functions in Kotlin with examples

There are many advanced features in Kotlin which gives an edge for the user using this language over Java. One such feature is Higher Order...

Follow us

1,358FansLike
10FollowersFollow
401SubscribersSubscribe

Most Popular