[XAMARIN] Animaciones en nuestras aplicaciones Xamarin y Xamarin.Forms

Hola a todos!

Ya he hablado anteriormente en otros artículos de este blog, lo sencillo que es crear animaciones en XAML para Windows y Windows Phone. Hoy quiero hablar de algo parecido, animaciones también, pero en nuestras aplicaciones Android e iOS, usando Xamarin.

Encontraremos dos aproximaciones distintas: Xamarin y Xamarin.Forms.

En Xamarin.Forms, al tener una vista unificada, dispondremos de mecanismos para crear animaciones en la vista directamente.

En Xamarin tenemos que partir de la base de que, al crear la interface de forma nativa, también tendremos que hacer lo mismo con las animaciones, por lo que cada plataforma tendrá su forma de realizarlas.

Vamos a verlo a continuación.

Xamarin.Forms

En XamarinForms, los controles que usamos para crear la interface de usuario heredan de la clase View.

Existen unos métodos extensores de esta clase, que nos permiten, mediante código, crear animaciones para nuestros controles. Por ejemplo podemos crear una página sencilla con una Label:

public MainPage()
{
    sampleLabel = new Label
    {
        Text = «Hello Xamarin.Forms animations!»,
        TextColor = Color.Blue,  
        XAlign = TextAlignment.Center,
        Opacity = 0
    };

    Content = new StackLayout
    {
        VerticalOptions = LayoutOptions.Center,
        Children =
        {
            sampleLabel
        }
    };
}

Como podemos ver, hemos establecido la opacidad de la Label a 0, por lo que no será inmediatamente visible.

A continuación podemos sobre escribir el método OnAppearing, que se lanza justo antes de mostrarse la página, para animar esta Label y crear un efecto de FadeIn:

protected override void OnAppearing()
{
    base.OnAppearing();

    sampleLabel.FadeTo(1, 750, Easing.Linear);
}

El método extensor FadeTo puede recibir tres parámetros:

  • Valor final
  • Tiempo de la animación
  • Función de easing. Este parámetro es opcionmal.

Existen otros métodos como ScaleTo, RotateTo, RotateXTo, RotateYTo, LayoutTo, RelRotateTo, TranslateTo, podemos verlos todos aquí.

Podemos crear animaciones complejas, combinando varios efectos, por ejemplo vamos a probar con FadeTo + ScaleTo para crear una animación más completa:

protected override async void OnAppearing()
{
    base.OnAppearing();

    sampleLabel.FadeTo(1, 750, Easing.Linear);

    await sampleLabel.ScaleTo(2, 1500, Easing.CubicInOut);
    await sampleLabel.ScaleTo(1, 500, Easing.Linear);
}

Lo que hemos hecho aquí, es crear una animación FadeTo lineal que tarda 750 milisegundos en completarse. Como no esperamos a que termine, al mismo tiempo se ejecuta una animación ScaleTo, que duplica el tamaño de la Label en 1 segundo, con  una función de easing cúbica. Cuando termina el escalado, se ejecuta otro ScaleTo en 500 milisegundos, que establece de nuevo el tamaño de la Label a su escala original.

Esta forma de crear animaciones nos da mucha flexibilidad a la hora de añadir ese “extra” a nuestras interfaces de usuario con Xamarin Forms.

Además, esto mismo que hemos usado con una Label, se puede llevar a cabo con cualquier otro control, usando exactamente el mismo código fuente.

Xamarin y Windows/Windows Phone

Vamos a ver un repaso rápido de como llevar a cabo esa misma animación, que vimos en Xamarin.Forms, en una aplicación universal para Windows y Windows Phone.

Empezamos por definir el XAML de nuestro TextBlock:

<Grid>
    <TextBlock x:Name=«TextHello»
                Text=»{Binding Hello}«
                VerticalAlignment=«Center»
                HorizontalAlignment=«Center»
                Foreground=«Blue»
                Opacity=«0»
                RenderTransformOrigin=«.5,.5»>
        <TextBlock.RenderTransform>
            <CompositeTransform ScaleX=«1» ScaleY=«1»/>
        </TextBlock.RenderTransform>
    </TextBlock>
</Grid>

Además de definir las propiedades básicas del TextBlock, añadimos un CompositeTransform, para poder animar el escalado del elemento.

