Firebase Expandable Notification Show image when a

2019-03-09 19:12发布

问题:

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

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.

回答1:

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



回答2:

See my FirebaseMessagingService

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "FirebaseMessageService";
    Bitmap bitmap;

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // There are two types of messages data messages and notification messages. Data messages are handled
        // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
        // traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
        // is in the foreground. When the app is in the background an automatically generated notification is displayed.
        // When the user taps on the notification they are returned to the app. Messages containing both notification
        // and data payloads are treated as notification messages. The Firebase console always sends notification
        // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
        //
        Log.d(TAG, "From: " + remoteMessage.getFrom());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
        }

        //The message which i send will have keys named [message, image, AnotherActivity] and corresponding values.
        //You can change as per the requirement.

        //message will contain the Push Message
        String message = remoteMessage.getData().get("message");
        //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 MainActivity 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);

    }


    /**
     * Create and show a simple notification containing the received FCM message.
     */

    private void sendNotification(String messageBody, Bitmap image, String TrueOrFalse) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.putExtra("AnotherActivity", TrueOrFalse);
        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)
                .setLargeIcon(image)/*Notification icon image*/
                .setSmallIcon(R.drawable.firebase_icon)
                .setContentTitle(messageBody)
                .setStyle(new NotificationCompat.BigPictureStyle()
                        .bigPicture(image))/*Notification with Image*/
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

    /*
    *To get a Bitmap image from the URL received
    * */
    public Bitmap getBitmapfromUrl(String imageUrl) {
        try {
            URL url = new URL(imageUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            InputStream input = connection.getInputStream();
            Bitmap bitmap = BitmapFactory.decodeStream(input);
            return bitmap;

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;

        }
    }
}

REFERENCE HERE



回答3:

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.



回答4:

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!



回答5:

'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.



回答6:

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)



回答7:

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


回答8:

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) {

}