42

I am implementing FCM notifications in Android, but how does notifications differ depending on the app status (background vs. foreground)?

see notifications image

I am sending the notification using the FCM API with Postman and this is the notification structure:

{ "notification": {
      "title": "Notification title",
      "body": "Notification message",
      "sound": "default",
      "color": "#53c4bc",
      "click_action": "MY_BOOK",
      "icon": "ic_launcher"
   },
   "data": {
       "main_picture": "URL_OF_THE_IMAGE"  
   },
   "to" : "USER_FCM_TOKEN"
}

The image to render is taken from data.main_picture.

I have implemented my own FirebaseMessagingService which makes the notifications display perfectly in foreground state. The notification code is the next:

NotificationCompat.BigPictureStyle notiStyle = new NotificationCompat.BigPictureStyle();
notiStyle.setSummaryText(messageBody);
notiStyle.bigPicture(picture);

Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_launcher)
            .setLargeIcon(bigIcon)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)
            .setStyle(notiStyle); code here

NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());

However, in background, the service is not even executed. In the AndroidManifest.xml, Firebase services are declared as follow:

<service
    android:name=".MyFirebaseMessagingService">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT"/>
  </intent-filter>
</service>

<service
    android:name=".MyFirebaseInstanceIDService">
  <intent-filter>
    <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
  </intent-filter>
</service>

My problem is not the LargeIcon or SmallIcon but displaying the big picture.

Thanks for your support.

AL.
  • 36,815
  • 10
  • 142
  • 281

15 Answers15

24

FCM notification messages don't support the largeIcon or bigPicture.

if you need them while in background you can use a FCM data message.

For data messages the onMessageReceived(message) method is always called, so you can use the message.getData() method and create your custom notification.

Read more about notification messages vs data messages here: https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