Ahora ya podemos crear la animación, usando un Storyboard:

<views:MvxWindowsPage.Resources>
    <Storyboard x:Key=«TextBlockAnimation» Duration=«0:0:1.5»>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName=«TextHello» Storyboard.TargetProperty=«Opacity»>
            <LinearDoubleKeyFrame KeyTime=«0:0:0.750» Value=«1»/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName=«TextHello» Storyboard.TargetProperty=«(UIElement.RenderTransform).(CompositeTransform.ScaleX)»>
            <LinearDoubleKeyFrame KeyTime=«0:0:1.0» Value=«2»/>
            <LinearDoubleKeyFrame KeyTime=«0:0:1.5» Value=«1»/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetName=«TextHello» Storyboard.TargetProperty=«(UIElement.RenderTransform).(CompositeTransform.ScaleY)»>
            <LinearDoubleKeyFrame KeyTime=«0:0:1.0» Value=«2»/>
            <LinearDoubleKeyFrame KeyTime=«0:0:1.5» Value=«1»/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</views:MvxWindowsPage.Resources>

Y ya solo nos queda lanzar la animación cuando se muestre la página, usando un Behavior o directamente desde código:

protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
    base.OnNavigatedTo(e);

    var animation = (Storyboard)this.Resources[«TextBlockAnimation»];
    animation.Begin();
}

Y ya hemos terminado, nada nuevo hasta ahora. Hemos creado una animación simple, como la que hicimos en Xamarin.Forms, pero esta vez usando XAML nativo para Windows y Windows Phone.

Xamarin y Android

Ahora vamos con Android y AXML, ¿Como creamos la misma animación? En primer lugar, creemos el layout de nuestra página inicial en AXML:

<?xml version1.0» encodingutf-8«?>
<LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android«
    xmlns:localhttp://schemas.android.com/apk/res-auto«
    android:orientationvertical«
    android:layout_widthfill_parent«
    android:layout_heightfill_parent«>
  <TextView
        android:id@+id/TextHello«
        android:layout_widthfill_parent«
        android:layout_heightwrap_content«
        android:textSize40dp«
        android:textColor#00F«
        local:MvxBindText Hello» />
</LinearLayout>

A continuación, necesitamos definir un set de animación. Para ello, crearemos un nuevo archivo AXML en la carpeta Drawable, que llamaremos TextAnimation:

<?xml version1.0» encodingutf-8«?>
<set xmlns:androidhttp://schemas.android.com/apk/res/android«
      android:shareInterpolatorfalse«>
  <alpha android:interpolator@android:anim/linear_interpolator«
         android:toAlpha1«
         android:startOffset0«
         android:duration750«/>
  <scale android:interpolator@android:anim/linear_interpolator«
         android:scaleGravitycenter_vertical«
         android:toXScale2«
         android:toYScale2«
         android:pivotX50%«
         android:pivotY50%«
         android:startOffset0«
         android:duration1000«/>
  <scale android:interpolator@android:anim/linear_interpolator«
         android:scaleGravitycenter_vertical«
         android:toXScale1«
         android:toYScale1«
         android:pivotX50%«
         android:pivotY50%«
         android:startOffset1000«
         android:duration500«/>
</set>

En Android, si queremos ejecutar varias animaciones en un mismo objeto, podemos crear un Set. Se comporta de forma parecida al Storyboard de XAML. Para crear nuestra animación completa, primero realizamos una animación alpha y a continuación dos scale, el segundo de ellos con un startOffset de 1000 milisegundos (1 segundo).

Para iniciar la animación, vamos a la clase FirstView.cs, al método OnCreate:

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.FirstView);

    Animation textAnimation = AnimationUtils.LoadAnimation(Application.ApplicationContext,
                                                            Resource.Drawable.TextAnimation);
    TextView textHello = FindViewById<TextView>(Resource.Id.TextHello);
    textHello.StartAnimation(textAnimation);
}

Obtenemos la animación con el método LoadAnimation de la clase AnimationUtils, obtenemos el TextView al que se la queremos aplicar, buscándolo por ID y finalmente llamamos al método StartAnimation del elemento a animar. Voila! Nuestra animación está lista!

