DEV Community

Cover image for Android Push Notifications Step by Step Guide
Bugfender
Bugfender

Posted on • Originally published at bugfender.com on

Android Push Notifications Step by Step Guide

Push notifications play an important role in user engagement and retention in your mobile app, keeping users up to date and creating a sense of urgency that leads to purchases. And in Android, we get the added benefit of Firebase Cloud Messaging (FCM) notification service, which acts as a middleman between the app server and the user’s Android device. It helps the delivery of push notifications, even if the app is not active or the user is using a different app on their device.

Firebase Cloud Messaging (FCM) is used to send data messages and alerts to users, thanks to its robust cross-messaging system. iOS, Web and Android platforms are all supported by FCM. Messages with a data payload of up to 4kb can be sent using FCM push notifications.

In this article, we will explore the step-by-step integration of push notifications into Android apps, and discuss the critical aspects of implementation. We will also introduce several products and tools that can simplify and amplify user engagement.

Understanding Android Push Notifications

Mobile push notifications help to improve user engagement, customer retention, and overall user experience in your applications. When push notifications are used properly, they can significantly enhance the effectiveness of mobile apps across various business domains.

Push notifications can be used for different use cases and purposes in your Android app, including:

i) Updating a user on the status of their online booking or schedule.

ii) Provide clarifications and updates for an online order the user has placed.

iii) Advising users of changes in the back-end and helping them track their package.

iv) Creating hype around events linked to the app, and introducing a user to new offers, promotions and opportunities.

v) Encouraging users to try new app features with teasing messages and notifying them of server updates and other back-end changes.

Implementation Approach of Push Notifications in Android Application

Prerequisites

You need to have these tools and services in order to successfully implement push notifications in your Android app FCM:

i) Android Studio – This is the IDE used for the Android development.

ii) Basic Knowledge & Understanding – You need a basic understanding of Android project development and structure, and manifest file configuration.

iii) A Firebase Account – You should have a Firebase account for creating and managing your project settings.

iv) Internet Availability – Integration testing and firebase setup require an internet connection.

Step 1. Setup your Firebase Project

Visit Firebase Console.

Create your project by Giving it a name and Click continue.

For further configuration, you can enable or disable the Google Analytics service to get the data analytics for your app.

To complete the setup you need to review the project settings; then you can create your project.

After you have created your project, you need to do additional project configuration for the push notification implementations.

Registering your app in project dashboard

You need to click on the Android icon in the dashboard to add an Android app. Next, enter a Android package name. This package name must be the same as the package name in your project (i.e., com.app.demoapp).

You can also enter your app’s nickname to identify your app in the console.

Add SHA-1 key for your app. You need to use this command to generate your SHA-1 key in your terminal: Now copy the SHA-1 key and paste it into the Firebase console.

./gradlew signingReport

Enter fullscreen mode Exit fullscreen mode

Finally Click ‘Register App’ to finish configuration.

Setup Google Services

Once you finish registering your app, you can download the google-services.json file and save this it to your computer.

Now you need to add google-services.json to your Android project, file to the app directory of your Android project.

MyApp/
├── app/
│ ├── src/
│ ├── build.gradle
│ ├── google-services.json
├── build.gradle
├── settings.gradle

Enter fullscreen mode Exit fullscreen mode

Add Firebase SDK

Next, add Firebase SDK to Your Project, in build.gradle add the Google services classpath:

buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        // Add this line
        classpath 'com.google.gms:google-services:4.3.10'
    }
}

Enter fullscreen mode Exit fullscreen mode

in app/build.gradle add the following dependencies:-

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

android {
    // ...
}

dependencies {
    // Add these lines
    implementation platform('com.google.firebase:firebase-bom:29.0.4')
    implementation 'com.google.firebase:firebase-analytics'
    implementation 'com.google.firebase:firebase-messaging'
}

Enter fullscreen mode Exit fullscreen mode

After you finish these steps you can click ‘Sync Now’ in the Android Studio to sync your project with the Firebase.

Step 2. Configure Your Android Project

Project-Level build.gradle

Open Your Project-Level build.gradle: Navigate to the root directory of your Android project and locate the build.gradle file.

Ensure the google() and mavenCentral() repositories are included in the repositories section.

buildscript {
    repositories {
        // Check that you have these lines
        google()
        mavenCentral()
    }
    dependencies {
        // Add this line
        classpath 'com.google.gms:google-services:4.3.10'
    }
}

allprojects {
    repositories {
        // Check that you have these lines
        google()
        mavenCentral()
    }
}

Enter fullscreen mode Exit fullscreen mode

Make changes in the build.gradle

