I'm an app using Xamarin>Forms targeting IOS, Android and WP 8.

I need push notifications feature in my app.

I have seen the pushsharp demos and seems promising. But all the codes I had seen is done separately for each platform.

I would like it to be done in the Xamarin.Forms project, somewhere in the App.cs so that I don't need to repeat the code for registering device, and handle how push notifications should be processed.

Any help would be greatly appreciated. Sample codes or tutorial references are welcome.

Edit : I implemented it based on Idot's answer. Here is the link for my answer.

1 upvote
  flag
This question has been addressed in the official Xamarin Forum, have a look: forums.xamarin.com/discussion/20845/… – Wizche
upvote
  flag
Its purely based on azure, and I'm looking for pushsharp. Also its not about Xamarin forms but separate implementation for each platform. But thanks for finding me something to start on. – Rohit Vipin Mathews
upvote
  flag
check out HOL On Azure Push notification in Xamrin: onedrive.live.com/… – Bhaumik Shah

6 Answers 11

This is not possible to do in pure Xamarin.Forms but is relatively trivial to implement a solution whereby they can be handled in the App.cs (although this will require platform specific implementations).

Take a look in the IXForms implementation within the Xamarin.Forms.Labs project where the notifications are channeled back to Forms project:

https://github.com/XLabs/Xamarin-Forms-Labs

and more specifically:

https://github.com/XLabs/Xamarin-Forms-Labs/tree/master/src/Platform/XLabs.Platform/Mvvm

I have been suggested to use the following plugin by xamarin support and forms.

This plugin works well

https://github.com/rdelrosario/xamarin-plugins/tree/master/PushNotification

Will update the answer once I get it to work.

UPDATE :

I got push notifications working for both iOS and Android.

I used Google Cloud Messaging Client, an excellent component for Android, and didn't have to write much of the code as mentioned in this answer.

My iOS implementation was similar to this, not much code required.

And for Pushing the notifications from the Server I used nuget package of PushSharp.

I didn't implement in WP, as that was not required in my project.

This Xamarin Help on Push Notifications is worth reading if you are going to implement Push Notifications.

upvote
  flag
Is this solution working with Android 5+? For what I can see the GCM component is making them crash, is that correct? – Ingenator
upvote
  flag
I didn't find any issues, I will double check and get back soon. If you are having a crash please share the exact error message. – Rohit Vipin Mathews
upvote
  flag
i am really struggling with Xamarin docs for same , my listener is not getting called – saket kumar
upvote
  flag
Thanks for this, Do this plugin support for GCM's topics so that server need not to fetch the registration_ids and client application subscribed to a topic. – Shivang Gupta
upvote
  flag
@SHIVANGSANGHI - you can add sender ids. – Rohit Vipin Mathews
upvote
  flag
Could anyone please tell me why my push notification is being replaced when I receive a new one ?? :( – Vishnu Babu
upvote
  flag
@VishnuBabu - In android - give it a new Id, if you give the same Id it will update the ld one. – Rohit Vipin Mathews
upvote
  flag
@Rohit Thank you !! I But where should I set it ?? – Vishnu Babu
upvote
  flag
@VishnuBabu - notificationId in notificationManager.Notify(notificationId, notification); //allinonescript.com/questions/29029709/… – Rohit Vipin Mathews
upvote
  flag
using notificationManager will it work if app is not in the background ? I am trying to use it with this plug-in.. – Vishnu Babu
upvote
  flag
@VishnuBabu - I dont think your question is about the existing answer or question. Please start a new thread if you have any specific question. Use the notify() method to issue the notification. When you call notify(), specify a notification ID. You can use this ID to update the notification later on. This is described in more detail in Managing Notifications. - developer.android.com/training/notify-user/… – Rohit Vipin Mathews
up vote 38 down vote accepted

I just implemented push notification a few days ago, and I'll share my solution here (based on PushSharp)

Step by step guide:

1) In your shared project, create an Interface called IPushNotificationRegister

public interface IPushNotificationRegister
{
    void ExtractTokenAndRegister();
}

This interface is used for fetching the push token and then send it to the server. this Token is unique per device.

2) In Your shared proejct, you should invoke ExtractTokenAndRegister (using your favourite IOC, I called it right after login).

Android Implementation:

3) Add Receivers for listening to events received by Google GCM service:

a)

[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class GCMBootReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        MyIntentService.RunIntentInService(context, intent);
        SetResult(Result.Ok, null, null);
    }
}

b)

[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]

namespace Consumer.Mobile.Droid.PushNotification
{
    [BroadcastReceiver(Permission = "com.google.android.c2dm.permission.SEND")]
    [IntentFilter(new string[] { "com.google.android.c2dm.intent.RECEIVE" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.c2dm.intent.REGISTRATION" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter(new string[] { "com.google.android.gcm.intent.RETRY" }, Categories = new string[] { "@PACKAGE_NAME@" })]
    [IntentFilter (new[]{ Intent.ActionBootCompleted }, Categories = new[]{ Intent.CategoryDefault })]
    public class GCMBroadcastReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            MyIntentService.RunIntentInService(context, intent);
            SetResult(Result.Ok, null, null);
        }
    }
}

c) Add Intent service to process the notification