Xamarin y iOS

Y por último, pero no menos importante, iOS. Aquí nos vamos a aprovechar de que creamos la interface de usuario en C# directamente, para ver lo facil que es crear animaciones.

Primero lo primero, Crear la view inicial:

public override void ViewDidLoad()
{
    View = new UIView { BackgroundColor = UIColor.White };
    base.ViewDidLoad();

    // ios7 layout
    if (RespondsToSelector(new Selector(«edgesForExtendedLayout»)))
    {
        EdgesForExtendedLayout = UIRectEdge.None;
    }

    var label = new UILabel(new CGRect(10, 100, 300, 60));
    label.Alpha = 0f;
    label.TextColor = UIColor.Blue;
    Add(label);

    var set = this.CreateBindingSet<FirstView, Core.ViewModels.FirstViewModel>();
    set.Bind(label).To(vm => vm.Hello);
    set.Apply();
}

Tras crear nuestra UILabel, creamos los bindings y establecemos los datos para el texto de la etiqueta.

Ahora vamos a usar el método Animate de la clase UIView para crear nuestra animación, igual que el resto de las plataformas:

private void CreateLabelAnimation(UILabel label)
{
    UIView.Animate(0.75, 0, UIViewAnimationOptions.CurveLinear,
    () =>
    {
        label.Alpha = 1f;
    }, null);
    UIView.Animate(1, 0, UIViewAnimationOptions.CurveLinear,
    () =>
    {
        label.Transform = CGAffineTransform.MakeScale(2f, 2f);
    }, null);
    UIView.Animate(0.5, 1, UIViewAnimationOptions.CurveLinear,
    () =>
    {
        label.Transform = CGAffineTransform.MakeScale(1f, 1f);
    }, null);
}

El método Animate recibe en primer lugar la duración, en segundos, a continuación la espera en segundos antes de ejecutar la animación, el tipo de transición en el enumerado UIViewAnimationOptions, una función que ejecute la animación y por último otra función que será ejecutada al terminar la animación.

Se explica solo el código, es muy sencillo. usamos una expresión lambda para modificar el objeto UILabel que queremos animar. En el primer caso, simplemente cambiamos la propiedad Alpha. En los dos siguientes usamos la clase CGAffineTransform y el método MakeScale para realizar el escalado necesario.

En resumen

Al final, el crear pequeñas animaciones le aporta un extra de calidad a nuestra aplicación, la hace parecer más suave y ligera.

Cada plataforma tiene su forma de hacer las cosas, a no ser que usemos Xamarin.Forms, donde animamos una sola vez y funciona en todas las plataformas.

Puedes descargarte el código del ejemplo directamente desde GitHub:

https://github.com/josueyeray/XamarinAnimations

Espero que os sea útil.

Un saludo y Happy Coding!

[EVENTOS] Un febrero movidito

Hola a todos!

Este febrero va a ser movidito en cuanto a eventos de desarrollo para la comunidad .NET y los desarrolladores móviles.

Bravent Xamarin tour

Bravent, consultora especializada en soluciones Microsoft

Bravent ha organizado un pequeño tour por Madrid, Barcelona y Sevilla sobre desarrollo con Xamarin.

Cada uno de los eventos constará de 5 charlas, impartidas por Javier Suarez Ruiz y un servidor:

Servicios Xamarin: Analíticas, rendimiento, testing y más

9:00 – 9:55 Introducción al desarrollo de apps con Xamarin.
10:00 – 10:55 Arquitectura de proyectos multiplataforma con Xamarin.
11:10 – 12:05 Introducción a Xamarin.Forms
12:10 – 13:05 Aplicaciones multiplataforma y Microsoft Azure
13:10 – 14:15  

¿Fechas, lugares y registro? A continuación:

  • Madrid, 4 de Febrero. Oficinas de Microsoft Ibérica. Registro aquí.
  • Sevilla, 9 de Febrero. Clouding Point. Registro aquí.
  • Barcelona,  16 de Febrero. Oficinas de Microsoft Ibérica. Registro aquí

Pasaremos una mañana entretenida, hablando de desarrollo móvil multiplataforma y haciendo un poco de networking.

Microsoft .NET Spain Conference

image

