Mobile App: Xamarin Forms Push Notification

En los últimos post os estoy hablando de cómo sacar provecho a Azure Mobile Apps tanto con Apache Cordova como con Xamarin Forms. Para cerrar el círculo nos queda ver como enviar notificaciones push a través de Azure Mobile Apps en Xamarin Forms.

En concreto veremos cómo hacerlo para android. Para ello necesitaremos crear una Azure Mobile App y habilitar Google Cloud Messaging, para ello seguir los pasos de mi post sobre notificaciones push con Apache Cordova.

Para seguir el siguiente el ejemplo os aconsejo que os descargáis el código de aquí para que podáis seguir el post de una forma más confortable.

Primero debemos crear el proyecto de Xamarin Forms, tenéis los pasos aquí. De este post también debéis coger el código de ServiceManger.cs donde tendremos la instancia a nuestra Azure Mobile App.

Una vez creado necesitamos añadir un componente a nuestro proyecto android (yourprojectname.Droid), concretamente  Google Cloud Messaging Client.
selectexportsql
selectexportsql
selectexportsql

Ahora ya podemos utilizar GCM.Client.dll que nos ayudará a implementar y controlará todo lo referente a notificaciones push en android.

Lo primero que haremos es crear en MainActivity.cs una propiedad donde guardaremos la instancia actual de nuestra activity ya que la necesitaremos en el proceso de registro del dispositivo en el hub de notificaciones push.

static MainActivity instance = null; 

// Devuleve la activity actual
public static MainActivity CurrentActivity
{
   get
   {
     return instance;
   }
}

Ahora creamos un método llamado RegisterNoticationPush que nos servirá para registrar el dispositivo par poder recibir notificaciones push.

private void RegisterNotificationsPush()
{
  try
  {
   // Validamos que todo este correcto para poder aplicar notificaciones Push
    GcmClient.CheckDevice(this);
    GcmClient.CheckManifest(this);
   // Registramos el dispositivo para poder recibir notificaciones Push
    GcmClient.Register(this, PushHandlerBroadcastReceiver.SENDER_IDS);
  }
  catch (Java.Net.MalformedURLException)
  {
      CreateAndShowDialog("There was an error creating the client. Verify the URL.", "Error");
  }
  catch (Exception e)
  {
     CreateAndShowDialog(e.Message, "Error");
   }
}
 
private void CreateAndShowDialog(String message, String title)
{
    AlertDialog.Builder builder = new AlertDialog.Builder(this); 
    builder.SetMessage(message);
    builder.SetTitle(title);
    builder.Create().Show();
}

Ahora vamos al método OnCreate inicializamos la instancia de MainActivity y llamamos al método anterior

protected override void OnCreate(Bundle bundle)
{            
   // Asignamos la acutal instacia de MainAcivity
   instance = this;
   //Registramos las notificaciones
   RegisterNotificationsPush();
 
   base.OnCreate(bundle);
 
   global::Xamarin.Forms.Forms.Init(this, bundle);
   LoadApplication(new App());
}

Llegados a este punto solo nos queda implementar la clase que donde una vez registrado el dispositivo en el hub lo registremos para recibir notificaciones push e implementemos los métodos donde procesar las notificaciones.

Para ello crearemos dos clases en nuestro proyecto droid.: GcmService y  PushHandlerBroadcastReceiver.

Empezaremos por crear la clase PushHandlerBroadcastReceiver

[BroadcastReceiver(Permission = Gcm.Client.Constants.PERMISSION_GCM_INTENTS)]
 [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_MESSAGE }, Categories = new string[] { "@PACKAGE_NAME@" })]
 [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_REGISTRATION_CALLBACK }, Categories = new string[] { "@PACKAGE_NAME@" })]
 [IntentFilter(new string[] { Gcm.Client.Constants.INTENT_FROM_GCM_LIBRARY_RETRY }, Categories = new string[] { "@PACKAGE_NAME@" })]
 public class PushHandlerBroadcastReceiver : GcmBroadcastReceiverBase<GcmService>
   {
       public static string[] SENDER_IDS = new string[] { "your senderID" };
   }

En el siguiente código nos tenemos que fijar en varios puntos:

  • En esta clase asignaremos  los senderId’s para vincularnos a GCM de google y poder recivir las notificaciones.
  • Debemos añadir los permisos que se indican y las definiciones necesarias para que funcione todo correctamente.
  • Debe derviar de la cale GcMBroadcastReceiverBase que es una clase genérica que le pasaremos el tipo de nuestra nueva clase GcmService que también implmentaremos.

Ahora implementamos la clase GcmService.

