2

I had setup an app on FCM to send notifications to android devices in Xamarin.Forms but only the notifications are received but images are not displayed in the system tray.

This is my AndroidManifest.xml

<application android:label="DMSMobileApp.Android">
    <receiver
    android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver"
    android:exported="false" />
    <receiver
        android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND">
      <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="${applicationId}" />
      </intent-filter>
    </receiver>
  </application>

I had created FirebaseMessagingService.cs to receive and convert to local notifications.

[Service]
    [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
    public class MyFirebaseMessagingService : FirebaseMessagingService
    {
        const string TAG = "MyFirebaseMsgService";
        public override void OnMessageReceived(RemoteMessage message)
        {
            var body = message.GetNotification().Body;
            Log.Debug(TAG, "Notification Message Body: " + body);
            SendNotification(body, message.Data);
            //new NotificationHelper().CreateNotification(message.GetNotification().Title, message.GetNotification().Body);
        }
        void SendNotification(string messageBody, IDictionary<string, string> data)
        {
            var intent = new Intent(this, typeof(MainActivity));
            intent.AddFlags(ActivityFlags.ClearTop);
            foreach (var key in data.Keys)
            {
                intent.PutExtra(key, data[key]);
            }

            var pendingIntent = PendingIntent.GetActivity(this,
                                                          MainActivity.NOTIFICATION_ID,
                                                          intent,
                                                          PendingIntentFlags.OneShot);


            var notificationBuilder = new NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
                                      .SetSmallIcon(Resource.Drawable.notification_template_icon_bg)
                                      .SetContentTitle("FCM Message")
                                      .SetContentText(messageBody)
                                      .SetAutoCancel(true)
                                      .SetContentIntent(pendingIntent);

            var notificationManager = NotificationManagerCompat.From(this);
            notificationManager.Notify(MainActivity.NOTIFICATION_ID, notificationBuilder.Build());
        }
    }

And by REST API I'm sending notifications.

var data = new
            {
                to = "/topics/ALL", // Recipient device token
                notification = new {
                    title = "Test",
                    body = "Message",
                    image = "https://cdn.pixabay.com/photo/2015/05/15/14/38/computer-768608_960_720.jpg"
                },
                image = "https://cdn.pixabay.com/photo/2015/05/15/14/38/computer-768608_960_720.jpg"
            };
var jsonBody = JsonConvert.SerializeObject(data);
            bool fcmState;
            using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, "https://fcm.googleapis.com/fcm/send"))
            {
                httpRequest.Headers.TryAddWithoutValidation("Authorization", serverKey);
                httpRequest.Headers.TryAddWithoutValidation("Sender", senderId);
                httpRequest.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json");

                using (var httpClient = new HttpClient())
                {
                    var result = await httpClient.SendAsync(httpRequest);

                    if (result.IsSuccessStatusCode)
                    {
                        fcmState = true;
                    }
                    else
                    {
                        // Use result.StatusCode to handle failure
                        // Your custom error handler here
                        //_logger.LogError($"Error sending notification. Status Code: {result.StatusCode}");
                    }
                }
            }
  1. I'm able to receive the notifications in the background and but in the foreground, I'm getting only sound but no notification in the system tray.
  2. I'm receiving notification in the system tray while the app is running in the background but not receiving the image.
Rohan Sampat
  • 930
  • 1
  • 13
  • 30

2 Answers2

4

I just solved it by downloading the image while I receive image data from FCM. Here's my code.

void SendNotification(string messageBody, IDictionary<string, string> data, RemoteMessage message)
    {
        var intent = new Intent(this, typeof(MainActivity));
        intent.AddFlags(ActivityFlags.ClearTop);
        foreach (var key in data.Keys)
        {
            intent.PutExtra(key, data[key]);
        }

        var pendingIntent = PendingIntent.GetActivity(this,
                                                      MainActivity.NOTIFICATION_ID,
                                                      intent,
                                                      PendingIntentFlags.OneShot);

        //var test = message.GetNotification().Body;
        string title = data["title"];
        string body = data["body"];
        string imageReceived = data["image"]; //It contains image URL.
        GetImageBitmapFromUrl(imageReceived); // This method will download image from URL.
        var notificationBuilder = new NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
                                  .SetSmallIcon(Resource.Drawable.logo)
                                  .SetContentTitle(title)
                                  .SetContentText(body)
                                  .SetStyle(new NotificationCompat.BigPictureStyle().BigPicture(imageBitmap)) //// This will show the image in system tray.
                                  .SetAutoCancel(true)
                                  .SetContentIntent(pendingIntent);

        var notificationManager = NotificationManagerCompat.From(this);
        notificationManager.Notify(MainActivity.NOTIFICATION_ID, notificationBuilder.Build());
    }