EL EVENTO, así con mayúsculas. Dos días completos, 8 tracks con sesiones de más de 1 hora de duración, dedicadas a todo el ecosistema .NET:

  • ALM
  • Web
  • Cloud
  • Data
  • Enterprise
  • Apps
  • Games
  • IoT

A esto hay que sumarle hands on labs durante los dos días y talleres para niños.  Un evento que no te puedes perder. El precio de las entradas ahora mismo va desde los 5 a los 10 euros, vamos unos desayunos.

Más detalles e inscripciones, aquí. El evento se celebrará en Madrid, en el campus universitario de la universidfad Politécnica de Alcalá, los días 27 y 28 de febrero.

Espero poder veros a muchos en alguno de estos eventos.

Un saludo y Happy Coding!

Azure Notifications Hub y Xamarin

Uno de los mayores problemas al trabajar con múltiples plataformas móviles, es el envío de notificaciones desde nuestro backend. En Azure tenemos disponible un servicio llamado NotificationsHub, que nos permite simplificar esta tarea.

Configurando un hub de notificaciones

Para empezar, necesitaremos configurar un centro de notificaciones en nuestra cuenta de Azure, desde el portal de administración. El apartado de Notifications Hub se encuentra dentro de la parte de Service Bus:

image

Tendremos que indicar un nombre del servicio, la región en la que queremos ejecutarlo y el namespace que usaremos. Una vez que lo hayamos creado, podemos entrar a su configuración. Lo unico que necesitamos en primera instancia es configurar las credenciales de cada Store (Apple Store, Google Play y Microsoft Store). Cada una de ellas tiene su propia configuración:

  • Apple Store: Necesitaremos generar un certificado digital que debemos generar con nuestra cuenta de desarrollador.
  • Windows Phone (MPNS) Necesitaremos generar un certificado digital.
  • Windows y Windows Phone (WNS) Tenemos que indicar el SID del paquete de nuestra aplicación y el secreto.
  • Google Play: Tenemos que indicar la clave de GCM (Google Cloud Messaging).

Vamos a ver como obtener las credenciales necesarias para Windows Phone (WNS) y para Google Play a continuación.

WNS

Para obtener el SID y el secreto de una aplicación que use WNS (Windows 8.1 o Windows Phone 8.1) Debemos tenerla asociada con la tienda en primer lugar y con un nombre reservado. Esto no significa que tenga que estar publicada. Simplemente debemos crear el proceso de publicación y reservar un nombre. Una vez hecho esto, en los detalles de la aplicación, en el dashboard de Windows Store podremos ir al apartado servicios:

image

Donde encontraremos un enlace para visitar el sitio de servicios Live:

image

En el sitio de Servicio Live, encontraremos los datos que necesitamos, el SID de paquete y la clave secreta:

image

Esos dos datos son los que necesitamos configurar en nuestro Notifications Hub, en la parte de WNS:

image

Y listo, ya tenemos todo lo necesario para que nuestro NotificationHub envie notificaciones a nuestra app Windows Phone o Windows Store.

Google Play

Google Play también requiere que realicemos cierta configuración en las APIs de google. Tenemos que ir a console.developers.google.com y crear un nuevo proyecto para nuestra aplicación. En el ejemplo crearemos un proyecto llamado NSHubSample con id: nshubsample-xamarin.

Dentro del proyecto tendremos que ir a la sección de APIs y habilitar el API Google Cloud Messaging for Android. Después, en la sección de credenciales tendremos que crear una nueva clave de servidor (clave pública) y quedarnos con la clave de API:

image

Ya solo tenemos que volver a la configuración de nuestro Notification Hub y añadir la clave de API de Google Play en la sección de Google Cloud Messaging settings:

image

Bien, con esto ya tenemos configurado nuestro notification hub para enviar mensajes a aplicaciones Windows, Windows Phone y Android. Como último paso, necesitaremos las cadenas de conexión para comunicarnos desde el servidor que envíe las notificaciones y desde las apps cliente. Podemos encontrarlas en la página principal de nuestro Notifications Hub, en el link “View Connection Strings”:

image

Al pulsar, se abrirá un popup en el que se mostrarán dos cadenas de conexión:

image

Nos quedaremos con ambas guardadas para usarlas en los siguientes pasos.