//Añadimos los permisos necesarios para utilizar notificaciones push
[assembly: Permission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "@PACKAGE_NAME@.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "com.google.android.c2dm.permission.RECEIVE")]
[assembly: UsesPermission(Name = "android.permission.INTERNET")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]
[assembly: UsesPermission(Name = "android.permission.GET_ACCOUNTS")]
 
namespace XamarinMobileAppPush.Droid
{
    //Indicamos que es un servicio que se ejecutará en background
    [Service]
    //Debe derivar de la clase GcmServiceBase
    public class GcmService : GcmServiceBase
    {
        public static string RegistrationID { get; private set; }
 
        //Constructor que llamará a su constructor base pasándole los sernder id's de nuestro GCM creado.
        public GcmService() : base(PushHandlerBroadcastReceiver.SENDER_IDS) { }
 
        //Sobreescribimos el método OnRegistered que se llamará una vez el dispositivo ha sido registrado
        protected override void OnRegistered(Context context, string registrationId)
        {
            try
            {
                RegistrationID = registrationId;
                //Una vez tenemos el id de regsitro podemos registrarnos a las notificaciones push de nuestra mobile app
                var push = ServiceManager.DefaultManager.CurrentClient.GetPush();
                MainActivity.CurrentActivity.RunOnUiThread(() => Register(push, null));
            }
            catch (Exception ex)
            {
                Log.Error("Exception", ex.Message);
            }
        }
 
        public async void Register(Microsoft.WindowsAzure.MobileServices.Push push, IEnumerable<string> tags)
        {
            try
            {
                await push.RegisterAsync(RegistrationID);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                Debugger.Break();
            }
        }
 
        //Sobreescribimos el método OnMessage que se llamará cuando se reciba una notificación push
        protected override void OnMessage(Context context, Intent intent)
        {
            var msg = new StringBuilder();
 
            if (intent != null && intent.Extras != null)
            {
                foreach (var key in intent.Extras.KeySet())
                {
                    msg.AppendLine(key + "=" + intent.Extras.Get(key).ToString());
                }
            }
 
            var prefs = GetSharedPreferences(context.PackageName, FileCreationMode.Private);
            var edit = prefs.Edit();
            edit.PutString("last_msg", msg.ToString());
            edit.Commit();
 
            string message = intent.Extras.GetString("message");            
            createNotification("Xamain Push", "Message: " + message);         
        }
 
        void createNotification(string title, string desc)
        {
            //Creamos la notificación
            var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
 
            //Creamos el intent para mostrar el mensjae
            var uiIntent = new Intent(this, typeof(MainActivity));
 
            //Notification Builder
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
 
           //Creamos el mensaje
            var notification = builder.SetContentIntent(PendingIntent.GetActivity(this, 0, uiIntent, 0))
                    .SetSmallIcon(Android.Resource.Drawable.SymActionEmail)
                    .SetTicker(title)
                    .SetContentTitle(title)
                    .SetContentText(desc)
                    .SetSound(RingtoneManager.GetDefaultUri(RingtoneType.Notification))
                    .SetAutoCancel(true).Build();
 
            //Mostramos la notificación
            notificationManager.Notify(1, notification);
        }
 
        //Sobreescribimos el método OnMessage que se llamará cuando se reciba una notificación push
        protected override void OnUnRegistered(Context context, string registrationId)
        {
            Log.Error("PushHandlerBroadcastReceiver", "Unregistered RegisterationId : " + registrationId);
        }
 
        //Sobreescribimos el método OnMessage que se llamará cuando se reciba una notificación push
        protected override void OnError(Context context, string errorId)
        {
            Log.Error("PushHandlerBroadcastReceiver", "GCM Error: " + errorId);
        }
    }

A destacar del código anterior:

  • Se deben sobreescribir los métodos OnRegistered, OnMessage, OnUnRegistered y OnError.
  • OnRegistered porque una vez registrado el dispositivo en GCM debemos registrarlo para recibir notificaciones push en nuestra Azure Mobile App.
  • OnMessage porque es donde realizaremos la lógica necesaria una vez recibida la notificación: como queremos mostrarla, si nuestra aplicación tiene que hacer algo especifico…
  • OnUnRegistered para que una vez se ha dado de bajo el dispositivo realizar alguna acción como avisar al usuario de tal hecho.
  • OnError, para poder captar cualquier error que suceda con la comunicaicón con el GMC  poder realizar acciones correspondientes.

Ahora ya estamos listos, podéis ejecutar la aplicación y ver como se ha registrado vuestro dispositivo en vuestra Azure Mobile Apps y probar de enviar notificaciones, en mi post anterior sobre notificaciones Push en Apache Cordova podéis ver cómo realizar esta prueba.

Este es el resultado:
selectexportsql

Si queréis ver cómo hacerlo en iOS o Windows podéis verlo aquí.

REferencias

https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-push/

 

[Total: 1    Average: 4/5]