Skip to main content

Push Notifications in Xamarin Forms

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.

Comments

Popular posts from this blog

Change Key Dynamically in Web.Config

System.Xml; private void SetConfigSettings() { string path = Server.MapPath("Web.config"); string newConnectionString = @"Server=local;Database="+txtDatabaseName.Text+";Trusted_Connection=true"; XmlDocument xDoc = new XmlDocument(); xDoc.Load(path); XmlNodeList nodeList = xDoc.GetElementsByTagName("appSettings"); XmlNodeList nodeAppSettings = nodeList[0].ChildNodes; XmlAttributeCollection xmlAttCollection = nodeAppSettings[0].Attributes; xmlAttCollection[0].InnerXml = txtKey.Text; // for key attribute xmlAttCollection[1].InnerXml = newConnectionString; // for value attribute xDoc.Save(path); // saves the web.config file }

HTTP errors

HTTP errors are sent to your web browser from a website if a problem is encountered when trying to view a webpage. If the webpage cannot be displayed, Internet Explorer will display either the actual error page sent by the website or a friendly error message built into Internet Explorer. Below you will find some of the most common errors and ideas for how to solve the problem that's causing them. The following table lists the most common HTTP errors that Internet Explorer will display. For information about HTTP protocols, error codes, and causes, visit the World Wide Web Consortium (W3C) website. You can also search the web for specific error codes. HTTP error message What it means What you can do The webpage cannot be found (HTTP 400) Internet Explorer is able to connect to the web server, but the webpage cannot be found because of a problem with the web address (URL). This error message often happen...