Ahora vamos a por la parte de las apps cliente. Usando Xamarin, vamos a crear una app para Android, Windows y Windows Phone.

Obteniendo los canales de notificación

Aunque con Xamarin podemos compartir la mayoría del código, la parte de registrar nuestro dispositivo/app con la nube de notificaciones es única en cada plataforma, al igual que el registro que hemos tenido que hacer anteriormente.

Windows XAML

Para comenzar, necesitaremos instalar el paquete “Windows Azure Service Bus Managed for Windows Store and Windows Phone”, desde el gestor de paquetes de NuGet en nuestro proyecto universal. Este paquete nos facilitará la tarea de enviar a Notifications Hub nuestros canales de notificaciones.

Para obtener estos canales de notificaciones usaremos la clase PushNotificationChannelManager, del namespace Windows.Networking.PushNotifications. Para ello usaremos el método CreatePushNotificationChannelForApplicationAsync. Una vez que tengamos el canal de notificaciones, se lo enviaremos a nuestro notifications hub. Para ello crearemos una nueva instancia de la clase NotificationHub, pasándo como parámetro:

  • El nombre de nuestro Notification Hub creado anteriormente, en este caso: nhsampledemo.
  • La cadena de conexión DefaultListenSharedAccessSignature que hemos obtenido anteriormente.

Finalmente, llamamos al método RegisterNativeAsync, pasándole la Uri del canal obtenido al principio como parámetro.

private async void InitNotificationsAsync()
{
    var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

    var hub = new NotificationHub("nhsampledemo", "<Endpoint listen>");
    var result = await hub.RegisterNativeAsync(channel.Uri);
}

Y con esto ya hemos registrado el canal de notificaciones para Windows y Windows Phone.

Android

En Android, necesitaremos en primer lugar instalar el componente de Google Cloud Messaging Client. Para ello hacemos click derecho sobre la carpeta Components del proyecto Android y seleccionamos la opción “Get more components”. Esto nos mostrará la lista de componentes disponibles, solo tendremos que buscar “Google Cloud Messaging Client”, hacer click sobre él y a continuación sobre el botón verde “Add to App”:

image

Para registrar nuestra aplicación, necesitaremos además el ID de proyecto de google api console que creamos anteriormente. Lo podemos encontrar en la página principal del proyecto:

image

Ahora si, ya podemos escribir el código necesario para registrar nuestra app con la nube de mensajes de google. Por ejemplo, en el método OnCreate de nuestra primera vista:

private void RegisterWithGCM()
{
    GcmClient.CheckDevice(this);
    GcmClient.CheckManifest(this);
    GcmClient.Register(this, "<PROJECT ID>");
}

El método CheckDevice comprueba que el dispositivo soporta los servicios de google play, necesarios para tener notificaciones. CheckManifest comprueba que hemos establecido las configuraciones necesarias en el manifiesto de la aplicación. Por último registramos nuestra aplicación con el método Register, en el que usamos el id de proyecto que hemos obtenido anteriormente.

Ahora ya tenemos nuestra app de Android registrada, pero para poder recibir notificaciones necesitaremos crear un servicio en background que las procese cuando lleguen al dispositivo. Para ello necesitaremos crear dos nuevas clases:

  • MyBroadcastReceiver, que se registrará como receptor de Google Cloud Messaging
  • GcmService, que tendrá el código necesario para recibir y procesar nuestras notificaciones.

Necesitaremos decorar el namespace de estas clases con los atributos de permisos que necesitamos:

[assembly: Permission(Name = "notificationsHub.Android.permission.C2D_MESSAGE")]
[assembly: UsesPermission(Name = "notificationsHub.Android.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")]
[assembly: UsesPermission(Name = "android.permission.WAKE_LOCK")]

namespace NotificationsHub.Android

La clase MyBroadfcastReceiver también tiene que estar decorada con algunos atributos para identificarla correctamente. Tiene que heredar ademas de la clase GcmBroadcastReceiverBase<>:

[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 MyBroadcastReceiver : GcmBroadcastReceiverBase<GcmService>
{
    public static string[] SENDER_IDS = new string[] { "<PROJECT ID>" };

    public const string TAG = "MyBroadcastReceiver-GCM";
}

GcmService, se decora con el atributo Service y hereda de GcmServiceBase. Además tendremos que agregar el paquete de NuGet Xamarin.NotificationHub al proyecto Android para poder crear el código de esta clase:

[Service] //Must use the service tag
public class GcmService : GcmServiceBase
{
    public static string RegistrationID { get; private set; }
    private NotificationHub Hub { get; set; }

    public GcmService() : base("<PROJECT ID>")
    {
        Log.Info(MyBroadcastReceiver.TAG, "GcmService() constructor");
    }

    protected override async void OnRegistered(Context context, string registrationId)
    {
        Log.Verbose(MyBroadcastReceiver.TAG, "GCM Registered: " + registrationId);
        RegistrationID = registrationId;

        createNotification("GcmService-GCM Registered…", "The device has been Registered, Tap to View!");

        Hub = new NotificationHub("nhsampledemo", "<listen endpoint>");
        try
        {
            await Hub.UnregisterAllAsync(registrationId);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            Debugger.Break();
        }

        try
        {
            List<string> TAGS = new List<string>()
            {
            };
            var hubRegistration = await Hub.RegisterNativeAsync(registrationId, TAGS);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            Debugger.Break();
        }
    }

    protected override void OnMessage(Context context, Intent intent)
    {
        Log.Info(MyBroadcastReceiver.TAG, "GCM Message Received!");

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

        string messageText = intent.Extras.GetString("msg");
        if (!string.IsNullOrEmpty(messageText))
        {
            createNotification("New hub message!", messageText);
            return;
        }

        createNotification("Unknown message details", msg.ToString());
    }

    void createNotification(string title, string desc)
    {
        var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
        var uiIntent = new Intent(this, typeof(FirstView));
        var notification = new Notification(Android.Resource.Drawable.Icon, title);
        notification.Flags = NotificationFlags.AutoCancel;
        notification.SetLatestEventInfo(this, title, desc, PendingIntent.GetActivity(this, 0, uiIntent, 0));

        notificationManager.Notify(1, notification);
    }

    protected override void OnError(Context context, string errorId)
    {
        //Manage errors
    }

    protected override void OnUnRegistered(Context context, string registrationId)
    {
        //Manage unregistering services.
    }
}

Podemos encontrar cuatro métodos importantes en esta clase: OnRegistered, OnMessage, OnError y OnUnRegistered:

  • OnRegistered se ejecuta cuando, en el paso anterior, registramos la aplicación con el backend Google Cloud Messaging, recibe el contexto y el id de registro, creamos una nueva instancia de la clase NotificationHub, des registramos las notificaciones que usen ese mismo ID, si había alguna, y a continuación llamamos a RegisterNativeAsync, igual que en Windows XAML.
  • OnMessage es invocado cuando recibimos un mensaje desde Google Cloud Messaging, en este caso procesamos el mensaje y lo mostramos en pantalla creando una nueva notificación.
  • OnError se lanza si se produce un error.
  • OnUnRegistered se ejecuta si esta instancia activa es des registrada.

iOS

Para iOS trabajaremos sobre la clase AppDelegate. Pero en primer lugar, tendremos que añadir un componente, de la misma forma que hicimos en Android. En este caso necesitamos el componente de Azure Mobile Services. También tendremos que añadir una referencia a la librería de WindowsAzure.Messaging para iOS. Todavía no existe un paquete exclusivo para ella, se descarga junto a la de Android que instalamos anteriormente.

Una vez instalado Azure Mobile Services, en la clase AppDelegate tenemos que sobre escribir los métodos FinishedLaunching, RegisterForRemoteNotifications y ReceivedRemoteNotification. En FinishedLaunching tenemos que añadir la llamada al registro de la aplicación en el servicio de notificaciones:

UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);

Tras ésta llamada, se lanzará el método RegisteredForRemoteNotifications, donde recibiremos el token del dispositivo y lo registraremos en nuestro notifications hub:

public override async void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
    Hub = new NotificationHub(ConnectionString, NotificationHubPath);
    await Hub.UnregisterAllAsync(deviceToken.ToString());
    await Hub.RegisterNativeAsync(deviceToken.ToString());
}

Cuando recibamos una notificación, se llamará al método ReceivedRemoteNotification, con la información de la misma dentro de un diccionario:

