I am trying to open an Activity
when the notification is clicked and below is my code.
Intent intent = new Intent(this.getApplicationContext(),
According to FCM
Documentation, for receiving and handling messages,
If you want to receive notifications when your app is in the foreground, you need to add some message handling logic.
To receive messages, use a service that extends FirebaseMessagingService. Your service should override the onMessageReceived callback, which is provided for most message types, with the following exceptions:
1). Notifications delivered when your app is in the background. In this case, the notification is delivered to the device’s system tray. A user tap on a notification opens the app launcher by default.
2). Messages with both notification and data payload, both background and foreground. In this case, the notification is delivered to the device’s system tray, and the data payload is delivered in the extras of the intent of your launcher Activity.
So Basically, we have two types of Payloads
1). Notification Payload
2). Data Payload
3). Both (an additional type we can consider).
Now let's discuss one by one these payloads. Before that you need to understand how can you send these Payloads to your app. All you have to do is to make use of any tool that can perform HTTP POST Request
. In my case, I am using the Postman tool, a Google Chrome Plugin.
Before making a HTTP Post Request
for FCM
, you have to consider three things:
1). HTTP Post Request URL : https://fcm.googleapis.com/fcm/send
2). Request Headers :
i). Content-Type : application/json
ii). Authorization : key = YOUR_SERVER_KEY
Below is the screenshot for the same to show how it looks.
3). Body : In this we are going to have JSON
for Notification
and Data Payloads
.
onMessageReceived()
is called only when the app is in Foreground
, For all other cases, it's a System Tray Notification
, which opens the Launcher Activity
when clicked. This is helpful when you don't want to control Notifications
by your own and not much data to deal with when Notification
comes. You can even control the sound, icon and click_action(only when the app is in Foreground
) without writing any code in your onMessageReceived()
. One example of a body of such HTTP POST Request
is attached in the screenshot below.For opening desired Activity
when sending click_action parameter, you have to use the below code in your onMessageReceived()
.
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (null != remoteMessage.getNotification().getClickAction()) {
startActivity(remoteMessage.getNotification().getClickAction(), null, this);
}
}
and below is your startActivity()
method :
public void startActivity(String className, Bundle extras, Context context) {
Class cls = null;
try {
cls = Class.forName(className);
} catch (ClassNotFoundException e) {
//means you made a wrong input in firebase console
}
Intent intent = new Intent(context, cls);
if (null != extras) {
intent.putExtras(extras);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
}
NOTE : This
click_action
key will work only when the app is in Foreground, for all other case when the app is in Background and closed, it doesn't work. It doesn't even open the Launcher Activity, in case of Background and Closed, if this parameter is specified.
GCM
. This is very important if we want to handle all the Notification
stuff by ourselve same as we all were doing in case of GCM
. Example of a body of such HTTP POST Request
is shown below.So in this case, onMessageReceived()
is called everytime and this will work in the same way as that of GCM
, so helpful to all of us. You have to Override
onMessageReceived()
as shown below.
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Map<String, String> data = remoteMessage.getData();
if (null != data && 0 < data.size()) {
if (data.containsKey("custom_key_1")) {
sendNotification(data.get("custom_key_1"));
}
}
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, DesiredActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_ic_notification)
.setContentTitle("FCM Message")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
Notification
and Data Payloads
as well. In this case, onMessageReceived()
is called when the app is in Foreground
. For background and closed state, Notification
comes in the system tray similar to Notification Payload
but the only difference is we can have data extras
as well that we can use to redirect user to a desired Activity
, when clicked on a Notification
. Below is the example of a body of such HTTP POST Request
.Example of a body of such HTTP POST Request
is shown below.When clicking on a Notification
on System Tray, it will open the Launcher Activity
and You need to Override
onCreate()
of your Launcher Activity
to get the data extras
and redirect user to the desired Activity
. Below is the code, you have to write in onCreate()
of your Activity
to redirect user to the desired Activity
.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getIntent().hasExtra("custom_key_1") && getIntent().getStringExtra("custom_key_1")
.equals("custom_value_1")){
startActivity(new Intent(this, DesiredActivity.class));
finish();
return;
}
// other operations
}
Another case to this type is, when your Launcher Activity
is defined as launchMode="true"
in the manifest
and when the Notification
Arrives, your Launcher Activity
is in the Foreground
. So when you click on the Notification, you have to Override
the onNewIntent()
method in your Launcher Activity
to open the desired Activity
. Below is the sample code for the same.
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (getIntent().hasExtra("custom_key_1") && getIntent().getStringExtra("custom_key_1")
.equals("custom_value_1")) {
startActivity(new Intent(this, DesiredActivity.class));
finish();
}
}
So in short, I would say it's good to go with the Data Payload type as it provides more flexibility and control over the Notification
and more importantly as we all are used to GCM
, so this type is what we all would like to prefer.
Note : Some devices are having issue receiving Notifications in Background as I found some queries over same here. Moreover at the time, I was investigating these cases, my ASUS phone was not receiving notifications in Background for any of the types mentioned above. So not sure what's the issue with these devices.
You have to use FLAG_UPDATE_CURRENT
in pendingIntent.
PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationId /* Request code */, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
and also pass the same id to notificationManager
notificationManager.notify(notificationId /* ID of notification */, notificationBuilder.build());
I use this in my FirebaseMessagingService:
/**
* Create and show a simple notification containing the received FCM message.
*
* @param messageBody FCM message body received.
*/
private void sendNotification(String title, String messageBody, String data) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(this.NOTIFICATION_SERVICE);
notificationManager.notify(id++ /* ID of notification */, notificationBuilder.build());
}
You can specify any Activity
to be receiver for push notifications:
<intent-filter>
<action android:name="PACKAGE_NAME.MESSAGE"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
This intent filter for the activity specifies which activity will be launched in response to push notification (PACKAGE_NAME
is your Android app package)
So you can add this intent filter in your Activity
which you want to open on the click of Push notification.
Sorry not to add a comment as I'm a fairly new comer.
You can just do the following two things for further investigating:
After the notification has been created, use shell command "adb shell dumpsys activity i [your package name]" to see your notification in detail, to confirm it is really what you want. Remember to replace "[your package name]" with your own package name;
Tracking the event log during the time you are reproducing this using "adb logcat -v threadtime -b events".
Post both of these and we might get something useful about what is going wrong under the hood.
Set your pending intent like below
Intent intent = new Intent(this.getApplicationContext(), NotificationActivity.class);
intent.putExtra("msgBody",messageBody);
intent.putExtra(Constants.NOTIF_INTENT_TYPE,Constants.NOTIF_INTENT_TYPE);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
add it to your notification using
.setContentIntent(pendingIntent);