I've been developing android apps for a while now and all of them have FCM integrated in them and functioning properly.
I have this app that the onMessageReceived isn't fired unless the app is opened, if the app is closed and I receive a notification it opens from splash and follows the normal flow (it doesn't go to the Notifications activity).
N.B: all the testing I've done was from the Firebase Console
I really don't know why, any help would be appreciated.
Here's my code:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.wtf("RECEIVED","NOTIFICATION");
// TODO(developer): Handle FCM messages here.
Log.wtf(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.wtf(TAG, "Message data payload: " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.wtf(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
sendNotification("Notification");
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, HomeActivity.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.mipmap.icon)
.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());
}
}
Using Firebase, you can send two type of notifications message basically.
1. Notification messages : sometimes thought of as "display messages."
2. Data/Payload messages : which are handled by the client app.
both above Notification has different behaviour, depending upon if your app is in foreground or background.
1.Notification msg + Background : delivered to the notification tray
2.Notification msg + Foreground : onMessageReceived() on Android
3.Data msg + Background : apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification.
4.Data msg + Foreground : your app receives a message object with both payloads available.
For more clarification check this.
For sending Data/payload message using FCM console use Advance option and insert key and value.
Related
I'm using this code, when the app is in the foreground it was working perfectly. but the notification coming during app is in background Intent does not have any data.
Intent intent = new Intent(this, SplashActivity.class);
intent.putExtra(Constant.device_id,deviceId);
intent.putExtra(Constant.isFromPush,true);
intent.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK );
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.default_notification_channel_id);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title_)
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(new Random().nextInt( 2000 ) /* ID of notification */, notificationBuilder.build());
To Handle intent data when app is in background you need to do something extra.
There should have "data" key in your response to get it in activity. Like,
{
"notification": {
"key_1": "value_1",
"key_2": "value_2"
},
"data": {
"key_1": "value_1",
"key_2": "value_2"
},
}
And you need to get the values inside your launching activity's onCreate method.
Launching activity is which <intent-filter> contains
<category android:name="android.intent.category.LAUNCHER" />
Receive data,
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
//bundle contains all info of "data" field of the notification
}
In background, app receives notification payload in the notification tray, and only handle data payload when the user taps on the notification
We have two type of Payload in case of send-downstream both are optional.
data
This parameter specifies the custom key-value pairs of the message's payload.
notification
This parameter specifies the predefined, user-visible key-value pairs of the notification payload.
[https://firebase.google.com/docs/cloud-messaging/http-server-ref#send-downstream][Find More detail here]
When you are in background, FCM will showing notification in system tray based on the info from notification payload. Title, message, and icon which used for the notification on system tray are get from the notification payload.
{
"notification": {
"title" : "title",
"body" : "body text",
"icon" : "ic_notification",
"click_action" : "OPEN_ACTIVITY_1"
}
}
You need to use data payload instead of notification payload ,your issue get resolved .
Here is the example JSON i'm reciving :
{
"to": "FCM registration ID",
"data": {
"someData" : "This is some data",
"someData2" : "etc"
}
}
Here is my java code.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage == null)
return;
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
try {
JSONObject json = new
JSONObject(remoteMessage.getData().toString());
handleDataMessage(json);
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.getMessage());
}
}
}
Messages with both notification and data payload:
A message can also contains both notification and data payload. When these kind of messages are sent, it will be handled in two scenarios depending upon app state (background / foreground). For these message we can use both notification and data keys.
When in the background – Apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification.
When in the foreground – App receives a message object with both payloads available.
I am using Firebase Cloud Messaging to send push notifications.
Here is my FirebaseMessageService:
public class FireBaseMessageService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.e("TAG", "From: " + remoteMessage.getFrom());
Log.e("TAG", "Notification Message Body: " + remoteMessage.getData().get("CardName")+" : "+remoteMessage.getData().get("CardCode"));
sendNotification(remoteMessage.getNotification().getBody());
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, StartActivity.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.mipmap.ic_launcher_final)
.setContentTitle("Notification")
.setContentText(messageBody)
.setTicker("Test")
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
And FirebaseInstanceServer:
public class FirebaseInstanceService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.e("TAG", "Refreshed token: " + refreshedToken);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
// Add custom implementation, as needed.
Log.e("TAG", "Refreshed token2: " + token);
}
}
Which is declared in the AndroidManifest:
<service
android:name=".util.notifications.FireBaseMessageService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".util.notifications.FirebaseInstanceService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
So issue is that when App is running ticker is shown well and notification come with default sound, but when App is in background or is not running, notification come without any sound and ticker is not shown in status bar.
Why is this happening and how can I fix it?
With FCM you specify a POST payload to send to https://fcm.googleapis.com/fcm/send. In that payload you can specify a data or a notification key, or both.
If your payload contains only a data key, your app will handle all push messages itself. E.g. they are all delivered to your onMessageReceived handler.
If your payload contains a notification key, your app will handle push messages itself only if your app is active/in the foreground. If it is not (so it's in the background, or closed entirely), FCM handles showing the notification for you by using the values you put into the notification key payload.
Note that notifications sent from a console (like Firebase console), they always include a notification key.
Looks like you want to be handling the FCM messages yourself so you can customize the notification a bit more etc, so it would be better to not include the notification key in the POST payload, so all push messages are delivered to your onMessageReceived.
You can read more about it here:
Advanced messaging options
Downstream message syntax
I spent 2 weeks to understand why my application cannot receive data message anymore when it's in background and as strange as it could be, I arrived to the conclusion that Android-Studio 2.1.2 is the problem!
I cannot receive any FCM message anymore in background application
https://github.com/firebase/quickstart-android/issues/89
{
"to": "user_device_token",
"collapse_key": "type_a",
"data": {
"body": "your message body",
"title": "notification title",
"description":"notification description ",
"imageUrl":"image url",
"key_1": "Value for key_1",
"key_2": "Value for key_2"
}
}
remove notification key from notification message json response from backend
I want to check notification data JSON object before its been shown to user
is that possible ?? and if it is possible how to do it
thanks for the help
Firstly parse and analyze json received in fcm service class and then display notification as required.
You can use this Service if you are using FCM.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* 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.
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());
}
sendNotification("String From Data Payload");
// 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.
}
remoteMessage contains the message which is received by the service. After receiving the message you can handle your data payload by using remoteData.getData() which is stored as a Map. You can use remote.getData().get("json_key") to get particular value for your json_key sent inside data payload.
After getting the data you can use the method sendNotification as follows:
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);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.logo)
.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());
}
in onMessageReceived of your fcm service check the json before passing it to notification
I've made an app using Firebase Auth and Messaging, I keep sending notifications to app through Firebase Console, the problem is I can't expand the notification if it is big. How do I do it? Help Me
public class FirebaseNots extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* 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:
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.
}
// [END receive_message]
/**
* Create and show a simple notification 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);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic)
.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());
}
}
Image Please Take A Look
Thanks
You need add a BigTextStyle to your notification if you want it to be expandable to show multiple lines:
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(messageBody));
This behavior is fixed in the next release of FCM which will be release very soon.
Keep an eye on https://firebase.google.com/support/releases for the next android release and update the version of the library in you app :)
Notifications from the Firebase console do not yet support BigStyle notifications. This is a known issue and they are working on a fix, as a workaround send your notifications using the REST API using data messages, then when the message is received generate the notification yourself like #ianhanniballake is suggesting.
I am using Firebase Cloud Messaging to send push notifications.
Here is my FirebaseMessageService:
public class FireBaseMessageService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.e("TAG", "From: " + remoteMessage.getFrom());
Log.e("TAG", "Notification Message Body: " + remoteMessage.getData().get("CardName")+" : "+remoteMessage.getData().get("CardCode"));
sendNotification(remoteMessage.getNotification().getBody());
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, StartActivity.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.mipmap.ic_launcher_final)
.setContentTitle("Notification")
.setContentText(messageBody)
.setTicker("Test")
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
And FirebaseInstanceServer:
public class FirebaseInstanceService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.e("TAG", "Refreshed token: " + refreshedToken);
// TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
// Add custom implementation, as needed.
Log.e("TAG", "Refreshed token2: " + token);
}
}
Which is declared in the AndroidManifest:
<service
android:name=".util.notifications.FireBaseMessageService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".util.notifications.FirebaseInstanceService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
So issue is that when App is running ticker is shown well and notification come with default sound, but when App is in background or is not running, notification come without any sound and ticker is not shown in status bar.
Why is this happening and how can I fix it?
With FCM you specify a POST payload to send to https://fcm.googleapis.com/fcm/send. In that payload you can specify a data or a notification key, or both.
If your payload contains only a data key, your app will handle all push messages itself. E.g. they are all delivered to your onMessageReceived handler.
If your payload contains a notification key, your app will handle push messages itself only if your app is active/in the foreground. If it is not (so it's in the background, or closed entirely), FCM handles showing the notification for you by using the values you put into the notification key payload.
Note that notifications sent from a console (like Firebase console), they always include a notification key.
Looks like you want to be handling the FCM messages yourself so you can customize the notification a bit more etc, so it would be better to not include the notification key in the POST payload, so all push messages are delivered to your onMessageReceived.
You can read more about it here:
Advanced messaging options
Downstream message syntax
I spent 2 weeks to understand why my application cannot receive data message anymore when it's in background and as strange as it could be, I arrived to the conclusion that Android-Studio 2.1.2 is the problem!
I cannot receive any FCM message anymore in background application
https://github.com/firebase/quickstart-android/issues/89
{
"to": "user_device_token",
"collapse_key": "type_a",
"data": {
"body": "your message body",
"title": "notification title",
"description":"notification description ",
"imageUrl":"image url",
"key_1": "Value for key_1",
"key_2": "Value for key_2"
}
}
remove notification key from notification message json response from backend