I am sending DATA payload from Postman, so the notification should be processed in onMessageReceived regardless of whether the app is in foreground or background.
According my logs and testing, onMessageReceived is fired, but the notifications are not showing (doesn't depend if the app is in foreground or background).
in manifest I have:
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service> <!-- [END firebase_iid_service] -->
<service
android:name=".MyFirebaseInstanceIDService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
and here is MyFirebaseMessagingService.java:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String title = "";
if (Objects.requireNonNull(remoteMessage.getData()).get("title") != null)
title = remoteMessage.getData().get("title");
String message = "";
if (Objects.requireNonNull(remoteMessage.getData()).get("message") != null)
message = remoteMessage.getData().get("message");
Log.e("notification",title);
sendNotification(title, message);
}
private void sendNotification(String title, String body) {
Intent i = new Intent(this, Novinky.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pi = PendingIntent.getActivity(this,
0, // Request code
i,
PendingIntent.FLAG_ONE_SHOT);
Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this,
getString(R.string.default_notification_channel_id))
.setSmallIcon(R.mipmap.ic_notify)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(sound)
.setContentIntent(pi);
NotificationManager manager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.notify(0, builder.build());
}
}
So I have Log.e("notification",title); there, and it is executed properly, but the notify is not received.
Before I send also a notification+data via Postman, that worked, but that is only an automatic notification not handled by app, so now I want to send only DATA payload and handle it in the app, but for some reason it doesn't work.
You need to make sure you have created your notification channel in your app. A good way to do this is as follows:
public class App extends Application {
#Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel nChan = new NotificationChannel(
getString(R.string.default_notification_channel_id),
"My_Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(nChan);
}
}
}
Creating your notification channel in the onCreate() of your app is a good idea as you don't have to worry about it for the rest of the application life time.
Related
I am making music player app , I start foreground service for the music playing process. but when app is removed from recent apps foreground notification is cancelled and music still plays! , which means foreground service without notification.
i have tried : setAutoCancel(false) andsetOnGoing(true)
when creating NotificationCompat.Builder inctance and both didn't work.
my notification creation code
public class MediaStyleHelper {
public static final String CHANNEL_ID = "2229";
public static NotificationCompat.Builder from(
Context context, MediaSessionCompat mediaSession) {
MediaControllerCompat controller = mediaSession.getController();
MediaMetadataCompat mediaMetadata = controller.getMetadata();
MediaDescriptionCompat description = mediaMetadata.getDescription();
NotificationCompat.Builder builder = new NotificationCompat.Builder(context , CHANNEL_ID);
builder
.setContentTitle(description.getTitle())
.setContentText(description.getSubtitle())
.setSubText(description.getDescription())
.setLargeIcon(description.getIconBitmap())
.setContentIntent(controller.getSessionActivity())
.setDeleteIntent(
MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP))
.setAutoCancel(false)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
return builder;
}
}
the service in manifest:
<service android:name=".services.AudioPlayerService"
android:exported="false"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
and starting foreground code
private void showPlayingNotification() {
NotificationCompat.Builder builder = MediaStyleHelper.from(this, mMediaSessionCompat);
if( builder == null ) {
return;
}
builder.addAction(new NotificationCompat.Action(android.R.drawable.ic_media_pause, getString(R.string.pause), MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PLAY_PAUSE)));
builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle().setShowActionsInCompactView(0).setMediaSession(mMediaSessionCompat.getSessionToken()));
builder.setSmallIcon(R.drawable.ic_play_circle_outline);
builder.setOngoing(true);
startForeground(1,builder.build());
//NotificationManagerCompat.from(AudioPlayerService.this).notify(1, builder.build());
}
note that i created notification channel using the code:
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
channel.setSound(null,null);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
the solution was to call startService(Intent) from activity. even if i called MediaBrowserCompat.connect() and media plays correctly , I needed to call startService(Intent)!
the code after this edit is:
public void initMediaBrowserCompat(){
startService(new Intent(this,AudioPlayerService.class));
mMediaBrowserCompat = new MediaBrowserCompat(this, new ComponentName(this, AudioPlayerService.class),
mMediaBrowserCompatConnectionCallback, getIntent().getExtras());
mMediaBrowserCompat.connect();
}
I have integrated Firebase Cloud Messaging with my application.
When I sent a notification from the Firebase console, if the app is in background or not opened I receive successfully the notification,
otherwise if the app is in foreground or opened, I did not receive it.
All suggestions are appreciated.
When app is in foreground, notifications are not generated themselves. You need to write some additional code. When message is received onMessageReceived() method is called where you can generate the notification. Here is the code:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d("msg", "onMessageReceived: " + remoteMessage.getData().get("message"));
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
String channelId = "Default";
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setContentText(remoteMessage.getNotification().getBody()).setAutoCancel(true).setContentIntent(pendingIntent);;
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, "Default channel", NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
manager.notify(0, builder.build());
}
}
FirebaseMessagingService never work when the app is in foreground. In this case if you want to receive the message from FCM then WakefulBroadcastReceiver will work for you
public class FirebaseDataReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("BroadcastReceiver::", "BroadcastReceiver");
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(intent.getExtras().getString("title"))
.setContentText(intent.getExtras().getString("message"));
NotificationManager manager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}
}
Link firebase with GCM in play store and write the below code in manifest
<receiver
android:name=".firebase.FirebaseDataReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>
I made apps that need to get a notification though the apps are closed. I'm using fcm to get the notification. But when the apps are removed from the recent task, I stop getting a notification. I had seen other article but I still can't get the answer to my problem.
I'm using firebase:
'com.google.firebase:firebase-messaging:11.0.2'
MyFirebaseMessagingService.java
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = MyFirebaseMessagingService.class.getSimpleName();
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.e(TAG, "From: " + remoteMessage.getFrom());
Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());
Log.e(TAG," remote :" +remoteMessage.toString() );
try {
JSONObject json = new JSONObject(remoteMessage.getData());
String title = json.get("title").toString();
String message = json.get("message").toString();
createNottification(title, message);
}
catch (Exception ex){}
if(remoteMessage.getNotification() != null)
Log.d(TAG, "Message Notification Body: "+remoteMessage.getNotification().getBody());
}
private void createNottification(String title,String message)
{
Uri notificationSoundURI = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);;
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.mipmap.pmi_launcher)
.setSound(notificationSoundURI )
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
notificationManager.notify(Config.NOTIFICATION_ID, notification);
}
}
Manifest.xml
<!-- Firebase Notifications -->
<service android:name=".services.MyFirebaseMessagingService" android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".services.MyFirebaseInstanceIDService"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
first pass PendingIntent and also pass unique notification ID for generate bunch or stack of notification. also set Flags for notification Intent.so just do this in this way. Hope it helps to you and also other users.
private void sendNotification(String message,String title) {
int id = (int) System.currentTimeMillis();
Intent notificationIntent = new Intent(this, SplashActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle(title)
.setContentText(message)
//.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(image).setSummaryText(message))
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
} else {
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher);
}
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(id, notificationBuilder.build());
}
I have firebase push notifications set up in my android app. The first time I launch an app, I print out the device id in my FirebaseInstanceIdService. When I try to send a notification to this device id from the firebase console, it says that it was sent successfully, but I don't receive it in my FirebaseMessagingService. If I try to send once more, I get the following error:
This is how I initialize services inside manifest.xml:
<service
android:name=".MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
FirebaseInstanceIdService:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d("TEST", "Refreshed token: " + refreshedToken);
super.onTokenRefresh();
sendRegistrationToServer(refreshedToken);
}
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}
}
FirebaseMessagingService:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("TEST", "From: " + remoteMessage.getFrom());
sendNotification("sfa");
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, NewsFeedActivity.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_app_icon)
.setContentTitle("FCM Message")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 , notificationBuilder.build());
}
}
This is how I initialize FirebaseApp inside my main activity onCreate method:
FirebaseApp.initializeApp(this);
Token will be refreshed on certain conditions:
App deletes Instance ID
App is restored on a new device
User uninstalls/reinstall the app
User clears app data
You have to make sure that you are using the same token that stored in your app to send the notifications to the app. If you accidentally reinstall or clear your app data, you might want to retrieve the new token before sending the notification.
I'm trying to stack push notifications with Firebase Cloud Messaging and I'm facing a problem, I don't know how to detect that the push notification has been cleared (with a sweep or with the Clear all button).
I've tried almost every tutorial I've seen on Stackoverflow with no success, so I'm missing something.
This is what I have right now:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
final static String GROUP_KEY_EMAILS = "group_key_emails";
protected PendingIntent getContentIntent(String data)
{
Intent notificationIntent = new Intent(getApplicationContext(), SplashScreen.class);
notificationIntent.putExtra("custom", data);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
return PendingIntent.getActivity(getApplicationContext(), 1, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
protected PendingIntent getDeleteIntent()
{
Intent intent = new Intent(getApplicationContext(), NotificationBroadcastReceiver.class);
intent.setAction("notification_cancelled");
return PendingIntent.getBroadcast(getApplicationContext(), 1, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if(remoteMessage.getNotification() != null)
{
try {
Map<String, String> data = remoteMessage.getData();
String customData = data.get("custom");
JSONObject customJSON = new JSONObject(customData);
final JSONObject pushData = customJSON.getJSONObject("custom data");
String message = remoteMessage.getNotification().getBody();
Notification notif1 = new android.support.v4.app.NotificationCompat.Builder(getApplicationContext())
.setContentTitle("My app")
.setContentText(message)
.setSmallIcon(R.drawable.icon)
.setAutoCancel(true)
.setGroup(GROUP_KEY_EMAILS)
.setContentIntent(getContentIntent(customData))
.setDeleteIntent(getDeleteIntent())
.build();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(1, notif1);
AuxiliaryFunctions.addPushNotificationsMessage(getApplicationContext(), message);
int notifId = AuxiliaryFunctions.readPushNotificationsMessagesNum(getApplicationContext());
if(notifId > 1)
{
NotificationCompat.InboxStyle style = new android.support.v4.app.NotificationCompat.InboxStyle()
.setSummaryText(notifId + " new messages");
JSONArray messages = AuxiliaryFunctions.readPushNotificationsMessages(getApplicationContext());
for(int i = 0; i < messages.length(); i++)
{
String localmessage = messages.getString(i);
style.addLine(localmessage);
}
Notification summaryNotification = new android.support.v4.app.NotificationCompat.Builder(getApplicationContext())
.setContentTitle("My app "+notifId+" new messages")
.setSmallIcon(R.drawable.iconplus)
.setStyle(style)
.setGroup(GROUP_KEY_EMAILS)
.setGroupSummary(true)
.setAutoCancel(true)
.setContentIntent(getContentIntent(""))
.setDeleteIntent(getDeleteIntent())
.build();
notificationManager.notify(1, summaryNotification);
}
} catch (JSONException e) {
}
}
}
}
This is my Notification Broadcast Receiver:
public class NotificationBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.e("", "NotificationBroadcastReceiver:onReceive");
}
}
And finally I declare this in my manifest:
<receiver android:name="auxiliary.NotificationBroadcastReceiver">
<intent-filter>
<action android:name="notification_cancelled"/>
</intent-filter>
</receiver>
Well, the notifications are shown correctly, they are being stacked if there are more than one notification and if the user clicks on the notification (summary or not) everything is going well and the notification is processed with no problem.
But if the user makes a sweep in the notification (summary or not) or clicks on the Clear all notifications button, the notification dissapears but the NotificationBroadcastReceiver is never called (the log NotificationBroadcastReceiver:onReceive is not shown in the console).
What am I missing??
I'm very ashamed! I've found out the reason of my problem and it was complete stupidity.
In my AndroidManifest I had this:
<receiver android:name="auxiliary.NotificationBroadcastReceiver">
<intent-filter>
<action android:name="notification_cancelled"/>
</intent-filter>
</receiver>
I forgot the dot before auxiliary. Once I put it:
<receiver android:name=".auxiliary.NotificationBroadcastReceiver">
<intent-filter>
<action android:name="notification_cancelled"/>
</intent-filter>
</receiver>
the receiver callback was called.
What surprise me is that AndroidManifest gave no error resolving the wrong path.