How to send a reply from a notification? - android

I'm doing an app that manages the received notifications. Currently, I'm implementing a feature that the user can reply through the reply action, but I couldn't find a way to properly set the reply message and send the message.
Here is what I have tried
fun sendReplyMessage(sbn: StatusBarNotification, replyMessage: String) {
sbn.notification.actions.firstOrNull { it.remoteInputs != null }?.let { action ->
action.remoteInputs?.get(0)?.extras
?.putCharSequence(action.remoteInputs?.get(0)?.resultKey, replyMessage)
action.actionIntent.send()
}
}

You have to get the notification action to access the pending intent, add the remote input on this intent, and then, call the method PendingIntent#send(context, requestCode, intent)
val notificationAction: android.app.Notification.Action = "Get the Action here"
val bundle = Bundle().apply{
putString(remoteInput.resultKey, "Add the text here")
}
val intent = Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
RemoteInput.addResultsToIntent(notificationAction.getRemoteInputs(), intent, bundle)
notificationAction.actionIntent.send(context, 0, intent)

Related

How to send Intent.ACTION_SEND inside BroadcastReceiver's onReceive?

I want to add an action to my notification, when the user clicks the button, it shares the text of the notification with other apps, here is my code:
class NotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val message = intent?.getStringExtra("sharedMessage")
val shareIntent: Intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_TEXT, message)
type = "text/plain"
}
shareIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
if (context != null) {
if (shareIntent.resolveActivity(context.packageManager) != null) {
context.startActivity(shareIntent)
}
}
}
}
The onReceive function can receive the click action, but it does not start my shareIntent which should prompt the user to choose an app for sharing. What is the issue?
There are restrictions on background processes (Service and BroadcastReceiver) launching activities. See https://developer.android.com/guide/components/activities/background-starts
This is probably why you aren't seeing the Activity launch.
However, why are you doing this in such a roundabout way? If you want an Activity launched when the user clicks on the notification, just do that directly instead of having the notification click start a BroadcastReceiver.

How to send a request when push notification is cancelled in Android

