Welcome to our Learn At Home Sale!

Limited-time Advanced Swift & Android book bundles, plus 50% off all books

Home · Android & Kotlin Tutorials

Firebase Cloud Messaging for Android: Sending Push Notifications

In this Firebase Cloud Messaging tutorial, you will learn how to add push notifications to Drink-It, an app that reminds you to drink water through the day.

5/5 4 Ratings

Version

  • Kotlin 1.3, Android 4.4, Android Studio 3.6

Firebase Cloud Messaging (FCM) is a set of tools that sends push notifications and small messages of up to 4 KB to different platforms: Android, iOS and web.

This topic is useful because you use push notifications in a lot of mobile projects. Firebase is one of the simplest methods to get notifications working.

In this project, you’ll build Drink-it, an app that sends push notifications throughout the day reminding you to stay hydrated. After all, with our busy lives, many of us forget how important water is.

In the process you’ll learn:

  • How to set up Firebase and create a project in it.
  • A method to connect your mobile app with the Firebase console.
  • The difference between receiving messages in the foreground and background of your app.
  • How to use the data received in the messages.
  • How to send test messages through Firebase console.
Note: This Firebase Cloud Messaging Tutorial assumes you know the basics of Android development, Kotlin and Android Studio. Also, it assumes that you already have a Google Account to configure the Firebase console. If you’re new to Android development, check out our Kotlin for Android Introduction or our Beginning Android Development With Kotlin series.

Getting Started

Download the starter project by clicking on the Download Materials button at the top or bottom of the tutorial. Open the starter project in Android Studio 3.6 or later.

Looking at the code, you’ll notice the starter project provides the user interface and some classes where you’ll add the logic of the app.

Build and run the starter project. You’ll see the Drink-It app with a button for retrieving a token. Right now, the button does nothing, but you’ll configure it soon.

Drink-It app initial view with a button to retrieve the token

What Is Firebase Cloud Messaging?

Push notifications — those small alerts that slide in from the top of our screen, letting us know an app needs our attention — have been around since the early days of Android apps. There are many tools that can help us add this functionality, but Firebase Cloud Messaging is one of the easiest and most straightforward to add in your projects.

Notification example

Firebase Cloud Messaging has a simple architecture with four main parts:

  1. A service, API or console that sends messages to targeted devices.
  2. The Firebase Cloud Messaging back end, where all the processing happens.
  3. A transport layer that’s specific to each platform. In Android’s case, this is called the Android Transport Layer.
  4. The SDK on the device where you’ll receive the messages. In this case, called the Android Firebase Cloud Messaging SDK.

You’ll use each of these parts throughout the tutorial. First, you’ll look at the setting up Drink-It in the Firebase console.

Configuring the Project in the Console

Before receiving any push notifications in your app, there’s a series of steps you’ll need to configure in the Firebase console. That’s what you’ll do in the first part of the tutorial.

Creating a Firebase Project in the Console

To begin, sign in to the Firebase console. Make sure you use the Google account you want to tie to your project.

After logging in, you’ll see one of two options:

  1. If this is your first project, you’ll see a button with the label Create a project.
  2. Firebase console with create a project button if this is your first project

  3. If you’ve already started other projects, you’ll see a list of them and a button with the label Add project.
  4. Firebase console with add project button if you have other projects

Once you get to the next screen, name the project and accept the terms of service. You can choose whatever name you want since you only need it to identify the project.

For this tutorial, you’ll set the name to Drink-It. Once the name is set, accept the Firebase terms and click continue.

Firebase console requesting information for the project name and service agreement

The next screen will prompt you to add Google Analytics. Click the checkbox to get statistics about your notifications, like how many people received them, if they opened them and more.

Analytics aren’t required for this tutorial, but you can activate them if you’re interested.

Screen prompting you to add Google Analytics to the project, which is optional

Finally, click Create project and wait until it says it’s ready. You’ll see an image like the one shown below.

Project creation was successful

Congratulations, you just created a Firebase project that works for Android, iOS and web!

Registering the App With Firebase

Now, you’ll continue to configure your Android app. Once the Firebase project is ready. Click Continue to display the main screen of the project.

Once on the project home page, you’ll notice several options and details. Here’s where you’ll find the option to add Firebase to an app.

Project hompage with options to add Firebase to an app