public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
    ProcessNotification(userInfo, false);
}

void ProcessNotification(NSDictionary options, bool fromFinishedLaunching)
{
    // Check to see if the dictionary has the aps key.  This is the notification payload you would have sent
    if (options != null && options.ContainsKey(new NSString("aps")))
    {
        //Get the aps dictionary
        NSDictionary aps = options.ObjectForKey(new NSString("aps")) as NSDictionary;

        string alert = string.Empty;

        if (aps.ContainsKey(new NSString("alert")))
            alert = (aps[new NSString("alert")] as NSString).ToString();

        //If this came from the ReceivedRemoteNotification while the app was running,
        // we of course need to manually process things like the sound, badge, and alert.
        if (!fromFinishedLaunching)
        {
            //Manually show an alert
            if (!string.IsNullOrEmpty(alert))
            {
                UIAlertView avAlert = new UIAlertView("Notification", alert, null, "OK", null);
                avAlert.Show();
            }
        }
    }
}

En este caso, tenemos que diferenciar si el método se llama desde el FinishedLaunching o no, para decidir si debemos o no mostrar la notificación recibida.

Y con esto hemos terminado con las aplicaciones cliente. Ahora podemos crear nuestro Servicio que envíe las notificaciones al Notification Hub para que este las distribuya a los diferentes servicios.

Servidor

Como ejemplo, usaremos una aplicación WPF muy sencilla, con unos botones que nos permitan enviar una notificación a cada plataforma. Para ello necesitaremos dos paquetes de NuGet:

  • Microsoft.WindowsAzure.ConfigurationManager
  • WindowsAzure.ServiceBus

El paquete Microsoft.WindowsAzure.ConfigurationManager se instalará automáticamente al instalar WindowsAzure.ServiceBus, como una dependencia. Una vez instalado este paquete, podremos escribir el siguiente código para enviar una notificación WNS (Windows Notification Service):

private async void Send_Windows(object sender, RoutedEventArgs e)
{
    NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<FULLSHAREDACCESS ENDPOINT>", "nhsampledemo");
    var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">Hello from a .NET App!</text></binding></visual></toast>";
    await hub.SendWindowsNativeNotificationAsync(toast);
}

Para Android y Google Cloud Messaging, usaríamos este código:

private async void Send_Android(object sender, RoutedEventArgs e)
{
    NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<FULLSHAREDACCESS ENDPOINT>", "nhsampledemo");
    var message = "{ \"data\" : {\"msg\":\"Hello from Azure!\"}}";
    var result = await hub.SendGcmNativeNotificationAsync(message);
}

Para iOS tendríamos el siguiente código:

private async void Send_iOS(object sender, RoutedEventArgs e)
{
    NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<FULL ENDPOINT>", "nhsampledemo");
    var alert = "{\"aps\":{\"alert\":\"Hello from .NET!\"}}";
    await hub.SendAppleNativeNotificationAsync(alert);
}

En ambos casos, el proceso es el mismo. Primero creamos una nueva instancia de la clase NotificationHubClient, pasándo la connection string de full access y el nombre de nuestro Notification hub. A continuación creamos el “payload”, la notificación que deseamos enviar. En este paso, tenemos que usar el formato nativo de cada plataforma de notificaciones. Para conocer como escribir esta “payload”, podemos visitar la página de cada plataforma:

Por último, para cada plataforma tenemos un método de envío de la notificación. En este ejemplo usamos SendWindowsNativeNotificationAsync para WNS y SendGcmNativeNotificationAsync para GCM.

Ya solo nos queda ejecutar las aplicaciones cliente para que se registren y lanzar la aplicación WPF para que envíe la notificación a cada una de ellas. La mejor parte de Notifications Hub, es no tener que pelearnos en nuestro servidor con tres APIs de notificaciones totalmente distintas. Nos permite centrarnos en crear las notificaciones y enviarlas de forma sencilla.

Puedes ver el código del ejemplo en GitHub, pero recuerda sustituir <LISTEN ENDPOINT>, <FULL ENDPOINT>, <PROJECT ID> y “nhsampledemo” por los valores correctos de tú Notification Hub, para hacerlo funcionar.

Un saludo y Happy Coding!