When an application receives push notification from FCM, it calls onMessageReceived. (See 1, 2 or 3.)
When a user taps the notification, it launches the applications, then it sends a request to a server that the user has read the notification.
I want to know when a device received a push notification, but the user swiped it (or cleared all notifications). I want to send a request to the server that the user simply cancelled the notification.
I tried to send BroadcastReceiver and show logs (see 4 or 5), but it works when the application was opened when the notification delivered. I suppose, that
MyFirebaseMessagingService:
override fun onMessageReceived(remoteMessage: RemoteMessage) {
...
// An event when a user swipes a notification.
val intent = Intent(this, NotificationBroadcastReceiver::class.java)
intent.action = "notification_cancelled"
val deleteIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
notificationBuilder.setDeleteIntent(deleteIntent)
// Navigation to an activity when a user taps the notification.
// It doesn't matter to this question.
val intent2 = Intent(this, MainActivity::class.java)
val navigateIntent = PendingIntent.getActivity(this, notificationId, intent2,
PendingIntent.FLAG_UPDATE_CURRENT)
notificationBuilder.setContentIntent(navigateIntent)
...
}
NotificationBroadcastReceiver:
class NotificationBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Timber.d("NotificationBroadcastReceiver onReceive")
Toast.makeText(context, "Notification dismissed", Toast.LENGTH_LONG).show()
// Send a request to the server.
}
}
AndroidManifest:
<uses-permission android:name="com.uremont.NOTIFICATION_PERMISSION" />
<receiver
android:name=".receiver.NotificationBroadcastReceiver"
android:exported="true"
android:permission="NOTIFICATION_PERMISSION"
>
<intent-filter>
<action android:name="notification_cancelled" />
</intent-filter>
</receiver>
works only when the application is opened. But when the application is in background or killed, it doesn't react to swipe. Probably we shouldn't use BroadcastReceiver, for instance, use PendingIntent.getService or PendingIntent.getForegroundService.
Can we send a request to the server?
After a short time it worked right (though I hardly changed much). After a lot of research I made this solution. Tested on several Android emulators and devices from API 19 to API 30.
Because using BroadcastReceiver is not safe, add in AndroidManifest:
<receiver
android:name=".NotificationBroadcastReceiver"
android:exported="false"
/>
NotificationBroadcastReceiver:
class NotificationBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Timber.d("NotificationBroadcastReceiver onReceive")
if (intent.extras != null) {
// Receive parameters of a cancelled notification.
val authToken = intent.getStringExtra(EXTRA_TOKEN)
val code = intent.getStringExtra(EXTRA_CODE)
Timber.d("token = $authToken, code = $code")
// We can access context even if the application was removed from the recent list.
Toast.makeText(context, "Notification $code was cancelled", Toast.LENGTH_SHORT).show()
// Send data to a server.
}
}
companion object {
const val EXTRA_TOKEN = "EXTRA_TOKEN"
const val EXTRA_CODE = "EXTRA_CODE"
}
}
MyFirebaseMessagingService:
override fun onMessageReceived(remoteMessage: RemoteMessage) {
...
// Get notification code from data.
val code = remoteMessage.data["code"]
val notificationBuilder = NotificationCompat.Builder(this,
...
val notificationId = Random.nextInt()
val intent = Intent(this, NotificationBroadcastReceiver::class.java).apply {
putExtra(EXTRA_TOKEN, authToken)
putExtra(EXTRA_CODE, code)
}
val deleteIntent = PendingIntent.getBroadcast(this, notificationId, intent,
PendingIntent.FLAG_CANCEL_CURRENT)
notificationBuilder.setDeleteIntent(deleteIntent)
val notification = notificationBuilder.build()
notificationManager.notify(notificationId, notification)
}
Send a push message to Android device with it's push token, for instance:
{
"to": "ddSOGiz4QzmY.....:APA91bHgoincFw.......",
"data": {
"title": "Test",
"message": "Test",
"code": "ABCDEF"
}
}
You can see different schemes of delivering push messages here. If a user presses "Force stop" at the application, it won't receive push messages (except "AliExpress", ha-ha).
When the user dismisses push notification, NotificationBroadcastReceiver::onReceive() is called. An application gets parameters of the push message. Then we can see a toast message and send these parameters to the server.
When the user presses "Clear all" notifications, all dismiss events are fired. So, you will see a sequence of toasts. The server will receive several requests simultaneously (check that it can handle, for instance, 10 requests in 0.01 second).

How to handle notifications with FCM when app is in either foreground or background

I used firebase to build My project.
It will also use the FCM (firebase cloud message).
But there is a problem. I can't handle the FCM (create my custom notificaion) when app is in background.
The official site tutorial said that
case 1: App foreground -> override the "onMessageReceived()" to create your custom notification.
case 2: App background -> System will create the notification directly. We needn't and can't do anything. Because it doesn't trigger the "onMessageReceived()" in this case.
However if I can do nothing when app is background, I can't create my custom notification. (e.g. After Users click the notification and it will pop up a window to show detail information.)
So how do I handle notifications with FCM when app is in background?
There is a bad news. Google change the Firebase source code in version 'com.google.firebase:firebase-messaging:11.6.0'.
handelIntent is "public final void method" now. which means we can't override it .
If you want to use the solution, change the version to be "com.google.firebase:firebase-messaging:11.4.2"
Try my way. It can perfectly work on the project build version is Android 6.0 above(api level 23) and I have tried it already.
There is better way than official site tutorial
The official site said that the notification will be created by system when app is in background. So you can't handle it by overriding the "onMessageReceived()". Because the "onMessageReceived()" is only triggered when app is in foreground.
But the truth is not. Actually the notificaions (when app is in background) are created by Firebase Library.
After I traced the firebase library code. I find a better way.
Step 1. Override the "handleIntent()" instead of "onMessageReceived()" in FirebaseMessagingService
why:
Because the method will be trigger either app is in foreground or the background. So we can handle FCM message and create our custom notifications in both cases.
#Override
public void handleIntent(Intent intent) {
Log.d( "FCM", "handleIntent ");
}
Step 2. Parse the message from FCM
how:
If you don't know the format of the message you set. Print it and try to parse it.
Here is the basic illustration
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
Log.d("FCM", "Key: " + key + " Value: " + value);
}
}
Step 2. Remove the notifications created by Firebase library when the app is in background
why:
We can create our custom notification. But the notification created by Firebase Library will still be there (Actually it created by ""super.handleIntent(intent)"". There is detail explaination below.). Then we'll have two notifcations. That is rather weird. So we have to remove the notificaion created by Firebase Library
how (project build level is Android 6.0 above):
Recognize the notifications which we want to remove and get the informaion. And use the "notificationManager.cancel()" to remove them.
private void removeFirebaseOrigianlNotificaitons() {
//check notificationManager is available
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null )
return;
//check api level for getActiveNotifications()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//if your Build version is less than android 6.0
//we can remove all notifications instead.
//notificationManager.cancelAll();
return;
}
//check there are notifications
StatusBarNotification[] activeNotifications =
notificationManager.getActiveNotifications();
if (activeNotifications == null)
return;
//remove all notification created by library(super.handleIntent(intent))
for (StatusBarNotification tmp : activeNotifications) {
Log.d("FCM StatusBarNotification",
"StatusBarNotification tag/id: " + tmp.getTag() + " / " + tmp.getId());
String tag = tmp.getTag();
int id = tmp.getId();
//trace the library source code, follow the rule to remove it.
if (tag != null && tag.contains("FCM-Notification"))
notificationManager.cancel(tag, id);
}
}
The my whole sample code:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static int notificationCount=0;
#Override
public void handleIntent(Intent intent) {
//add a log, and you'll see the method will be triggered all the time (both foreground and background).
Log.d( "FCM", "handleIntent");
//if you don't know the format of your FCM message,
//just print it out, and you'll know how to parse it
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
Log.d("FCM", "Key: " + key + " Value: " + value);
}
}
//the background notification is created by super method
//but you can't remove the super method.
//the super method do other things, not just creating the notification
super.handleIntent(intent);
//remove the Notificaitons
removeFirebaseOrigianlNotificaitons();
if (bundle ==null)
return;
//pares the message
CloudMsg cloudMsg = parseCloudMsg(bundle);
//if you want take the data to Activity, set it
Bundle myBundle = new Bundle();
myBundle.putSerializable(TYPE_FCM_PLATFORM, cloudMsg);
Intent myIntent = new Intent(this, NotificationActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.putExtras(myBundle);
PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationCount, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//set the Notification
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.icon)
.setContentTitle(cloudMsg.getTitle())
.setContentText(cloudMsg.getMessage())
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationCount++, notificationBuilder.build());
}
/**
* parse the message which is from FCM
* #param bundle
*/
private CloudMsg parseCloudMsg(Bundle bundle) {
String title = null, msg=null;
//if the message is sent from Firebase platform, the key will be that
msg = (String) bundle.get("gcm.notification.body");
if(bundle.containsKey("gcm.notification.title"))
title = (String) bundle.get("gcm.notification.title");
//parse your custom message
String testValue=null;
testValue = (String) bundle.get("testKey");
//package them into a object(CloudMsg is your own structure), it is easy to send to Activity.
CloudMsg cloudMsg = new CloudMsg(title, msg, testValue);
return cloudMsg;
}
/**
* remove the notification created by "super.handleIntent(intent)"
*/
private void removeFirebaseOrigianlNotificaitons() {
//check notificationManager is available
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null )
return;
//check api level for getActiveNotifications()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//if your Build version is less than android 6.0
//we can remove all notifications instead.
//notificationManager.cancelAll();
return;
}
//check there are notifications
StatusBarNotification[] activeNotifications =
notificationManager.getActiveNotifications();
if (activeNotifications == null)
return;
//remove all notification created by library(super.handleIntent(intent))
for (StatusBarNotification tmp : activeNotifications) {
Log.d("FCM StatusBarNotification",
"tag/id: " + tmp.getTag() + " / " + tmp.getId());
String tag = tmp.getTag();
int id = tmp.getId();
//trace the library source code, follow the rule to remove it.
if (tag != null && tag.contains("FCM-Notification"))
notificationManager.cancel(tag, id);
}
}
}
However if I can do nothing when app is background, I can't create my custom notification. (e.g. After Users click the notification and it will pop up a window to show detail information.)
So how do I handle notifications with FCM when app is in background?
First, you need to create correct message payload that you send to fcm server. Example:
{
"to": "topic_name",
"priority": "high",
"data": {
"field1": "field1 value"
"field2": "field2 value"
}
"notification" : {
"body" : "Lorem ipsum",
"title" : "sampke title"
"click_action": "SHOW_DETAILS"
}
}
data payload is actual data you want to show as message details after user clicks on notification, notification payload represents how generated notification should look (there are much more attributes possible to set), you don't need to build notification by yourself, you only need to set it properties here.
To show your activity after user taps on notication, you need to set intent filter corresponding to click_action:
<intent-filter>
<action android:name="SHOW_DETAILS"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
so activity that have above intent filter will be launched automatically when user taps to notification.
Last step is to retrieve data when activity is launched after notification tap. It's pretty easy. Custom data is passed to activity via bundle. Inside onCreate method for your activity do something like that:
Bundle bundle = getIntent().getExtras();
if(bundle.getString("action").equals("SHOW_DETAILS")) /*This indicates activity is launched from notification, not directly*/
{
//Data retrieved from notification payload send
String filed1 = bundle.getString("field1");
String filed2 = bundle.getString("field2");
}
All of above is valid if app is not running or it's in background. If your app is foreground, no notification will be created. Instead, you will receive onMessageReceived() event so you can handle the same data there (I guess you know how).
Reference:
https://firebase.google.com/docs/cloud-messaging/http-server-ref
https://github.com/firebase/quickstart-android/tree/master/messaging
You need to use FCM data messages in order to create custom notification in a android app.Even your app is in background, onMessageReceived will be called, so you can process the data and show the custom notification.
https://firebase.google.com/docs/cloud-messaging/android/receive
Data message format which has to be sent from server:
{"message":{
"token":"Your Device Token",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
FCM Won't send a background notification if your app is killed any more, and as you described in your answer about the handleIntent() solution It may work for some devices and for some old version of the FCM, also if you #override method that doesn't described in the official doc's of firebase you may struggle some problems here, and you use it on your own risk!.
What is the solution?
You need to use your own push-notification-service beside FCM like Telegram.
OR using SyncAdapter beside GCM like Gmail.
So if you need it to work successfully like those apps, you have to use your own hack.
public class FirebaseMessageReceiver extends FirebaseMessagingService{
private static final String TAG = "main";
String s12;
String channel_id = "general";
Intent intent;
#Override
public void onNewToken(#NonNull String token)
{
Log.d(TAG, "Refreshed token: " + token);
}
#Override
public void
onMessageReceived(RemoteMessage remoteMessage) {
s12=remoteMessage.getNotification().getClickAction();
Log.d("tttt",(remoteMessage.getData().toString()));
Log.d("ttttttt",(remoteMessage.getNotification().toString()));
if (remoteMessage.getNotification() != null) {
showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
}
//
}
public void handleIntent(Intent intent)
{
try
{
if (intent.getExtras() != null)
{
RemoteMessage.Builder builder = new RemoteMessage.Builder("FirebaseMessageReceiver");
for (String key : intent.getExtras().keySet())
{
builder.addData(key, intent.getExtras().get(key).toString());
}
onMessageReceived(builder.build());
}
else
{
super.handleIntent(intent);
}
}
catch (Exception e)
{
super.handleIntent(intent);
}
}
private RemoteViews getCustomDesign(String title, String message) {
RemoteViews remoteViews = new RemoteViews(getApplicationContext().getPackageName(), R.layout.notification);
remoteViews.setTextViewText(R.id.title111, title);
remoteViews.setTextViewText(R.id.message111, message);
remoteViews.setImageViewResource(R.id.icon111, R.drawable.favicon);
return remoteViews;
}
// Method to display the notifications
public void showNotification(String title, String message) {
intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(s12));
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent notifyIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Log.d("notifyy",notifyIntent.toString());
NotificationCompat.Builder builder
= new NotificationCompat
.Builder(getApplicationContext(),
channel_id)
.setSmallIcon(R.drawable.favicon)
.setAutoCancel(true)
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
.setOnlyAlertOnce(true)
.setContentIntent(notifyIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
builder = builder.setContent(getCustomDesign(title, message));
}
else {
builder = builder.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.drawable.favicon);
}
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Check if the Android Version is greater than Oreo
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(channel_id, "web_app",
NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(
notificationChannel);
}
notificationManager.notify(0, builder.build());
}
}

Mvvmcross Android Notification Pass Parameter to Existing ViewModel

I have a foreground service with a notification. When the user clicks the notification, it will bring the user back to the main screen viewmodel (or load it again if unloaded).
I want to add 2 actions (pause, stop) to the notification. It is preferred to call the same viewmodel with a parameter to indicate the action type, and let the main screen viewmodel to handle the action. As the main screen viewmodel may have been loaded already, no more initialization will be executed. Passing parameter like showing viewmodel does not work. The existing viewmodel does not know it was triggered from the notification indeed.
How can I pass a different parameter for each action type to the viewmodel, and retrieve it in the viewmodel to act accordingly? Or it should be done in a different way?
This is the code of the notification:
var request = MvxViewModelRequest<RouteLayoutViewModel>.GetDefaultRequest();
var intent = Mvx.Resolve<IMvxAndroidViewModelRequestTranslator>().GetIntentFor(request);
const int pendingIntentId = 0;
PendingIntent pendingIntent = PendingIntent.GetActivity(Application.Context, pendingIntentId, intent, PendingIntentFlags.UpdateCurrent);
var builder = new NotificationCompat.Builder(this);
builder
.SetContentTitle(AppConstants.AppName)
.SetContentText("notification_text")
.SetSmallIcon(Resource.Drawable.Icon)
.SetContentIntent(pendingIntent); ..........
var notification = builder.Build();
StartForeground(AppConstants.SERVICE_RUNNING_NOTIFICATION_ID, notification);
Thanks,
Nick
MvvmCross 5 changed the way the ViewModel parameters are serialized internally. MvvmCross 5 hasn't been updated yet to handle this scenario AFAIK. Here is some sample code demonstrating how to workaround the issue using a BroadcastReceiver currently. This approach will allow you to navigate with parameters after the user clicks on the Android Notification.
When you're building the notification:
var intent = new Intent(context, typeof(YourBroadcastReceiver));
intent.SetAction("YOUR_ACTION");
// Put your other parameters here...
intent.PutExtra("id", id);
var pendingIntent = PendingIntent.GetBroadcast(context, _notificationId, intent, PendingIntentFlags.UpdateCurrent);
...
notificationBuilder.SetContentIntent(pendingIntent);
Then you add a BroadcastReceiver class like so:
[BroadcastReceiver]
public class YourBroadcastReceiver : MvxBroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == "YOUR_ACTION")
{
// TODO: Extract the contents from the intent.
var id = intent.GetIntExtra("id", 0);
// TODO: Navigate using IMvxNavigationService using the parameters pulled from the Intent.
}
}
}

FCM Push Notification Android receiving 2 notifications in the background

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();
}
}
}

Categories

Resources