Find and locate the build.gradle file in your project app directory, then add the google-services plugin at the end of the file, and add the Firebase and Firebase Messaging dependency in the dependencies section.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 33
    defaultConfig {
        applicationId "com.example.myandroidapp"
        minSdkVersion 21
        targetSdkVersion 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.8.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

    // Add Firebase BOM
    implementation platform('com.google.firebase:firebase-bom:29.0.4')
    // Add Firebase Messaging dependency
    implementation 'com.google.firebase:firebase-messaging'
}

// Add this line at the bottom of the file
apply plugin: 'com.google.gms.google-services'

Enter fullscreen mode Exit fullscreen mode

With these steps completed, your project is configured with Firebase dependencies, including Firebase Messaging for push notifications. Let us now proceed with Firebase Messaging service setup and handling the notifications in your app.

Step 3. Implement the FCM

Add a Service to Handle FCM Messages

Create a new class named MyMessagingService that extends FirebaseMessagingService.

You need to override onMessageReceived Method to handle incoming messages when your app is in foreground state. Then implement logic to handle the notification and optionally show it to the user.

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // Handle the received message
        if (remoteMessage.getNotification() != null) {
            // Get the message body
            String messageBody = remoteMessage.getNotification().getBody();
            // Send a notification
            sendNotification(messageBody);
        }
    }

    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, intent, PendingIntent.FLAG_ONE_SHOT);

        String channelId = getString(R.string.default_notification_channel_id);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_notification)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

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

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId, "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0, notificationBuilder.build());
    }
}

Enter fullscreen mode Exit fullscreen mode

Register in AndroidManifest.xml file

Open the AndroidManifest.xml file in your project.

Now you need to register the MyMessagingService in the manifest to handle FCM messages.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myandroidapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

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

        <!-- Other activities and services -->
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
Enter fullscreen mode Exit fullscreen mode

Step 4: Obtain the FCM Registration Token

To receive push notifications, your app needs to obtain the FCM registration token. This token uniquely identifies the app instance on the device.

Code Example to Fetch the Device Token

You can fetch the FCM registration token in your FirebaseMessagingService or any other appropriate place in your app. Let’s see how to do it in FirebaseMessagingService.

Update MyMessagingService:

import android.util.Log;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // Handle the received message
        if (remoteMessage.getNotification() != null) {
            // Get the message body
            String messageBody = remoteMessage.getNotification().getBody();
            // Send a notification
            sendNotification(messageBody);
        }
    }

    @Override
    public void onNewToken(String token) {
        Log.d(TAG, "Refreshed token: " + token);
        // Send the token to your server or save it as needed
        sendRegistrationToServer(token);
    }

    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, intent, PendingIntent.FLAG_ONE_SHOT);

        String channelId = getString(R.string.default_notification_channel_id);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_notification)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

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

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId, "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0, notificationBuilder.build());
    }

    private void sendRegistrationToServer(String token) {
        // TODO: Implement this method to send the token to your app server.
        // This can be an API call to store the token on your server
    }
}
Enter fullscreen mode Exit fullscreen mode

You can fetch the token in an Activity or Fragment, and store or use it as required.

import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.messaging.FirebaseMessaging;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

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

        // Fetch the token
        FirebaseMessaging.getInstance().getToken()
                .addOnCompleteListener(task -> {
                    if (!task.isSuccessful()) {
                        Log.w(TAG, "Fetching FCM registration token failed", task.getException());
                        return;
                    }

                    // Get new FCM registration token
                    String token = task.getResult();

                    // Log and toast
                    Log.d(TAG, "FCM Registration Token: " + token);
                    // You can send this token to your server or store it as needed
                });
    }
}
Enter fullscreen mode Exit fullscreen mode

Using these methods you can get the FCM registration token in your Android app. The token can be fetched either in the FirebaseMessagingService or any Activity or Fragment. This token is important for sending targeted push notifications to specific devices.

Step 5: Send Push Notifications

If you want to send notifications from a server you need to make a POST request to FCM API.

You need to Get a Server Key

  • In the Firebase Console → Project Settings → “Project Overview” → “Cloud Messaging”.
  • In “Project credentials”, you will find the Server key.

cURL Request: This cURL command will be used to send notifications. Replace <YOUR_SERVER_KEY> with your actual server key and <FCM_DEVICE_TOKEN> with the FCM token of the target device.

//CURL request to send push notifications
curl -X POST \
  https://fcm.googleapis.com/fcm/send \
  -H "Authorization: key=<YOUR_SERVER_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
        "to": "<FCM_DEVICE_TOKEN>",
        "notification": {
          "title": "Notification",
          "body": "Notification sent from server"
        },
        "data": {
          "key1": "value1",
          "key2": "value2"
        }
      }'