Diego Giorgini
  • 12,489
  • 1
  • 47
  • 50
  • 12
    onMessageReceived(message) is called only when the app is in foreground. – Anirudh Dec 08 '16 at 07:57
  • 17
    onMessageReceived(message) is not called in background – Parth Anjaria Feb 02 '17 at 10:03
  • 5
    All of you are partially correct. I was facing exactly same issue when i was sending message using firebase console. onMessageReceived doesn't call when app is in background or killed. But i send using API onMessageReceived is always called. i downloaded Advanced Rest client for Chrome and started sending notification data. onMessageReceived is called every time. Thanks to below tutorial http://androidbash.com/firebase-push-notification-android/ – Krishan Mar 14 '17 at 17:13
  • 3
    Yes, @Krishan is right. The documentation is clear once you're looking in the right place. When a FCM message contains a "notification" payload, and the app is in the background, then onMessageReceived does not get called. If it contains a "data" payload, then it *is* called, even if it's in the background (in case it's killed or not running, it's started, and then onMessageReceived is invoked). Here is the official explanation (this should be included in the answer): https://firebase.google.com/docs/cloud-messaging/android/receive – Milos Ivanovic Dec 07 '17 at 11:55
  • 2
    Check this post for image notifications in background https://sureshsala.blogspot.in/2018/01/firebase-push-notification-with-image.html – Suresh Jan 02 '18 at 04:37
  • This is the correct answer and should be marked as correct. – Swapnil Oct 24 '18 at 09:19
  • I have tested the same **Using Messaging API** from **AdvancedREST Client**. See this [blog](http://androidbash.com/firebase-push-notification-android/) – Rahul Khurana Dec 24 '18 at 11:41
14

In case some lands here in 2019, you can simply add an image field to the notification object:

    {
        notification: {
            title: title,
            body: body,
            image: "http://path_to_image"
        },
        data: {
            click_action: "FLUTTER_NOTIFICATION_CLICK",
            your_data: ...,
        },
        token: token
    }

I have tested it using Flutter on Android and I would assume it works on native Android since they both probably use the same native SDK.

gatti
  • 1,083
  • 1
  • 11
  • 25
6

If your problem is related to showing Big Image i.e. if you are sending push notification with an image from firebase console and it displays the image only if the app in the foreground. The solution for this problem is to send a push message with only data field.

{ "data": { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", "message": "Firebase Push Message Using API" "AnotherActivity": "True" }, "to" : "device id Or Device token" }

This definitely solves the problem.

Arun
  • 613
  • 1
  • 7
  • 14
  • onMessageReceived(message) is called only when the app is in foreground. Then how will sending only data field will work when app is in background? – Mayura Devani Mar 06 '17 at 05:35
  • @MayuraDevani I have not read the internal files of firebase, but i have tested it, it works if sent with only data field, even customised intents working fine. – Arun Mar 06 '17 at 09:11
  • In my case, If I use only data field, then i get push message only when application is in foreground, but not when app in background or killed. – Mayura Devani Mar 06 '17 at 09:28
  • @MayuraDevani You need to change the code in FirebaseMessagingService, there would be a check for app in foreground, remove that. Same code will be executed for all the scenarios. BTW was notification coming for sending notification with firebase console ? – Arun Mar 06 '17 at 12:38
  • Yes, Notifiation is coming when sending from firebase console. Hey, Is your code working when app is killed? I mean if you force stop your application, and then send notification, Is it working ? – Mayura Devani Mar 07 '17 at 05:44
  • Yes it is working, notification is coming even when we close the app from task manager. – Arun Mar 07 '17 at 09:20
  • Ohh, In my case it is not working. What can be the problem? I am sending only data message from server, and i am simply displaying notification in method onMessageReceived in FirebaseMessagingService without check for app in foreground or background. I am tetsing in OnePlus, Letv and Gionee devices. – Mayura Devani Mar 07 '17 at 10:15
  • Please test the same on Nexus emulator, is it working ? Also please check if there is any check in the notification utils for app in foreground/background, if you have notification utils. – Arun Mar 07 '17 at 12:39
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/137440/discussion-between-bhai-and-mayura-devani). – Arun Mar 07 '17 at 12:41
5

Messages, that contain both notification and data payload (like your example sent with Postman) are automatically displayed to end-user devices by the FCM library. And this does not include (big) images.

I guess there are two possibilities for you:

  1. Try what Rashmi Jain suggested. However, this solution could work right now and stop working tomorrow, if the Firebase library is updated (and thus the implementation of the message handling)

  2. Send a data message with Postman. You may not fill the notification object in the JSON therefore, so it could look something like this:

    {
      "message": {
        "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
        "data":{    
          "title" : "Awesome title",
          "body"  : "Your awesome push notification body",
          "image"  : "your_image_url"
        }
      }
    }
    

I would prefer the 2nd option. Good luck!

Benjamin Menrad
  • 898
  • 10
  • 14
4

Update 2019 August.

[wasted couple of days just because py doesn't support latest changes for notification]

Just add image=url into your notification object.

It works in Native Android. Just add image into notification object. Also please note that in Python library image field doesn't exist. [As of Aug 19] https://github.com/firebase/firebase-admin-python

I used PHP and this library https://github.com/kreait/firebase-php/ Its super simple and more importantly, it works for big image notification when app is in background or has been killed.

Code:

<?php

require __DIR__.'/vendor/autoload.php';
require __DIR__.'/simple_html_dom.php';

use Kreait\Firebase;
use Kreait\Firebase\ServiceAccount;
use Kreait\Firebase\Messaging\Notification;
use Kreait\Firebase\Messaging\CloudMessage;

$serviceAccount = ServiceAccount::fromJsonFile('/path/to/cred.json');

$firebase = (new Firebase\Factory())->withServiceAccount($serviceAccount)->create();
$messaging = $firebase->getMessaging();

// this works when app is closed or in bg
$notification = Notification::fromArray([
    'title' => $title,
    'body' => $body,
    'image' => $imageUrl,
]);

// for foreground process 
$data = [
    'image' => $imageUrl,
    'news_id' => $news_id,
];

$topic = 'default_topic1';

$message = CloudMessage::withTarget('topic', $topic)
    ->withNotification($notification) // optional
    ->withData($data);

$messaging->send($message);

print_r($message);
Max
  • 1,528
  • 21
  • 33
3

If you are sending push notification then get all required things in data instead of notification, for example

{
   "data": {
       "main_picture": "URL_OF_THE_IMAGE",
       "title": "Notification title",
      "click_action": "MY_BOOK", 
      "color": "#53c4bc", 
   },
   "to" : "USER_FCM_TOKEN"
}

remove notification object and get all value from data object.

Hoping that it will be work for you.

Avinash Singh
  • 4,970
  • 8
  • 20
  • 35
1

'Data' key needs to be there in Push Notification bundle.

In addition to above answers, If you are testing push notifications using FCM console, 'data' key and object is not added to Push Notification bundle. So you will not receive detailed push notification when App is background or killed.

In this case you have to opt for your back end admin console to test App background scenario.

Here, you will have added 'data' key to your push bundle. so, detailed push will be shown as expected. Hope this helps few.

Max Droid
  • 924
  • 9
  • 10
1

If anyone still having an issue with this in 2021 convert the image to bitmap and use .setStyle instead of setLargeIcon(bitmap).

val pendingIntent = PendingIntent.getActivity(this, 0, intent, FLAG_ONE_SHOT)
    val notification = NotificationCompat.Builder(this, Companion.CHANNEL_ID)
        .setContentTitle(message.data["title"])
        .setContentText(message.data["message"])
        .setStyle(NotificationCompat.BigPictureStyle().bigPicture(bitmap))
        .setSmallIcon(R.drawable.ic_home)
        .setAutoCancel(true)
        .setContentIntent(pendingIntent)
        .build()
Mridul S Kumar
  • 326
  • 1
  • 4
  • 20
1

I solved that by using the following:

{
  "to": "dllBLnfORt6Bnc3hg:APA91bGz7reSbPs-vlgy9fX-gkGRZ5zdUfFB0k9b2UwvYFuEeHwyGywtpjWOQJcxGBq4bb32Uctbh2aR2SDdA8NWRjC6posTUq8WUCHFN_knRDvEfZhkSxsSgI1rbQTfYbUpuKq1kSH_",
  "notification": {
    "body": "Queen's Platinum Jubilee award recipients honoured",
    "OrganizationId": "2",
    "content_available": true,
    "priority": "high",
    "subtitle": "Elementary School",
    "title": "Platinum price incresed!",
    "image": "https://www.thenaturalsapphirecompany.com/education/wp-content/uploads/2017/12/pyrite-pyrites-mineral-sulfide-56030.jpeg"
  },
  "data": {
    "priority": "high",
    "sound": "app_sound.wav",
    "content_available": true,
    "bodyText": "xxxxxxxxxxxxx",
    "organization": "Catalytic Price",
    "type" : "asasf"
  }
}

Add image key under notification

for more details please follow the following url: https://firebase.google.com/docs/cloud-messaging/android/send-image#rest

Abd Abughazaleh
  • 4,615
  • 3
  • 44
  • 53
0

If your expecting only one notification in a system tray for your app then the below solution can solve the problem, until FCM comes up with proper solution.

  1. remove MyFirebaseMessagingService from manifest.

    <service android:name=".MyFirebaseMessagingService">   <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT"/>   </intent-filter> </service>
    
  2. MyGcmReceiver Extend GcmReceiver class and right the notification logic.
  3. Add MyGcmReceiver in manifest

        <receiver
        android:name=".MyGcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="package_name" />
        </intent-filter>
    </receiver>
    
  4. cancelAll notifications before notifying the notification. (Otherwise firebase also, shows notification when app is in background)

Harsha Vardhan
  • 3,324
  • 2
  • 17
  • 22
0

You can send messages using this rest client tool.Using this tool You can send messages to client app in background and foreground too. To send a message using API, you can use a tool called AdvancedREST Client, its a chrome extension, and send a message with the following parameters.

Rest client tool Link: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

use this url:- https://fcm.googleapis.com/fcm/send Content-Type:application/json Authorization:key=Your Server key From or Authoization key(see below ref)

{ "data": { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", "message": "Firebase Push Message Using API" "AnotherActivity": "True" }, "to" : "device id Or Device token" }

Authorization key can be obtained by visiting Google developers console and click on Credentials button on the left menu for your project. Among the API keys listed, the server key will be your authorization key.

And you need to put tokenID of the receiver in the “to” section of your POST request sent using API.

And This piece of android code //message will contain the Push Message

    String message = remoteMessage.getData().get("message1");

    //imageUri will contain URL of the image to be displayed with Notification


    String imageUri = remoteMessage.getData().get("image");

    //If the key AnotherActivity has  value as True then when the user taps on notification, in the app AnotherActivity will be opened.

    //If the key AnotherActivity has  value as False then when the user taps on notification, in the app MainActivity2 will be opened.

    String TrueOrFlase = remoteMessage.getData().get("AnotherActivity");

    //To get a Bitmap image from the URL received

    bitmap = getBitmapfromUrl(imageUri);


    sendNotification(message, bitmap, TrueOrFlase);
Syed Danish Haider
  • 1,334
  • 11
  • 15
0

Push 5otally depends push request received and also device capabilities like in some device battery saber impacts the all what we paas is url image and not actual image in push request so device should have those capabilities to download image and android/ apk have to display the image and firebase or APNS

0

See My Code 2021 FireBase Cloud Messages

Setup 1 implementation 'com.google.firebase:firebase-messaging:23.0.'

Setup 2 create a new java class

public class FireBasePushNotification extends FirebaseMessagingService {

private static final String TAG = "FireBaseNotification";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    Map<String, String> params = remoteMessage.getData();
    if (params.size() > 0) {
        sendNotification(params.get("title"), params.get("message"));
        broadcastNewNotification();
    }else {
        sendNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
    }

}

@Override
public void onNewToken(String token) {
    Log.d(TAG, "Refreshed token: " + token);
}


private void sendNotification(String title, String messageBody) {
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.putExtra("Push Notification", title);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
    NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel mChannel = new NotificationChannel(getResources().getString(R.string.app_name),
                getResources().getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
        mChannel.enableLights(true);
        mChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
        notificationManager.createNotificationChannel(mChannel);
    }
    NotificationCompat.Builder notificationBuilder;
    notificationBuilder = new NotificationCompat.Builder(this, getResources().getString(R.string.app_name))
            .setAutoCancel(true)
            .setSmallIcon(R.drawable.ic_stat_name)
            .setColor(getResources().getColor(R.color.black))
            .setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
                    R.drawable.ic_stat_name))
            .setDefaults(Notification.DEFAULT_ALL)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setChannelId(getResources().getString(R.string.app_name))
            .setFullScreenIntent(pendingIntent, true);
    notificationManager.notify(1, notificationBuilder.build());
}

private void broadcastNewNotification() {
    Intent intent = new Intent("new_notification");
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

}

Setup 3 GO TO Manifest.xml File Replay Your Package Name com.tamilviews.firebasechack

<service
                android:name="com.tamilviews.firebasechack.FireBasePushNotification"
                android:enabled="true"
                android:exported="false">
                <intent-filter>
                    <action android:name="com.google.firebase.MESSAGING_EVENT" />
                </intent-filter>
            </service>
    
    <meta-data
                android:name="com.google.firebase.messaging.default_notification_icon"
                android:resource="@drawable/ic_stat_name" />
    
            <meta-data
                android:name="com.google.firebase.messaging.default_notification_color"
                android:resource="@color/purple_700" />
0

To show an image from push notification in foreground,

first, you must append the imageUrl field on the android section at the backend, you can find more information about this concept at:

Firebase Send URL Image

second, you can retrieve this field on the function "onMessageReceived", you can access to this field with:

remoteMessage.notification?.imageUrl

third, this is an Uri with an Url inside, you can access to the url with:

val url = URL(imageUrl?.toString())

four, you must download the content and put into a bitmap:

private fun getBitmapfromUrl(imageUrl: Uri?): Bitmap? {
    return try {
        val url = URL(imageUrl?.toString())
        val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
        connection.setDoInput(true)
        connection.connect()
        val input: InputStream = connection.getInputStream()
        BitmapFactory.decodeStream(input)
    } catch (e: Exception) {
        // TODO Auto-generated catch block
        e.printStackTrace()
        null
    }
}

five, append the bitmap to the notification:

.setLargeIcon(imageBitmap)

Saludos.

-2

Send Big Picture notification from Firebase console : Works for both background and foreground app

Instead of onMessageReceived, override zzm() of FirebaseMessagingService and create your custom notification from here

@Override
public void zzm(Intent intent) {
    Log.e(TAG, "zzm : " + intent);
    createBigPictureNotification();        
}

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}
Sagar Poshiya
  • 136
  • 3
  • 11
Rashmi Jain
  • 343
  • 2
  • 10