using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Media;
using Android.OS;
using Android.Support.V4.App;
using Consumer.Mobile.Infra;
using Consumer.Mobile.Services.PushNotification;
using Java.Lang;
using XLabs.Ioc;
using TaskStackBuilder = Android.Support.V4.App.TaskStackBuilder;

namespace Consumer.Mobile.Droid.PushNotification
{
    [Service]
    public class MyIntentService : IntentService
    {
        private readonly ILogger _logger;
        private readonly IPushNotificationService _notificationService;
        private readonly IPushNotificationRegister _pushNotificationRegister;

        public MyIntentService()
        {
            _logger = Resolver.Resolve<ILogger>();
            _notificationService = Resolver.Resolve<IPushNotificationService>();
            _pushNotificationRegister = Resolver.Resolve<IPushNotificationRegister>();
        }

        static PowerManager.WakeLock _sWakeLock;
        static readonly object Lock = new object();


        public static void RunIntentInService(Context context, Intent intent)
        {
            lock (Lock)
            {
                if (_sWakeLock == null)
                {
                    // This is called from BroadcastReceiver, there is no init.
                    var pm = PowerManager.FromContext(context);
                    _sWakeLock = pm.NewWakeLock(
                    WakeLockFlags.Partial, "My WakeLock Tag");
                }
            }

            _sWakeLock.Acquire();
            intent.SetClass(context, typeof(MyIntentService));
            context.StartService(intent);
        }

        protected override void OnHandleIntent(Intent intent)
        {
            try
            {
                Context context = this.ApplicationContext;
                string action = intent.Action;

                if (action.Equals("com.google.android.c2dm.intent.REGISTRATION"))
                {
                    HandleRegistration(context, intent);
                }
                else if (action.Equals("com.google.android.c2dm.intent.RECEIVE"))
                {
                    HandleMessage(context, intent);
                }
            }
            finally
            {
                lock (Lock)
                {
                    //Sanity check for null as this is a public method
                    if (_sWakeLock != null)
                        _sWakeLock.Release();
                }
            }
        }

        private void HandleMessage(Context context, Intent intent)
        {

            Intent resultIntent = new Intent(this, typeof(MainActivity));


            TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);

            var c = Class.FromType(typeof(MainActivity));
            stackBuilder.AddParentStack(c);
            stackBuilder.AddNextIntent(resultIntent);

            string alert = intent.GetStringExtra("Alert");
            int number = intent.GetIntExtra("Badge", 0);

            var imageUrl = intent.GetStringExtra("ImageUrl");
            var title = intent.GetStringExtra("Title");

            Bitmap bitmap = GetBitmap(imageUrl);

            PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, (int)PendingIntentFlags.UpdateCurrent);

            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .SetAutoCancel(true) // dismiss the notification from the notification area when the user clicks on it
                .SetContentIntent(resultPendingIntent) // start up this activity when the user clicks the intent.
                .SetContentTitle(title) // Set the title
                .SetNumber(number) // Display the count in the Content Info
                .SetSmallIcon(Resource.Drawable.Icon) // This is the icon to display
                .SetLargeIcon(bitmap)
                .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
                .SetContentText(alert); // the message to display.

            // Build the notification:
            Notification notification = builder.Build();

            // Get the notification manager:
            NotificationManager notificationManager =
                GetSystemService(Context.NotificationService) as NotificationManager;

            // Publish the notification:
            const int notificationId = 0;
            notificationManager.Notify(notificationId, notification);
        }

        private void HandleRegistration(Context context, Intent intent)
        {
            var token = intent.GetStringExtra("registration_id");
            _logger.Info(this.Class.SimpleName, "Received Token : " + token);

            if (_pushNotificationRegister.ShouldSendToken(token))
            {
                var uid = Android.Provider.Settings.Secure.GetString(MainActivity.Context.ContentResolver, Android.Provider.Settings.Secure.AndroidId);
                _notificationService.AddPushToken(token, DeviceUtils.GetDeviceType(), uid);
            }
        }


        private Bitmap GetBitmap(string url)
        {

            try
            {
                System.Net.WebRequest request =
                    System.Net.WebRequest.Create(url);
                System.Net.WebResponse response = request.GetResponse();
                System.IO.Stream responseStream =
                    response.GetResponseStream();
                return BitmapFactory.DecodeStream(responseStream);


            }
            catch (System.Net.WebException)
            {
                return null;
            }

        }

    }
}

d) Implement the Interface IPushNotificationRegister:

using Android.App;
using Android.Content;
using Consumer.Mobile.Services;
using Consumer.Mobile.Services.PushNotification;
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]