To start integrating Firebase with your project, click the Android button, which is under Get started by adding Firebase to your app. You’ll see a screen requesting data from your app.

Firebase screen that requests information from your Android app

Enter the following information:

  • Android Package Name: com.raywenderlich.android.drinkit. This is important. It must match your application ID.
  • App Nickname: Drink-it.
  • Debug signing certificate SHA-1: You don’t need this, just leave it empty.

Screen with the Android app details filled in

Next, click Register app to proceed to the next step.

Adding Firebase Configuration Files to Your Android Project

This screen prompts you to download a JSON file that contains the service configuration for Firebase. Save it anywhere on your computer and remember where you place it. You’ll add it to the project next.

Screen to download the JSON file

Go into Android Studio and switch to the project view in the left panel:

Project View in Android Studio

Add the file to the project in the path DrinkIt/app:

Project tree with the JSON file added

Note: Your starter project already contains a file named google-services.json, but you still need to replace it with the one you just downloaded. The starter project includes this file so Android Studio can compile and run the starter project at this initial stage. When you start your own app from scratch, you won’t have this file in the project folder.

Adding the Firebase SDK to the App

In Android Studio, switch back to the Android view in the left panel:

Android view in Android studio left pane

Open build.gradle, which Android Studio tags as (Project: DrinkIt). This file is in Gradle Scripts/build.gradle.

Next, add this code in the dependencies section:

classpath 'com.google.gms:google-services:4.3.3'

Click Sync Now in the yellow warning at the top and wait for the Gradle sync.

Android studio yellow bar at the top requesting to sync gradle

The project build should be successful.

Android Studio build window indicating build was successful

Then open Build.gradle, labeled as (Module: app). This file is also in the Gradle Scripts section within the Android view.

Next, add this code at the top with the other, similar lines:

apply plugin: 'com.google.gms.google-services'

If you chose the Google Analytics option during the Firebase project creation, add this in the dependencies section:

implementation 'com.google.firebase:firebase-analytics:17.2.3'

Once again, click Sync Now and wait for the build to finish.

Go back to the Firebase console and click Next in the screen where you downloaded the file. You’ll see a small prompt that checks whether your app has connected to the server or not:

Firebase console indicator checking if the app is communicating with the server

Build and run to make this check successful. The app will look like the image below with no changes in the UI:

Successful app build

If the check was successful, the yellow warning will change to a congratulations message:

Message showing your app has communicated correctly with Firebase

If everything is correct, click Continue to console. Otherwise, go back over the steps above and check you did everything correctly.

Adding Firebase to an app with a confirmation button

You’ll now see the console homepage and the Android logo:

Name of the project with an Android purple logo indicating the app has Firebase integrated now

Build and run. You shouldn’t see any changes in the app.

Drink-it app with no changes

Configuring the Demo App

At this point, you’ve done all the configuration you need to do in the Firebase console. Next, you’ll add some code to the Drink-it app so it can remind you to drink water! If you haven’t had any recently, you can take a drink right now, by the way. :]

Including the Maven Repository

Google recommends adding their Maven repository to your app, but all Android Studio 3.6 projects include it by default. Take a moment to ensure this repository isn’t missing.

In your project-level build.gradle file — labeled Project: DrinkIt in Android Studio — make sure you have a line of code with google() in the repositories section of buildscript and allprojects respectively.

Next, you need to edit the Android Manifest.

Open AndroidManifest.xml in app/manifests. Inside the application tags, add the following:

<service
  android:name=".MyFirebaseMessagingService"
  android:exported="false">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT" />
  </intent-filter>
</service>

The code above adds a service for handling the received notifications. Within the project, you have a file called MyFirebaseMessagingService in com.raywenderlich.android.drinkit. That service is currently empty, but once you complete it later, it will take care of receiving and processing your notification information.

For now, open MyFirebaseMessagingService and make sure it extends from FirebaseMessagingService as shown below:

class MyFirebaseMessagingService : FirebaseMessagingService() {

Next, you need to add the following dependency in your app module build.gradle:

implementation 'com.google.firebase:firebase-messaging:20.1.3'

This dependency includes the sources for FirebaseMessagingService. However, you still need to add the following import on the top of MyFirebaseMessagingService:

import com.google.firebase.messaging.FirebaseMessagingService

Using the Device Token

The device token is a unique identifier that contains two things:

  1. Which device will receive the notification.
  2. The app within that device that will receive the notification.

Firebase automatically generates these tokens and delivers them to you as a developer.

Retrieving the Device Token

Device tokens may change over time, due to circumstances like:

  • The app deleted the Instance ID.
  • The user got a new device and restored the app.
  • The user uninstalled and reinstalled the app.
  • The user cleared app data.

In these cases, you’ll need to retrieve the device token.

In most of your apps, you’ll retrieve this token in the background. Sometimes, you’ll need to save it to a database so you can use it to send push notifications with internal APIs. In this app, you already have a Retrieve token button, which you’ll use so you can see the operation’s result.

Open MainActivity.kt. In the layout of this screen, there’s a Retrieve token button. Create an onClickListener for the button inside onCreate() by using the following code:

  button_retrieve_token.setOnClickListener {
    // 1
    FirebaseInstanceId.getInstance().instanceId
      .addOnCompleteListener(OnCompleteListener { task ->
        // 2
        if (!task.isSuccessful) {
          Log.w(TAG, "getInstanceId failed", task.exception)
          return@OnCompleteListener
        }
        // 3
        val token = task.result?.token

        // 4
        val msg = getString(R.string.token_prefix, token)
        Log.d(TAG, msg)
        Toast.makeText(baseContext, msg, Toast.LENGTH_LONG).show()
       })
    }
  }

Here’s what this code does, step-by-step:

  1. You get the instance of the app that’s tied to the Firebase back end and add a complete listener to it so you know when the task finishes, whether with an error or success.
  2. You check if the task, which is the result of this function, isn’t successful and return an error to the console.
  3. If the task is successful, you get the result from it.
  4. After getting the token, you set it as a string and output it for both the terminal and a toast message.

The code shows several errors now because you need to import some classes. To fix those errors, add this code to the top of MainActivity.kt with the rest of the imports:

import com.google.firebase.iid.FirebaseInstanceId
import com.google.android.gms.tasks.OnCompleteListener
import android.util.Log
import android.widget.Toast

Build and run, then tap the Retrieve token button. The token now shows in the toast message. Check the console and you’ll also see the token there.

App showing the retrieve token in a toast message

With the device token retrieved, Firebase can now connect with your device. In the next section, you’ll see how to do that shortly.

Checking if Devices Can Receive Notifications

When sending push notifications in Android, it’s important to make sure the devices you’re pushing to have Google Play Services enabled. Otherwise, they won’t be able to receive your messages.

In a small app, sending push notification to some devices that can’t receive them might not matter. However, when you’re using resources on a paid quota, distinguishing the devices that can get messages from the ones that can’t is vital.

To do this, add this function in MainActivity.kt:

private fun checkGooglePlayServices(): Boolean {
  // 1
  val status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this)
  // 2
  return if (status != ConnectionResult.SUCCESS) {
    Log.e(TAG, "Error")
    // ask user to update google play services and manage the error.
    false
  } else {
    // 3
    Log.i(TAG, "Google play services updated")
    true
  }
}

Check out what this code does:

  1. First, you use Android’s availability API to check for Google Play Services.
  2. If the status isn’t successful, you need to manage the error. In this case, you know the user can’t receive push notifications.
  3. If it is successful, there’s no problem and you can continue with the notification process.

Again, you’ll get errors because of missing imports. Add those imports at the top of the file with this code:

import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability

Now, use the following code to add the check to onClickListener, right after button_retrieve_token.setOnClickListener {:

if (checkGooglePlayServices()) {

} else {
  //You won't be able to send notifications to this device
  Log.w(TAG, "Device doesn't have google play services")
}

Depending on the purpose of your notifications, you may want to display an alert message to the user. For this app, you’ll just show the message in the terminal.

Test this error by creating an Android Virtual Device with Google Play Services disabled. Notice that the screen has a message suggesting that you use another image. That’s because most app dependencies use Google Play Services.

Android Studio virtual device manager showing a device without Google Play Services

Build and run. You should see no change in the app.

App running with no changes

Sending a Test Message With Notification Composer

Firebase includes a tool called Notification Composer that lets you send tests or custom messages when your user base isn’t too big. For larger projects, you’ll need to create an API or another tool to automate this process.

Either way, it’s important to learn to use this tool, because it’s always handy to be able to send messages for testing.

To access the Notification Composer in the Firebase console, click the project name.

Firebase console with the Drink-It project listed in the main page

Since the project is new, you’ll find the option to Send your first message.

Firebase console in the project Drink-it view prompting to send the first message

If you don’t have this option available, you can find it on the left side menu under the grow section:

Left-side menu of the Firebase console

Configuring Notification Composer

Notification Composer allows you to configure the data of the message you’ll send and preview your notification on the right side of the window. Enter the following data:

  • Notification title: Most apps use the name of the app, but you can actually add any title.
  • Notification text: Add: “This is a reminder to drink water!”
  • Notification image: This is optional. For this tutorial, you won’t add an image.
  • Notification name: This is for your personal use, so you can identify the notification in the console. This data is also optional.

Note that the notification text can be anything you want, but it should be brief or the entire message won’t display.

Notification composer step one

Now, select your app identifier: com.raywenderlich.android.drinkit

Notification composer target app

You can schedule the time, but for this tutorial select now — unless you want to wait for it to arrive!

Notification composer scheduling

You can play around with the other values, but they aren’t necessary. When you’re done, click Review.

Notification composer extra optional values

A confirmation window will appear. If you didn’t activate Google Analytics, you’ll see a red alert. Don’t worry about it, it’s not required.

Click Publish and take a look at the emulator or device where you installed your app.

Alert displayed in Firebase console confirming the notification data

If you’re in the list of notifications, you can either click the New notification button or select the Duplicate notification option from the drop-down menu to send another one.

History of notifications with duplicate option

Be careful! If the app is in the foreground, you won’t see the notification. Later, you’ll configure foreground notifications.

For now, send the app to the background and try again, and you’ll see a notification appear.

Notification in the emulator

When you click on the notification, it will open the app. Nothing happens because you haven’t configured any additional actions.

Background-Restricted Apps

If for some reason your notification isn’t appearing. It could be because of the version of Android your device is using. Android 9, also known as Android P, introduced the possibility of restricting apps from running in the background. Although you’re probably testing on an emulator or on your own device, it’s important to know this is possible.

If you have trouble testing, check that the app isn’t background-restricted.

To access these settings, go to Settings ▸ Apps & notifications, select the Drink it app from the list then scroll down and select Battery. You might need to open the Advanced section before you see the Battery option.

Once in the Battery usage screen, tap on Background restriction. You’ll get a warning that notifications may arrive later or not arrive at all.

Background restricted apps alert in settings

If your notification shows up without problems, you’re good to carry on to the next section.

Setting Custom Icons and Colors

Android gives you the possibility to set a custom icon and color for the notifications through Android Manifest.

There are several ways to set the notification’s icon:

  1. Don’t assign an icon. In this case, the app icon will appear.
  2. Set it in Android Manifest.
  3. Send it in the notification payload.

The color of the notification will vary depending on the Android version. If the version is earlier than Android N, the color will appear in the background of the icon. If the version is N or above, the icon and app name will use the color.

You’ll set the color and icon using Android Manifest. Add the following code to AndroidManifest.xml inside of the application tag:

<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_launcher_foreground" />
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorPrimary" />

The first tag sets the notification icon; the second sets the color. The name values are standard, so every time you want to change the icon or color, you’ll add the same value to the name attribute. The resource value is the one you’ll configure. For the icon, it can have any drawable and for the color, any valid value is possible.

Build and run, then send another notification. It will use the color and icon you selected, which may vary depending on the device or emulator you’re using.

Notification with custom color and icon

Receiving Notifications in the Foreground Versus Background

When receiving notifications, it’s important to distinguish whether the app is running on the foreground or background. Basically, you need to consider the following:

  • Foreground: The notification and the data are both handled in onMessageReceived().
  • Background: The System UI handles the notification, while onMessageReceived() handles the data payload.

You’ll now configure Drink-it to handle notifications when it’s running in the foreground.

Add the following code to MyFirebaseMessagingService:

override fun onMessageReceived(remoteMessage: RemoteMessage) {
  super.onMessageReceived(remoteMessage)
  handleMessage(remoteMessage)
}

Then you’ll add another method for handling the message:

private fun handleMessage(remoteMessage: RemoteMessage) {
  //1
  val handler = Handler(Looper.getMainLooper())

  //2
  handler.post(Runnable { 
      Toast.makeText(baseContext, getString(R.string.handle_notification_now), 
                     Toast.LENGTH_LONG).show() 
    }
  )
}

Now, review the code above:

  1. You create a handler to get the message and extract the data.
  2. You use that handler to post the toast through a runnable.

You’ll get errors because of missing imports. Add them at the top of the file with this code:

import android.os.Handler
import android.os.Looper
import android.widget.Toast
import com.google.firebase.messaging.RemoteMessage

Build and run and check the notification with the app in the foreground.

Notification in the emulator in foreground

Displaying Notification Data in Activities

Sometimes, you want to do something with the data that arrived through the notification. For your last step, you want to display the text of the notification in the activity.

To do this, you’ll add a broadcast manager, which listens to incoming data from notifications and does the appropriate treatment.

To start, add this code to MyFirebaseMessagingService:

private var broadcaster: LocalBroadcastManager? = null

override fun onCreate() {
  broadcaster = LocalBroadcastManager.getInstance(this)
}

Then add this code to handleMessage() , inside handle.post:

remoteMessage.notification?.let {
  val intent = Intent("MyData")
  intent.putExtra("message", it.body);
  broadcaster?.sendBroadcast(intent);
}

If you see an error on the intent, import this code at the top:

import android.content.Intent

In MainActivity.kt, you need to add some more code to receive the message. First, add a BroadcastReceiver with the following code:

private val messageReceiver: BroadcastReceiver = object : BroadcastReceiver() {
  override fun onReceive(context: Context?, intent: Intent) {
    text_view_notification.text = intent.extras?.getString("message")
  }
}

This BroadcastReceiver checks the notification when it arrives and looks for the string called message. It then puts it on the screen, assigning it to notification_text.

If you have errors, it’s because you need to import some more classes. Add this at the top of your file:

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent

Next, in the activity, add this code to OnStart():

LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, IntentFilter("MyData"))

