I am using FCM to push notification. I am passing intent to launch new activity when notification is clicked.when app is in foreground,app works fine and intent launch new activity, but when app is in background, it does not launch new activity but launch instance of default activity.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//Displaying data in log
//It is optional
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
//Calling method to generate notification
sendNotification(remoteMessage.getNotification().getBody());
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, SecActivity.class);
intent.putExtra("started_from","notification");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Firebase Push Notification")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
}
Hope you are trying to launch the mainactivity when the message is received. When the app is resumed from background your current activity is getting cleared.
From the documentation for FLAG_ACTIVITY_CLEAR_TOP:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
Try removing this flag.
I too had this same problem but i managed to have it fix with this ,
In your default activity mentioned in the manifest do this in the onCreate
if (bundle != null) {
if ((String) bundle.get("tag") != null) {
String tag = (String) bundle.get("tag");
if (tag.equals("abc")) {
Intent intent = new Intent(SplashActivity.this, MessageDetailsActivity.class);
startActivity(intent);
} else if (tag.equals("def")) {
openSpecificActivity(tag, (String) bundle.get("id"));
}
} else {
Intent i = new Intent(SplashActivity.this, HomeActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
i got a solution for that.
just put below code in oncreate method of launcher activity.
if (bundle != null) {
String value = bundle.getString("key");
if (value != null) {
startActivity(new Intent(MainActivity.this, secActivity.class));
}
}
when app is in background or killed,FCM will not call onmessagerecieved method,but it will send data to system tray to display notification.so datapayload(sent from fcm console) will not be handled by onmessagerecieved method.when user click on notification,it will launch default activity of app and datapayload will be passed by intent .so making change in oncreate method of launcher activity(as above)we can get datapayload even when app is in background or killed.(ex key is sent by fcm console).when app is in foreground datapayload and will be handled by onmessagerecieved method of fcm service.
Based upon Antinio's answer
https://stackoverflow.com/a/37845174/4454119
Why is this happening?
There are two types of messages in FCM (Firebase Cloud Messaging):
display-messages: These messages trigger the onMessageReceived() callback only when your app is in foreground
data-messages: Theses messages trigger the onMessageReceived() callback even if your app is in foreground/background/killed
Firebase team have not developed a UI to send data-messages to your devices, yet.
So you need to use data-messages..
In FCM you have two types of messages
Notification Messages
Data Messages
Use notification messages when you want FCM to handle displaying a notification on your client app's behalf. Use data messages when you want to process the messages in your client app.
If you need to process your message before sending it to the system tray, it's better to use Data messages, as for these types of messages, the callback first reaches the onMessageRecieved method before going to the system tray.
Use this:
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
IN YOUR SERVICE
"to": token,
"notification": {
"title": "Title,
"body": "Body"
},
"data" : {
"update": "yes"
}
IN ANDROID KOTLIN
val intent = Intent(this,MainActivity::class.java)
intent.putExtra("update","yes")
......
Related
On the Android app, I need to open a specific activity on clicking push notification. I am directly sending the message from the firebase FCM console. I Did the configuration below, with some condition to open different activities. It is working properly while the app is in the foreground.
While the app is in the foreground, on clicking the received notification, it opens the corresponding activity based on given condition. Everything working fine.
But while the app is in the background, on clicking push notification, it opens the main activity. Also, the message showing is the message I gave in the Notification payload of FCM(Not that given in data payload/Additional section of FCM console).
I need app to open specific activity on clicking push notification while the app is in the background as well.
Can't I do this from the FCM console directly?
please advise
public class MyFireBaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
private static int count = 0;
#Override
public void onNewToken(#NonNull String s) {
super.onNewToken(s);
Log.e(TAG, "onNewToken: " + s);
}
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
Map<String,String> opendata = remoteMessage.getData();
String actionValue = opendata.get("openactivity");
Intent intent=new Intent();
assert actionValue != null;
switch (actionValue) {
case "Activity1":
intent = new Intent(this, Activity1.class);
break;
case "Activity2":
intent = new Intent(this, Activity2.class);
break;
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("pushnotification","True");
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel("MyID", "Myapp", importance);
mChannel.setDescription(remoteMessage.getData().get("message"));
mChannel.enableLights(true);
mChannel.setLightColor(Color.RED);
mChannel.enableVibration(true);
mNotifyManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, "MyID");
mBuilder.setContentTitle(remoteMessage.getData().get("title"))
.setContentText(remoteMessage.getData().get("message"))
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.maft_logo))
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setColor(Color.parseColor("#FFD600"))
.setContentIntent(pendingIntent)
.setChannelId("Myid")
.setPriority(NotificationCompat.PRIORITY_LOW);
mNotifyManager.notify(count, mBuilder.build());
count++;
}
}
Manifest
<service
android:name=".MyFireBaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
If notification clicks on app background state, then that will open app launcher activity. In launcher activity you need to check if there is any pending intent from notification and execute that.
Try this in your launcher activity(MainActivity).
Intent intent=new Intent();
Intent fromIntent = getIntent();
if (fromIntent.getExtras()!=null){
try {
Map<String,String> opendata = remoteMessage.getData();
String actionValue = opendata.get("openactivity");
switch (actionValue){
case "Activity1":
intent=new Intent(this, Activity1.class);
break;
case "Activity2":
intent=new Intent(this, Activity2.class);
break;
default:
intent = new Intent(MainActivity.this, DefaultActivity.class);
break
}
} catch(Exception e){
intent = new Intent(MainActivity.this, DefaultActivity.class);
}
} else{
intent = new Intent(MainActivity.this, DefaultActivity.class);
}
startActivity(intent);
when your app in background, the method onMessageReceived never invoked, system notification auto show on your notification tray instead, so you need implement some logic (same in onMessageReceived method) in your main activity to navigate user to the destination screen.
There are two type of notification :
Data message notification other one is
Normal notification
In Data message notification send from server, when your app is kill then we got payload in onMessageReceive method.
But in case of Notification fire from other like console and your app is kill then you got default notification there is no callback in onMessageReceive method.
For testing you can set log in your onMessageReceive method but your log not print, when your app is kill and you fire notification from console, but with server because of data message
you got callback in onMessageReceive.
In your case everything working fine, you have to try with actual server.
I recently discovered that almost everything about the notification is managed by the cloud messaging function. You don't need to create a NotificationManager inside the onMessageReceived. The function presets the title & body. It can also set the activity to be opened when the notification is clicked.
You just need to include the payload parameter "click_action" that is sent alongside the notification. Your payload needs to look something like this:
return admin.messaging().sendToTopic(
topicId,
{
notification: {
title: "Custom title",
body: "Custom body",
click_action: "DestinationActivity"
},
data: {
"payload": myPayload
}
}
More on cloud functions here.
Now move to your project's Manifest and find the destination activity. Make the following changes (make sure to set the exported attribute to true):
<activity
android:name="DestinationActivity"
android:exported="true">
<intent-filter>
<action android:name="DestinationActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The intent filter picks the click_action parameter from the payload so any notification with "DestinationActivity" as its click action shall be handled by the Destination activity. I am starting to think that one doesn't even need to override the onMessageReceived method. FCM makes it really convenient.
I'm having a problem using the FCM Push Notification Messaging Service, as I've overridden the handleIntent() method to receive the notification when the app is in the foreground. I am also using the onMessageReceived() method.
But when the app is in the background, I will receive 2 notifications, which one of them only opens up the app and runs the MainActivity while the other is opening up the app how I want it to.
FYI: The notification I receive when I am in the foreground is exactly how I want it to open.
This is the code I've written below :
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private final String NOTIFICATION_TYPE = "type";
private final String NOTIFICATION_ID = "id";
private final String NOTIFICATION_TYPE_PRODUCT_DETAIL = "productdetail";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String title = remoteMessage.getNotification().getTitle();R
String body = remoteMessage.getNotification().getBody();
String token = remoteMessage.getFrom();
Log.d("FireBase TAG: ", token);
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d("FireBaseMessageService","FireBase Data payload : " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
}
#Override
public void handleIntent(Intent intent) {
super.handleIntent(intent);
String type = intent.getExtras().getString(NOTIFICATION_TYPE, "");
int id = 0;
try {
id = Integer.valueOf(intent.getExtras().getString(NOTIFICATION_ID, ""));
} catch (NumberFormatException e) {
e.printStackTrace();
}
//Intents
Intent mainIntent = MainActivity.newIntent(this);
Intent editProfileIntent = EditProfileActivity.newIntent(this);
Intent settingsIntent = SettingsActivity.newIntent(this);
Intent productIntent = ProductActivity.newNotificationIntent(this, id, false, true);
if (UserManager.getSingleton().isUserLoggedIn(getApplicationContext())) {
PendingIntent pendingIntent;
if (type.equalsIgnoreCase(NOTIFICATION_TYPE_PRODUCT_DETAIL)) {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(mainIntent);
stackBuilder.addNextIntent(productIntent);
editProfileIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT);
}
else {
pendingIntent = PendingIntent.getActivity(this, 0, productIntent,
PendingIntent.FLAG_ONE_SHOT);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(intent.getExtras().getString("gcm.notification.title"))
.setContentText(intent.getExtras().getString("gcm.notification.body"))
.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}
}
}
I have deleted the NotificationCompat.Builder from the onMessageReceived() method.
But I am still receiving two notifications in the background.
App Gradle :
compile 'com.google.firebase:firebase-core:11.4.2' //Firebase
compile 'com.google.firebase:firebase-messaging:11.4.2' //Firebase Cloud Messaging
I've tried searching for a solution online but unluckily there isn't a solution pointing to Android.
You are handling your Notification stuff into handleIntent(Intent intent). You should probably remove super.handleIntent(intent); to prevent the Firebase system to handle notification while the app is in background.
Solution: remove super.handleIntent(intent);
Just make a sendnotification() method and set whatever parameters you want to pass like body i.e sendnotification(String body). Use pending intent to start you activity and when you click on notification your app parse the data to the launcher activity which is defined in manifest, so once you have data in your launcher activity you can send data to other activity using intent.
I think the .setContentText("") is getting called more than 1 times and are you getting same notification two times?
The notification which works perfectly is generated by your code but when your application is not in foreground android system will generate the notification for you. In this case when you don't have the control to send data in your intent that you were sending to open your desired Activity.
In this case, you have to do some modification on your servers payload. You have to add click_action in your payload, this is how android system will identify the destination activity.
Payload Example:
{ "notification": {
"title":"Notification title",
"body":"Notification body",
"click_action":"<Your_destination_activity>",
}, "data":{
"param1":"value1",
"param2":"value2"
},
"priority":"high",
}
Reference:
https://firebase.google.com/docs/cloud-messaging/http-server-ref
yes,
When you app in background you will receive the push at system tray so system tray will create push with notification title and message.
and when you click on the push your initial launcher activity (which mentioned as launcher in manifest) will open.
you can get your notification data at you launcher activity (bundle).
private void handlePush() {
Intent intent = null;
if (bundle.getString("push_type") != null && bundle.getString("push_type").length() > 0) {
switch (bundle.getString("push_type")) {
case PUSH_TYPE_FOLLOW_USER: {
intent = new Intent(this, ProfileExternalActivity.class);
intent.putExtra(Constants.USER_ID, Integer.parseInt(bundle.getString("id")));
intent.putExtra(Constants.FROM_PUSH_NOTIFICATION_SPLASH, true);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
break;
}
}
if (intent != null)
startActivity(intent);
finish();
}
}
and you need to check activty have data or not
if (bundle != null)
handlePush();
else //your next activity
FYI : https://firebase.google.com/docs/cloud-messaging/android/receive
or
you can get payload object instead of data object inside notification , if you have payload object in your notification object, push all time received at your onMessageReceived().
for people still having this issue:
Here is a hack to prevent this behavior. I've looked all over and there seems to be minimal info about this, but if you save the actual message being sent in shared preferences and then do a check against that value in onRecieve, you can easily prevent this. The only downside is that your user can't send the exact same message two times in a row in the form of a notification (but that would be annoying anyway). example:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
SharedPreferences Settings = getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = Settings.edit();
message = remoteMessage.getNotification().getBody();
from = remoteMessage.getFrom(); //this comes through as the topic, oddly...
if(from.equals("/topics/"+userID+deviceID+"all")) {
if(!message.equals(Settings.getString("messageall",null))) {//this filters any dupe messages
utils.postNotification(title, message, context, extra, "messages");//create notification
editor.putString("messageall", message);//always update to the last message
editor.commit();
}
}
}
I am using the fcm console to send messages to all of devices that have my app installed, the notifications don't have any extra payload only the notification message.
I want to know if there is a simple way to know if an Activity was opened from an FCM notification click.
There is a solution for that by extending the FirebaseMessagingService service and creating a notification by yourself.
I want to know if there is another solution without extending the service or passing extras to the notification.
Is there any extra that is being passed with the Intent that is used for opening the activity from the notification click?
I hope you know that FCM based messaging created two types of notification
Firstly, the notification that we create from on onMessageReceived() method, the point to note here is that onMessageReceived() will be triggered if the app is in foreground.
Secondly, FCM creates its own default notification when app is in background, in this case onMessageReceived() is not intercepted and hence we cannot set a pending intent on our own.
Note : the above mentioned types comes to play when you are sending a "notification" push message to your app in the case of a me "data" message onMessageReceived() is triggered irrespective of the app being in foreground or background (the notifications sent from FCM console are "notifications" type push messages)
Coming back to your question, it is not clear if you're sending a push message from FCM console or making a FCM server request, so let's make cases here.
Message being sent by FCM Console :
send data payload from the advance section in notification panel on FCM which looks like this
when app is in foreground onMessageReceived() will be intercepted
use the code below to receive the data payload
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//Displaying data in log
//It is optional
//Calling method to generate notification
sendNotification(remoteMessage.getData());
}
//This method is only generating push notification
//It is same as we did in earlier posts
private void sendNotification(Map<String, String> messageBody) {
Intent intent = new Intent(this, SplashScreen.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
0,
setNotificationRoute(messageBody),
PendingIntent.FLAG_UPDATE_CURRENT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.sym_def_app_icon)
.setContentTitle(messageBody.get("title"))
.setContentText(messageBody.get("text"))
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
private Intent setNotificationRoute(Map<String, String> messageBody) {
Intent intent = null;
String type = messageBody.get("type");
if (type != null) {
switch (type) {
case "android": //intercept your payload here to create swit
intent = new Intent(this, MainActivity.class);
break;
default:
break;
}
}
return intent;
}
}
and if app is in background, then on notification click app will be opened on a "default" activity, you can set any activity as a default one by adding the following lines in the app manifest in the activity's intent filter:
<category android:name="android.intent.category.DEFAULT" />
inside this activity you can call to get intent extras and then get the data payload to decide on which activity you need to land on. The code is below
.
.
.
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
setNotificationRoute(getIntent().getExtras());
.
.
}
private void setNotificationRoute(Bundle extras) {
String type = extras.getString("type");
Intent intent = null;
if (type != null) {
switch (type) {
case "message":
String room = extras.getString("room");
intent = new Intent(this, MainActivity.class);
startActivity(intent);
break;
default:
break;
}
}
}
Message sent from FCM Server: the message sent from FCM consolse above is same as sending the below json body as post request to FCM server:
{
"notification": {
"title": "Hi Tester",
"text": "News for testing",
"sound": "default",
"badge": 0
},
"data":{
"type": "credits"
},
"priority": "high",
"to": "{{device_token}}"
}
the process of intercepting the notifications will be same for this case.
if you want to Start any Activity without extending FireBaseMessaging class then you can set this flags with your FCM data payload.
So whenever the user clicked on FCM Notification on System Tray.That defined Activity should open.And if you want to get extra bundle data.you can get it using getIntent().getExtras(); method.
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Match update",
"body":"Arsenal goal in added time, score is now 3-0"
},
"android":{
"ttl":"86400s",
"notification"{
"click_action":"MainActivity.class" // define your activity here
}
},
"payload": {
"aps": {
"category": "NEW_MESSAGE_CATEGORY"
}
}
}
Please refer to below link:-
"sets the appropriate keys to define the result of a user tap on the notification on Android and iOS — click_action, and category, respectively."
No need pass any extra with intent. Just set the flags like
Intent lIntent = new Intent(getApplicationContext(),YourActivity.class);
lIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
lIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
lIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(lIntent);
I have integrated the FCM in my app, I can receive the notification while the App is running or killed etc. but If the app is running then I can be able to navigate the specific screens. but If the app killed or closed, then If I clicked the notification then always it's redirect to the home screen not for the navigated area.
this is the code I used :
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Check if message contains a data payload.
// if (remoteMessage.getData().size() > 0) {
L.d(TAG, "Message data payload: " + remoteMessage.getData());
// if (remoteMessage.getNotification() != null) {
String msg = remoteMessage.getNotification().getBody();
if (!TextUtils.isEmpty(msg)) {
sendNotification(remoteMessage.getData(), msg);
}
}
private void sendNotification(Map<String, String> data, String messageBody) {
String referenceKey = data.get("ReferenceKey");
String referenceValue = data.get("ReferenceValue");
switch (referenceKey) {
case Repository.ModuleCode.BRAND:
intent = new Intent(this, WebViewActivity.class);
intent.putExtra("ID", referenceValue);
intent.putExtra("browser", false);
break;
case Repository.ModuleCode.NEWS:
intent = new Intent(this, NewDetailActivity.class);
break;
}
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_notification)
.setContentTitle(getString(R.string.app_name))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
in the manifest :
<service
android:name=".fcm.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".fcm.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
in App Gradle
compile 'com.google.android.gms:play-services:9.6.1'
compile 'com.google.android.gms:play-services-maps:9.6.1'
I cannot navigate the exact page if the app killed or closed cases only.
Thanks in advance
Finally I changed the Payload from the backend then it solved my problem.
Previously I used the PayLoad like this
{ "notification": {
"text": "Your Text1"
},
"data": {
"ReferenceKey": "PR" ,
"ReferenceValue": "10,"
},
"to" : "pushtoken"
}
then I remove the notification and used like this.
{
"data": {
"Message": "Test",
"ReferenceKey": "PR" ,
"ReferenceValue": "10,"
},
"to" : "pushtoken"
}
Then it's working for foreground / Killed / closed.
After this I cannot get notification in the xiaomi note3 only.
It's working as expected ..onMessageReceived will not get triggered if the app is killed or in background.If your app is in the background or closed then a notification message is shown in the notification center, and any data from that message is passed to the intent that is launched as a result of the user tapping on the notification.
You can use getIntent().getExtras(); for fetching the intent while launching to get the intent.
more info here;
eg:
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
if (bundle.containsKey("data")) {
Intent intent = new Intent(mContext, ExpectedActivity.Class)
intent.putExtras("PUSH_KEY",bundle.get("data").toString());
startActivity(intent)
}
}
Place this code in your launcher activity.And this will navigate you to your expected activity even when the app is killed or is in background.
Or
You can call your customized activity on click of notification if your app is in background by calling rest service api for firebase messaging as given here https://stackoverflow.com/a/37599088/3111083.
onMessageReceived only works when your application is in the foreground, if the application is in the background or killed it wont work, the notification will inflate with the title and message body. If you click on the notification it will direct you to apps launcher activity and the notification's data object can be retrieved from the getIntent in the onCreate.
The data's object key/value has already been serilies into the intent, so just extract your data with the key/varible from your data object.
For example:
Bundle extras = getIntent().getExtras();
String msg = extras.getString("time");
Note you can only get the data if the notification is clicked on.
I have a problem with notification on Android (Xamarin).
My scenario is this:
I have a class handling (inheriting GcmServiceBase) the message and creating the Notification object.
In this class I override OnMessage method in this way:
protected override void OnMessage(Context context, Intent intent)
{
if (intent != null || intent.Extras != null)
{
string messageText = intent.Extras.GetString("message");
string messageTitle = intent.Extras.GetString("title");
Intent app_launch_intent = new Intent(context, typeof(Project.WaitForm));
if (App.Instance == null)
{
Console.WriteLine("GCM: Notification received while application not running...");
app_launch_intent.AddFlags(ActivityFlags.ClearTop);
app_launch_intent.AddFlags(ActivityFlags.SingleTop);
}
else if ((App.Instance != null) && (App.Instance.mainActivity.IsInBackground))
{
App.Instance.Logger.Write("GCM: Notification received while application in background...", LogType.Default, LogLevel.Info);
app_launch_intent = new Intent(context, App.Instance.mainActivity.GetType());
}
else
{
App.Instance.Logger.Write("GCM: Notification received while application in foreground...", LogType.Default, LogLevel.Info);
app_launch_intent = new Intent(context, App.Instance.mainActivity.GetType());
app_launch_intent.AddFlags(ActivityFlags.SingleTop);
}
app_launch_intent.PutExtras(intent.Extras);
app_launch_intent.PutExtra("isNotify", true);
PendingIntent pendingIntent = PendingIntent.GetActivity(this, PushService.notificationId, app_launch_intent, PendingIntentFlags.OneShot);
createNotification(context, app_launch_intent, pendingIntent, messageTitle, messageText);
if (App.Instance == null)
{
Console.WriteLine("GCM: Notification object correctly created.");
}
else
{
App.Instance.Logger.Write("GCM: Notification object correctly created.", LogType.Default, LogLevel.Info);
}
}
}
public void createNotification(Context context, Intent result_intent, PendingIntent pendingIntent, string title, string desc)
{
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
Notification.Builder builder = new Notification.Builder(this)
.SetContentIntent(pendingIntent)
.SetAutoCancel(true)
.SetContentTitle(title)
.SetContentText(desc)
.SetSmallIcon(Resource.Drawable.notify_icon_transparent)
.SetLargeIcon(PushService.IconAgenda)
.SetTicker(title);
Notification notification = builder.Build();
PushService.notificationId += 1;
notificationManager.Notify(PushService.notificationId, notification);
}
as you can see, when message is received I test if application object exists then I create Intent and notification object (App.Instance is a singleton holding informations about the app itself. mainActivity is the current activity shown on screen).
In this way when notification is clicked, last activity on the top of the stack (current on-screen activity if app is in foreground or last on-screen activity before app went in background) will come
up and something in it will take care about notification itself, called by OnNewIntent.
Everything is working fine except for a thing:
Let's say I have 3 Activity called A, B, C.
I start the app and then I receive 2 different notifications when current activity on screen is A.
Both will be displayed in the top bar without problems.
I click on the first of them and it asks me to open another activity (catched in OnNewEvent of current activity and due to notification type), so I say "yes" and I will have a transition to activity C.
Once reached activity C and after done some work, I click on the other notification.
Clicking on it I will be carried to activity A and then notification will be handled.
I know this "problem" is because at notify creation I use the App.Instance.mainActivity.GetType() to create intent that will be use to create PendingIntent and that at that time was activity A for both.
So my question is:
How can I handle second notify click in last activity on screen (so in activity C) instead of activity A?
(I add Xamarin tag just because code above is in C# and not in Java so it may sound strange to a native Android developer)