// Gives the app permission to register and receive messages.
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]

// Needed to keep the processor from sleeping when a message arrives
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
[assembly: UsesPermission(Name = "android.permission.RECEIVE_BOOT_COMPLETED")]
namespace Consumer.Mobile.Droid.PushNotification
{
    public class PushNotificationRegister : IPushNotificationRegister
    {          
        public override void ExtractTokenAndRegister()
        {
            string senders = AndroidConfig.GCMSenderId;
            Intent intent = new Intent("com.google.android.c2dm.intent.REGISTER");
            intent.SetPackage("com.google.android.gsf");
            intent.PutExtra("app", PendingIntent.GetBroadcast(MainActivity.Context, 0, new Intent(), 0));
            intent.PutExtra("sender", senders);
            MainActivity.Context.StartService(intent);
        }


    }
}

iOS implementation:

4) In your AppDelegate , add the following method:

a)

public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    var deviceTokenString = deviceToken.ToString().Replace("<","").Replace(">", "").Replace(" ", "");
    var notificationService = Resolver.Resolve<IPushNotificationService>();
    var pushNotificationRegister = Resolver.Resolve<IPushNotificationRegister>();

    if (pushNotificationRegister.ShouldSendToken(deviceTokenString))
    {
        var uid = UIDevice.CurrentDevice.IdentifierForVendor.AsString();
        notificationService.AddPushToken(deviceTokenString, DeviceUtils.GetDeviceType(), uid);
    }
}

b) Implement IPushNotificationRegister :

using Consumer.Mobile.Services;
using Consumer.Mobile.Services.PushNotification;
using UIKit;

namespace Consumer.Mobile.iOS.PushNotification
{
    public class iOSPushNotificationRegister : IPushNotificationRegister
    {
        public override void ExtractTokenAndRegister()
        {
            const UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
            UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
        }
    }
}

Regarding WP, I didn't implemented it.

If you need the code in the server side using PushSharp, let me know.

You can check the client samples I've based my solution here

upvote
  flag
Thank you. I will certainly have a look at it. No I wont need the server side code. – Rohit Vipin Mathews
1 upvote
  flag
Where are you handling the DidReceiveRemoteNotification for IOS? – Rohit Vipin Mathews
upvote
  flag
I didn't, if you want to add custom behavior for showing notifications while the app is running, you'll need to handle it in the AppDelegate class: public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo) {} – IdoT
upvote
  flag
You have broadcast receiver for android that is why i was curious – Rohit Vipin Mathews
upvote
  flag
You are right, I kept BootReceiver as I followed the guide, You can remove it if you're not interested in handling notifications while your app is running. – IdoT
upvote
  flag
Hi, @IdoT , I am starting using PushSharp, I want to know if there is a way to get the Apple response after a remote notification is sent to a device. I have an old windows service I created a long time ago where I was able to get response (if OK or failure). But since now I have to use multi-platform notifications I need to use PushSharp if possible. Thanks. – Fernando Pardo
upvote
  flag
Yes you can! You can check the sample code here: github.com/Redth/PushSharp/blob/master/PushSharp.Sample/… where you can register to a notification 'OnNotificationSent' and others that indicate it failed. – IdoT
upvote
  flag
Yes, sorry I just found OnNotificationFailed 1 minute ago and was going to put here =) thank you for your help! – Fernando Pardo
upvote
  flag
@IdoT I'm interested in the code server side, do you have a link or if you prefer I can open a new question regarding it. – DQuaglio
upvote
  flag
As I stated above, I used PushSharp, if you have a question on the implementation, then please open a question and I'll happily answer, as it is not relevant for the client implementation here. – IdoT
upvote
  flag
@DQuaglio - See the last part of my answer, I have mentioned what I used. – Rohit Vipin Mathews
upvote
  flag
@IdoT your Github link for a client is not working. So could you please send me link for both client and server side using Pushsharp – pArth savadiya
upvote
  flag
@pArthsavadiya - please check the reference, you can find in the main page all relevant samples – IdoT
upvote
  flag
Actually I dont find IPushNotificationService interface. Where do I find that ? – Anik Saha
upvote
  flag
@AnikSaha - this is described in step #1, you need to create it. – IdoT

There is a blog post recently here about implementing Push Notifications on Xamarin Forms (well each individual platform because there is no Forms based implementation), using Azure Mobile Services.

http://www.xamarinhelp.com/push-notifications/

In Xamarin Forms you could also use a notifications SDK like Donky (which is the European equivalent to the American Urban Airship); you can easily make a scalable notifications project in a single day, I've twice built WhatsApp clone shells in under 35 minutes each time using this SDK. See http://docs.mobiledonky.com

You might look at the Appboy Component which has support for this out of the box. https://components.xamarin.com/view/appboy-sdk-bindings

As others have said, you can't do generically without some platform-specific components.

Not the answer you're looking for? Browse other questions tagged or ask your own question.