With the code above, you create the broadcast manager instance so whenever a notification arrives, you check if the data labeled MyData is available.

Then, add this code to OnStop():

LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver)

With this code, you’ll unregister this receiver to avoid keeping it in memory when it’s no longer needed.

You also need to import the context, as some of the added code may show errors. Add this to your imports:

import androidx.localbroadcastmanager.content.LocalBroadcastManager
import android.content.IntentFilter

Build, run and send a notification. You’re now receiving the notifications correctly! Check the image below to compare your code:

App with the notification in the foreground with the text in the screen changed

Sending a Payload in the Notification

You have one last step to implement. If you close the app completely and send the notification, you’ll get it in the System UI. However, if you click it, the text on the screen is still Drink It and not the text of the notification.

To fix this, you need to modify the code in MyFirebaseMessagingService.kt. In handler.post, change the code in remoteMessage.notification to the following:

remoteMessage.notification?.let {
  val intent = Intent("MyData")
  intent.putExtra("message", remoteMessage.data["text"]);
  broadcaster?.sendBroadcast(intent);
}

This takes the information that comes in the payload of the notification with the key text and puts it in an intent called MyData with another key called message, which is directed to MainActivity.

To receive this, add this code to the onCreate() of your MainActivity:

val bundle = intent.extras
if (bundle != null) { 
  text_view_notification.text = bundle.getString("text")
}

With this, you’re displaying the content of the notification payload in text_view_notification.

Now, test that this works. Create a notification in Firebase Notification Composer as you did in the previous steps. This time, however, use the following configuration options in step 5 of the wizard.

Extra options for notification in Firebase console

In the key field, enter text. Then, in the value textfield, enter I know you haven’t finished your water bottle!.

Build and run, then send this notification and voila! Everything works now.

Test it in background and foreground and make sure the text view changes with the message received. This is how the app should look now:

Final result of the app with the notification data payload in the screen text view

Congratulations! You just created an Android app that reminds you to drink water. Just remember to schedule your notifications in Firebase Composer so they arrive regularly. Don’t forget to keep hydrated. :]

Where to Go From Here?

Download the completed project files by using the Download Materials button at the top or bottom of the tutorial.

If you want to learn more about Firebase for Android, check out our tutorial on Real-Time Databases or our tutorial on Authentication with Firebase.

We hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below!

Average Rating

5/5

Add a rating for this content

4 ratings

More like this

Contributors

Comments