Enter fullscreen mode Exit fullscreen mode
  • https://fcm.googleapis.com/fcm/send API endpoint.
  • H "Authorization: key=<YOUR_SERVER_KEY>": This is an authorization header with your server key.
  • H "Content-Type: application/json": content type header.
  • d '{ ... }': This is the JSON payload that has your notification and data.

Advanced Topics

Handling Data Messages

Data messages are a type of message that can carry custom key-value pairs and are handled differently from notification messages. Data messages are received in the onMessageReceived method of FirebaseMessagingService , regardless of whether the app is in the foreground or background.

Example for Handling Data Messages

Update MyMessagingService

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

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

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

    @Override
    public void onNewToken(String token) {
        Log.d(TAG, "Refreshed token: " + token);
        sendRegistrationToServer(token);
    }

    private void handleNow(Map<String, String> data) {
        // Process the data here
        String key1 = data.get("key1");
        String key2 = data.get("key2");
        // Handle the data accordingly
    }

    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, intent, PendingIntent.FLAG_ONE_SHOT);

        String channelId = getString(R.string.default_notification_channel_id);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)
                .setSmallIcon(R.drawable.ic_notification)
                .setContentTitle(getString(R.string.app_name))
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

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

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId, "Channel human readable title", NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0, notificationBuilder.build());
    }

    private void sendRegistrationToServer(String token) {
        // Implement this method to send token to your app server
    }
}
Enter fullscreen mode Exit fullscreen mode

Managing Notification Channels

Starting with Android 8.0 (API level 26), all notifications must be assigned to a channel. This allows users to control notification settings for each channel.

Example for Creating Notification Channels

Create a Method to Set Up Notification Channels:

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;

public class NotificationUtils {

    public static final String CHANNEL_ID = "default_channel_id";
    public static final String CHANNEL_NAME = "Default Channel";
    public static final String CHANNEL_DESCRIPTION = "This is the default notification channel";

    public static void createNotificationChannel(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    CHANNEL_NAME,
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            channel.setDescription(CHANNEL_DESCRIPTION);
            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Call This Method in Your MainActivity or Application Class:

javaCopy code
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

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

        // Create notification channel
        NotificationUtils.createNotificationChannel(this);
    }
}

Enter fullscreen mode Exit fullscreen mode

Alternatively, you can call NotificationUtils.createNotificationChannel(this); in your Application class if you have one:

import android.app.Application;

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // Create notification channel
        NotificationUtils.createNotificationChannel(this);
    }
}

Enter fullscreen mode Exit fullscreen mode

Update Your Notification Builder to Use the Channel ID:

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, intent, PendingIntent.FLAG_ONE_SHOT);

    String channelId = NotificationUtils.CHANNEL_ID;
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(getString(R.string.app_name))
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setContentIntent(pendingIntent);

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

    notificationManager.notify(0, notificationBuilder.build());
}
Enter fullscreen mode Exit fullscreen mode

Testing Push Notifications

When push notifications are implemented, we need to do testing to make sure they are implemented correctly.

In Android Studio, you can open the logcat, View > Tool Windows > Logcat.

We can also filter the logcat output using the tag we used in the FirebaseMessagingService class. The application must be running on device or through an emulator.

When the notification is received, we can see the data in logcat like this:

D/MyFirebaseMsgService: Message Notification Body: This is a test notification!

Enter fullscreen mode Exit fullscreen mode

Message data can be seen like this:

D/MyFirebaseMsgService: Message data payload: {key1=value1, key2=value2}

Enter fullscreen mode Exit fullscreen mode

Conclusion

In this article we learned about push notifications, along with a step-by-step approach to implementation. We learned how to set up a project in Firebase console and how to complete the required configuration in Firebase project settings, so you can start sending Android notifications to your Android users.

You need to start by setting up a Firebase project and downloading the google-services.json file. After that, you need to put this file app’s directory and modify the build.gradle files to include Firebase dependencies.

Then, you need to create a class that will handle the incoming messages and register this service class in the AndroidManifest.xml. After adding the service in manifest file, you need to fetch the FCM token that is used to uniquely identify your app, so a notification can be sent to the targeted device.

Notifications can be tested by sending messages from the Firebase Console and using Android Studio’s logcat to confirm delivery. To activate server-side notifications, use a cURL request with your Firebase server key and the device’s FCM token.

To maintain compatibility with later Android versions, you’ll need to process data messages in your ‘FirebaseMessagingService` and manage notification channels for sophisticated configurations.

Push notifications, which offer relevant updates and customized information – and can increase user retention and conversion rates – are crucial for encouraging user engagement.

Read the official Firebase and Android SDK docs for more information and in-depth directions. These websites provide thorough guidance and industry-best practices for incorporating push notifications into your application.

Top comments (0)