Code to download image if there's a link in 'image' key in Data IDictionary.

Bitmap imageBitmap = null;
    Bitmap roundedImage = null;
    public Bitmap GetImageBitmapFromUrl(string url)
    {
        using (var webClient = new System.Net.WebClient())
        {
            var imageBytes = webClient.DownloadData(url);
            if (imageBytes != null && imageBytes.Length > 0)
            {
                imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
                roundedImage = Bitmap.CreateScaledBitmap(imageBitmap, 300, 300, false);
                //roundedImage = getRoundedShape(resizedImage);
            }
            webClient.Dispose();
        }
        return roundedImage;
    }

The data which I'm sending to FCM via REST API. Thanks to @Harikrishnan, first I was using nofitication object, it worked but didn't had image data in it.

var data = new
            {
                to = "/topics/ALL", // Recipient device token
                data = new {
                    title = "Test",
                    body = "Message",
                    image = "https://cdn.pixabay.com/photo/2015/05/15/14/38/computer-768608_960_720.jpg"
                },
            };
Rohan Sampat
  • 930
  • 1
  • 13
  • 30
1

FCM Notification Have two types messages

  • Display-Messages: OnMessageReceived() callback only when your app is in foreground
  • Data-Messages: OnMessageReceivedd() callback even if your app is in foreground/background/killed.

For your first question, please have a look at the below articles for sending push notifications in Xamarin.

https://xmonkeys360.com/2019/12/08/xamarin-forms-fcm-setup-configuration-part-i/ https://xmonkeys360.com/2019/12/09/fcm-configuration-in-xamarin-forms-part-ii/

You should use Data-Message to receive background notification as per your 2nd requirement.

{
 "to" : "4OsejRWk8RF72znDZEr",

 "data": //Note that here it is sent as Data instead of notification
  {
    "body": "Hello Xamarin",
    "title": "Title"  
    "image": "image url"
  }
} 

To receive image in the notification received, am using the below code.

var imageReceived = message.Data["image"]; //Make sure you process the received image to required type based on your requirement. 
var notification = new NotificationCompat.Builder(this, MainActivity.CHANNEL_ID);
notification.SetContentIntent(pendingIntent)
                    .SetContentTitle("FCM Message")
                    .SetContentText(messageBody)
                    .SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.notification_template_icon_bg))                    .SetSmallIcon(Resource.Drawable.notification_template_icon_bg) //Pass here the image you received if that is your requirement.
                    .SetStyle(new NotificationCompat.BigTextStyle())
                    .SetPriority(NotificationCompat.PriorityHigh)
                    .SetColor(0x9c6114)
                    .SetAutoCancel(true);
notificationManager.Notify(MainActivity.NOTIFICATION_ID, notification.Build());
Harikrishnan
  • 1,474
  • 2
  • 11
  • 25
  • I Tried it but not receiving image in notification – Rohan Sampat Jan 29 '20 at 10:23
  • Please check my updated answer. That is how am using to display images. – Harikrishnan Jan 29 '20 at 11:52
  • @RohanSampat: Note that you can send the notification as Data in your JSON only for Android. For iOS, you need to send it as notification only. – Harikrishnan Jan 29 '20 at 12:00
  • @RohanSampat: If my reply helps you, please remember to mark my reply as an answer. Thanks... – Harikrishnan Jan 29 '20 at 13:00
  • By your ans I was able to send data object with all the details and image URL, but to show I had to download it from the URL. I had posted the code which solved the issue, but thanks to you for your suggestion to send data by 'Data' object instead of 'notification'. – Rohan Sampat Jan 30 '20 at 06:15
  • Hi @RohanSampat, Yes, my answer needs customization on your end as am not sure 100% sure of how you are processing the image. Thats why I mentioned on comment "Make sure you process the received image to required type based on your requirement". Happy that it helped you. Happy coding :) You can upvote/accept the answer if that helps. – Harikrishnan Jan 30 '20 at 07:36