[Codemotion 2017] Taller de Xamarin

Codemotion 2017

Otro año más, Codemotion se celebrará en Madrid los días 24 y 25 de noviembre en el Campus de Montepríncipe de la Universidad CEU San Pablo. Como en años anteriores, es una cita imprescindible para el mundo del desarrollo de software.

Codemotion 2017

Taller Xamarin

Este año volveré a tener la oportunidad de participar en el evento aunque a diferencia de años anteriores, donde participé con sesiones técnicas, estaré con un taller.

El Sábado 25 de Noviembre, de 12:15h a 14:00h tendremos un taller de desarrollo de aplicaciones multiplataforma con Xamarin. En este Lab veremos como desarrollar aplicaciones nativas multiplataforma para iOS, Android, Windows, macOS y Linux compartiendo la mayor cantidad de código posible utilizando Xamarin.Forms.

Requisitos:

  • Visual Studio 2015 o 2017 para Windows (la versión Community es perfectamente válida) o Visual Studio para macOS.
  • Asegúrate de tener instalado Xamarin.
  • Emuladores de Android.
  • Muchas ganas!

Material:

¿Nos vemos allí?

Más información

[Evento Sevilla] Últimas novedades y taller Xamarin

Introducción

Seguimos activos en SVQXDG, grupo de desarrolladores Xamarin de Sevilla, con un nuevo evento!. En esta ocasión, llegamos justo tras el Microsoft Connect(); 2017 donde no nos cabe duda que se presentarán novedades relacionadas con Xamarin. Por ese motivo, nada mejor que agrupar todo en una sesión técnica!. Además, en el mismo evento, y gracias al feedback recibido de otros eventos, vamos a tener un divertido taller donde desarrollaremos desde cero una aplicación móvil para Android, iOS, Windows, macOS y Linux utilizando Xamarin.Forms.

¿Te suena interesante?

El evento

La agenda:

  • 18:00h – 18:10h: Recepción y bienvenida!
  • 18:10h – 19:00h: Novedades Xamarin: Tras un intenso Connect(); 2017, nada mejor que ver las últimas novedades en Xamarin, Xamarin.Forms o Mobile Center para estar al día. Con Javier Suárez.
  • 19:00h – 21:00h: Taller de desarrollo Xamarin: Desarrollaremos una aplicación paso a paso utilizando MVVM y buenas prácticas conectando con un backend. ¿Te animas?. Con Javier Suárez.

Por supuesto, también tendremos momentos para el networking, resolución de dudas e incluso algunos detalles con los asistentes.

Requisitos para el taller:

  • Visual Studio 2015 o 2017 para Windows (la versión Community es perfectamente válida) o Visual Studio para macOS.
  • Asegúrate de tener instalado Xamarin.
  • Emuladores de Android.
  • Muchas ganas!

El lugar

El evento se celebrará en la ETS de Ingeniería Informática. Dirección detallada:

E.T.S. Ingeniería Informática – Universidad de Sevilla, Aula A0.30
Av. Reina Mercedes s/n
Sevilla Se 41012

La fecha

Será el próximo Martes, 28 de Noviembre a las 18:00h (GMT+1). Tendremos una charla de una hora junto a un taller de dos horas.

¿Te apuntas?

Más información

[Xamarin.Forms] .NET Standard 2.0 y Entity Framework Core

Introducción

Cuando desarrollamos aplicaciones móviles, en una gran cantidad de ocasiones, vamos a necesitar trabajar y gestionar datos. Podemos necesitar sencillas clave-valor para gestionar la configuración de la aplicación, o bien, datos más complejos relacionales utilizando una base de datos local como SQLite o Realm.

A la hora de trabajar con datos, una opción muy familiar para desarrolladores .NET es Entity Framework.

¿Podemos utilizar Entity Framework desde una aplicación Xamarin?, ¿qué limitaciones encontramos?.

En este artículo, vamos a ver paso a paso como llegar a utilizar Entity Framework Core en una aplicación Xamarin.Forms.

NOTA: Este artículo se focaliza en aprender como utilizar Entity Framework Core en una aplicación Xamarin. No tiene como objetivo dar a conocer conceptos básicos de Entity Framework.

Entity Framework Core

Entity Framework es un ORM (object-relational mapper) que permite a los desarrolladores trabajar con una base de datos utilizando objetos .NET. Con un largo recorrido, la primera versión de Entity Framework aparecía en verano de 2008, ha ido evolucionando en base a las necesidades de desarrolladores. Como proyecto Open Source, ha contado con importantes contribuciones.

En verano de 2016, llega .NET Core y junto al mismo algunas tecnologías relacionadas, como Entity Framework Core.

Cuando hablamos de Entity Framework Core nos referimos a una versión ligera, extensible y además multiplataforma de Entity Framework.

NOTA: Si cuentas con experiencia con Entity Framework encontrarás Core muy familiar. Sin embargo, recuerda que es una versión más ligera y que hay opciones no disponibles (por ejemplo, lazy loading).

Con el lanzamiento de .NET Standard 2.0 Preview para UWP junto con el lanzamiento de Entity Framework Core 2.0, podemos desarrollar aplicaciones móviles para iOS, Android y UWP con EF y SQLite. A pesar de no contar con todas las opciones de Entity Framework, la versión Core es muy interesante por diversos motivos:

  • Fácil de arrancar.
  • Se integra bien con Linq.
  • Se puede utilizar en diferentes plataformas gracias a .NET Core (Android, macOS, Linux, etc.).

NOTA: Puedes ver una tabla comparativa ente EF Core y EF 6 en este enlace.

Comenzamos

Partimos de una aplicación Xamarin.Forms creada con la plantilla disponible:

Nueva App Xamarin.Forms

Librería .NET Standard

Nuestro objetivo es tener una librería .NET Standard, una librería con una especificación de APIs .NET diseñada para estar disponible en todos los runtimes .NET. Esta librería actuará de forma similar a una PCL, será el lugar donde añadiremos el código común compartido de todas las aplicaciones móviles además de la lógica de Entity Framework Core.

Tenemos varias opciones para tener la librería. Podemos crear una librería .NET Standard nueva que reemplazará a la PCL (la acabaremos borrando):

Nueva librería .NET Standard

O podemos editar la PCL para convertirla en una librería .NET Standard.

<Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
     <PackageTargetFallback>$(PackageTargetFallback);portable-win+net45+wp8+win81+wpa8</PackageTargetFallback>
     </PropertyGroup>
</Project>

Vamos a utilizar .NET Standard 2.0:

.NET Standard 2.0

NOTA: Para poder utilizar Entity Framework 2.0, es necesario utilizar una .NET Standard versión 2.0. Necesitas tener instalado .NET Core SDK 2.0.

Añadir Microsoft.EntityFrameworkCore.Sqlite

Tenemos que añadir paquete NuGet de Entity Framework en nuestros proyectos. Para ello, hacemos clic derecho en la gestión de paquetes NuGet de la solución y añadimos Microsoft.EntityFrameworkCore.Sqlite.

Microsoft.EntityFrameworkCore.Sqlite

Trabajando con Entity Framework

Tras añadir el paquete de Entity Framework podemos comenzar a trabajar!.  Si ya has trabajado previamente con Entity Framework no te será desconocido el contexto DbContext.

En Entity Framework llamamos contexto a la puerta de enlace entre el modelo que utilizamos y el framework que se encarga de conectar con al base de datos y de realizar el mapeo de las diferentes operaciones con comando de datos. DbContext será el responsable de:

  • Conexiones de base de datos.
  • Operaciones de datos tales como consultas y persistencia.
  • Seguimiento de cambios.
  • Mapeo de datos.
  • Gestión de transacciones.
  • Etc.

Vamos a desarrollar una aplicacación que permita tomar notas.

Comenzamos definiendo nuestros Modelos que se encargarán de definir el esquema de nuestra base de datos.

Modelos

public class TodoItem
{
     [Key]
     public int Id { get; set; }
     public string Name { get; set; }
     public string Notes { get; set; }
     public bool Done { get; set; }
}

Crear el contexto

A continuación, nos aseguramos que nuestra clase TodoItem es parte de nuestro DbContext. Definimos el contexto:

class DatabaseContext : DbContext
{
     public DbSet<TodoItem> TodoItems { get; set; }

     public DatabaseContext()
     {
          this.Database.EnsureCreated();
     }

     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
     {
          var dbPath = DependencyService.Get<IDatabaseService>().GetDatabasePath();
          optionsBuilder.UseSqlite($"Filename={dbPath}");
     }
}

De igual forma a cuando trabajamos directamente con SQLite por ejemplo, necesitamos código específico por plataforma para acceder a la ruta de la base de datos adecuada.

Android

public class DatabaseService : IDatabaseService
{
      public string GetDatabasePath()
      {
           return Path.Combine(
           System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), 
           AppSettings.DatabaseName);
      }
}

iOS

public class DatabaseService : IDatabaseService
{
     public string GetDatabasePath()
     {
         return Path.Combine(Environment.GetFolderPath(
         Environment.SpecialFolder.MyDocuments), 
         "..", 
         "Library", 
         AppSettings.DatabaseName);
     }
}

NOTA: Es importante utilizar el servicio de dependencia de Xamarin.Forms parar resolver la dependencia específica de la plataforma donde se ejecuta la aplicación:

[assembly: Dependency(typeof(DatabaseService))]

Insertar nuevos registros

La clase DbSet<TEntity> representa una colección para una entidad dada dentro del modelo y es la vía de entrada a las operaciones de la base de datos. Las clases DbSet<TEntity> se agregan como propiedades al DbContext.

Para insertar nuevos registros a la colección representada por el DbSet, utilizamos el método DbSet.Add:

_context.TodoItems.Add(item);

Esto añade los cambios al DbSet en memoria, es necesario utilizar el método SaveChanges para actualizar la base de datos.

_context.SaveChanges();

Actualizar registro

Para actualizar una entidad, se deben realizar los cambios necesarios en el valor de la propiedad o propiedades de la misma y utilizar el método Update junto a  SaveChanges.

_context.TodoItems.Update(todoItem);

Obtener información desde la base de datos

La forma más común utilizada para obtener varias entidades es utilizar el método ToList:

public IList<TodoItem> GetAll()
{
     return _context.TodoItems.ToList();
}

Si lo que se busca es recuperar una sola instancia de una entidad, se puede usar el método First o Single, dependiendo de si espera que haya más de una fila que coincida con los criterios.

Eliminar registro

Por último, para eliminar registros, utilizamos el método Remove disponible en la clase DbSet además de, SaveChanges.

public void Remove(TodoItem item)
{
     _context.TodoItems.Remove(item);
     _context.SaveChanges();
}

Puedes descargar el ejemplo realizado desde GitHub:

Ver GitHub

Recuerda, cualquier comentario, duda o pregunta es bienvenida en los comentarios de la entrada.

Más información

[Xamarin.Forms] Probando Live XAML, actualizando XAML al vuelo!

Productividad trabajando con XAML

Conseguir aplicaciones con una interfaz rica, elegante y perfectamente adaptada a cada plataforma requiere un proceso de repetición de cambio, compilación, depuración y vuelta a repetir.

Contamos con opciones interesantes para solventar este problema como Previewer, Gorilla Player o Xamarin Live Player. Ya vimos todas las herramientas anteriores, ahora, nos llega el turno de probar otra opción muy interesante, Live XAML.

Live XAML

Live XAML es una extensión disponible para Visual Studio tanto en Windows como en macOS que se encarga de inyectar el código necesario para reaccionar ante cualquier cambio de XAML. Esto significa que, con tu aplicación en modo depuración en un emulador o en un dispositivo, puedes ver al vuelo cualquier cambio en XAML.

La instalación

Desde la página oficial de la herramienta podemos descargar una extensión para Visual Studio disponible tanto para Windows como para macOS.

Tras descargar e instalar la extensión todo listo. Uno de los grandes puntos positivos de la herramienta es su facilidad de uso, tras instalar, para utilizar la herramienta en cada proyecto bastará con indicarle a la herramienta que añada paquete NuGet en la librería compartida llamado LiveXAML o bien, añadir el paquete a mano.

LiveXAML NuGet

Comenzamos con un ejemplo sencillo

Partimos de un proyecto básico, la plantilla vacía de Xamarin.Forms. Lanzamos el proyecto en depuración.

Comenzamos con las pruebas más sencillas posibles, cambiar propiedades básicas como el texto o el color del Label añadido por defecto:

Continuamos con otros requisitos básicos al desarrollar en aplicaciones, el uso de recursos y estilos.

La herramienta se comporta sin problemas al utilizar recursos tanto a nivel de elemento, como a nivel de página como a nivel de aplicación.

Probamos posibilidades más complejas

Tiene buena pinta, pero…¿y será válido con aplicaciones más complejas?. Recientemente, en el blog vimos un recopilatorio de ejemplos Xamarin.Forms con intefaz atractiva. Entre ese recopilatorio se encuentra un ejemplo que intenta reproducir la interfaz de Netflix en Xamarin.Forms. Vamos a utilizarla.

Podemos realizar pruebas con enlace a datos en sus difentes modos.

La cabecera con transparencias haciendo uso de Custom Renderer, efecto Parallax, el uso de controles personales para listados, etc. Estamos trabajando con una página relativamente compleja. Podemos realizar cambios al vuelo y realizar pruebas directamente. Por ejemplo, cambios en el tamaño de la cabecera y pruebas con el efecto Parallax:

Puedes descargar el ejemplo de Netflix desde GitHub:

Ver GitHub¿Aumentamos la complejidad?

¿Funcionaría con .NET Standard?, ¿y con librerías personalizadas?. Pasamos a continuación a ver un ejemplo haciendo uso de .NET Standard, SkiaSharp y la librería Microcharts que aporta diversas gráficas de gran belleza y posibilidades creadas con SkiaSharp.

Creamos un pequeño control que añade animaciones a la gráfica. Ajustar la velocidad de la animación, tamaño de fuentes, elementos, etc. Sería fantástico poder aplicar estos cambios al vuelo, sin necesidad de parar, recompilar, esperar el despliegue, etc., ¿verdad?.

Fíjate que en la cabecera de la gráfica hacemos también uso de efectos. Aplicamos un efecto que añade sombras al texto.

Puedes descargar el ejemplo desde GitHub:

Ver GitHub

Conclusiones

Tras todas las pruebas que has podido ver anteriormente (más muchas otras), los resultados son excelentes. No he encontrado errores de renderizado, comunicación o funcionamiento en general de la herramienta. Así que, debemos destacar su fácil instalación y su buen hacer. Tampoco es necesario aprender nada nuevo ya que todo se integra en Visual Studio y con el flujo habitual. Eso si, recuerda, estamos ante una herramienta que tiene coste.

Más información

[Material] dotNetMálaga 2017

El evento

El pasado sábado 30 de Septiembre, tenía lugar en Málaga la dotNetMálaga 2017. Una jornada con múltiples sesiones técnicas en varios tracks, talleres, regalos, sorteos y mucho networking.

El resultado fue un fantástico día de comunidad con muchas preguntas, ayuda y tiempo para charlar entre todos.

El material

Pude participar en el evento con una de las sesiones técnicas hablando de pequeños trucos y consejos para conseguir el mejor rendimiento posible en Xamarin.Forms junto con un taller de desarrollo de aplicaciones para Hololens.

Rendimiento y Xamarin.Forms

¿Sabes el ciclo de vida de un Layout?, ¿qué opciones de Layout son más óptimas?, ¿cómo afectan los Bindings al rendimiento y como tratarlos?, ¿rendimiento en listados?, ¿fast renderers?, ¿que tener en cuenta al crear Custom Renders o Behaviors?. Intentamos dar respuesta a todas estas preguntas en esta sesión.

Puedes descargar todos los ejemplos utilizados desde GitHub:

Ver GitHubTaller Hololens con Wave Engine

Por la tarde continuamos con un divertido taller realizando una aplicación para Hololens con Wave Engine. Nuestro objetivo fue crear el sistema solar con posibilidad de realizar Air Tap sobre cada planeta para obtener información además de hacer uso de comandos de voz.

HoloPlanets

En el taller vimos:

  • Crear App 3D con el sistema solar.
  • Uso de modelos 3D.
  • Crear proyectos para HoloLens.
  • Gestión de cámara y posicionamiento.
  • Air Tap.
  • Comandos de voz.

La presentación utilizada:

Puedes descargar cada paso dado en el taller desde GitHub:

Ver GitHub

Gracias a ponentes y patrocinadores, por supuesto a todos los asistentes y mi enhorabuena a toda la organización. ¿Vamos pensando en la dotNetMálaga 2018?.

Más información

Creando la interfaz de Netflix con Xamarin.Forms

Introducción

La evolución de Xamarin.Forms es meritoria. En los últimos tiempos se han recibido novedades interesantes como efectos, vistas nativas, Forms Embedding, etc. Sin embargo, en muchos casos se sigue asociado a desarrollos muy simples o formularios básicos.

Realmente, en el estado actual de Xamarin.Forms se pueden conseguir aplicaciones nativas de gran escala, con interfaces cuidadas y con alta integración con la plataforma. Hay que tener en cuenta el conjunto de Custom Renderers (código específico en cada plataforma) necesario para lograrlo.

NOTA: La elección entre Xamarin Classic o Xamarin.Forms es importante. Es necesario evaluar la aplicación a desarrollar, el conjunto de características específicas de cada plataforma (que pueden requerir un Custom Renderer), etc. 

En este artículo, vamos a tomar como referencia una aplicación bastante conocida, disponible en las listas de destacados de las diferentes tiendas, Netflix. Vamos a desarrollar la interfaz de la aplicación móvil de Netflix con Xamarin.Forms paso a paso.

¿Cuántos Custom Renderers crees que serán necesarios?, ¿qué cantidad de código podremos compartir?, ¿tendremos buen resultado final?.

La pantalla de selección de perfil

Vamos a comenzar partiendo de una pantalla bastante representativa y común en Netflix, la selección de usuario o perfil.

Vamos a analizar características de la pantalla y a determinar que vamos a necesitar:

  • Se puede ver una barra de navegación. Algo que podemos conseguir de forma sencilla en Xamarin.Forms gracias al uso de NavigationPage.
  • En la barra de navegación se muestra una imagen, el logo de la aplicación. Para poder ajustar la imagen, tamaño y posición, vamos a necesitar un Custom Renderer en el caso de iOS. Para Android, podemos utilizar layout AXML con facilidad.
  • En la barra de navegación también tenemos un botón de edición. Nada complejo que podemos abordar utilizando ToolbarItem.
  • Y llegamos al listado de opciones de perfil para elegir. La mayor característica que diferencia al listado es ele uso de columnas. Utilizaremos FlowListView.

Añadir el logo en la barra de navegación

En Android tenemos la definición de la Toolbar en Resources > layout >Toolbar.axml. Para añadir una imagen como logo y poder configurarla a nuestro antojo:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/toolbar"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="?attr/colorPrimary"
 android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
 android:popupTheme="@style/ThemeOverlay.AppCompat.Light"
 android:elevation="5dp">
      <ImageView
           android:id="@+id/logoImageLayout"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:adjustViewBounds="true"
           android:src="@drawable/netflix" />
</android.support.v7.widget.Toolbar>

El caso de iOS es ligeramente diferente.

public class LogoPageRenderer : PageRenderer
{
     public override void ViewWillAppear(bool animated)
     {
          base.ViewWillAppear(animated);

          var image = UIImage.FromBundle("netflix.png");
          var imageView = new UIImageView(new CGRect(0, 0, 140, 70));

          imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
          imageView.Image = image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);

          if (NavigationController != null)
          {
               NavigationController.TopViewController.NavigationItem.TitleView = imageView;
          }
     }
}

Creamos un sencillo Custom Renderer donde vamos a añadir un UIImageView como nuestro logo de la TitleView de UINavitationItem.

Botones en la barra de navegación

Este bloque no tiene gran complejidad ya que Xamarin.Forms cuenta con soporte directo para poder añadir y gestionar botones de la Toolbar.

<ContentPage.ToolbarItems>
     <ToolbarItem
          Icon="edit"/>
</ContentPage.ToolbarItems>

Listado con columnas

¿Cómo podemos gestionar esta necesidad?. Tenemos muchas opciones:

  • Crear un control personalizado de Layout.
  • Crear un control más simple utilizando un ScrollView y un Grid.
  • Utilizar algo existente que nos otorge esta solución.

La comunidad Xamarin y el conjunto de plugins, controles y librerías disponibles es elevada. Vamos a utilizar FlowListView.

FlowListView permite crear listados con columnas además de permitir:

  • Carga infinita.
  • Cualquier contenido como celda.
  • DataTemplateSelector.
  • Grupos.
  • Etc.

Añadimos el paquete NuGet a todos los proyectos de la solución. Debemos realizar la inicialización de FlowListView en nuestra librería compartida, App.xaml.cs:

FlowListView.Init();

A continuación, y tras declarar el espacio de nombres en la página XAML de selección de perfil:

xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView"

Utilizamos el control:

<flv:FlowListView
     FlowItemsSource="{Binding Profiles}"
     FlowItemTappedCommand="{Binding HomeCommand}"
     BackgroundColor="{StaticResource BackgroundColor}"
     FlowColumnCount="2" 
     FlowColumnExpand="First"
     SeparatorVisibility="None"
     HasUnevenRows="True">
     <flv:FlowListView.FlowColumnTemplate>
          <DataTemplate>
               <templates:ProfileItemTemplate />
          </DataTemplate>
     </flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>

Definimos dos columnas con la propiedad FlowColumnCount.

Vamos a ver el resultado final de lo que llevamos, en Android:

Selección de perfil en Android

Y en iOS:

Selección de perfil en iOS

Vamos bastante bien, ¿continuamos?.

Pantalla principal

Continuamos con la pantalla principal y al igual que hicimos previamente, vamos a realizar un análisis previo de que vamos a necesitar:

  • Tenemos un menú lateral deslizante. Un patrón de navegación muy conocido y utilizado en una gran variedad de aplicaciones. En Xamarin.Forms podemos utilizar este patrón de navegación utilizando una MasterDetailPage.
  • Se continua mostrando el logo en la barra superior. Continuaremos utilizando lo previamente realizado.
  • Contamos con un botón de búsqueda en la parte superior. De nuevo, volveremos a hacer uso de ToolbarItem.
  • El contenido se caracteriza por contar con diferentes grupos o bloques de elementos a los que accedemos realizando scroll horizontal. Para conseguir este objetivo, vamos a realizar un control personal.

Menú lateral deslizante

Al navegar al apartado principal, necesitaremos utilizar una MasterDetailPage.

<MasterDetailPage 
     xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
     x:Class="Xamarin.Netflix.Views.MainView" 
     xmlns:views="clr-namespace:Xamarin.Netflix.Views"
     MasterBehavior="Popover">
     <MasterDetailPage.Master>
          <views:MenuView
               BindingContext="{Binding MenuViewModel}"/>
     </MasterDetailPage.Master>
     <MasterDetailPage.Detail>
          <ContentPage 
               BackgroundColor="Transparent" />
     </MasterDetailPage.Detail>
</MasterDetailPage>

MasterDetailPage cuenta con dos propiedades fundamentales:

  • Master: Contenido del menú lateral deslizante.
  • Detail: Vista que visualizamos.

En Master vamos a definir el menú principal de Netflix un poco más adelante. En Detail, vamos a definir en una ContentPage la vista principal.

Listado horizontal

Necesitamos utilizar un listado horizontal. Ante un volumen elevado de elementos debemos de pensar en aspectos como el rendimiento (caché, reutilización del celdas, etc.). En este caso, cada listado horizontal cuenta con un volumen bajo de elementos.

Vamos a realizar un control personal con código totalmente compartido y utilizando elementos de Xamarin.Forms. Vamos a utilizar un ScrollView junto a un StackLayout apilando elementos horizontalmente. Veamos el constructor del control con la definición básica del mismo:

public HorizontalList()
{
      _scrollView = new ScrollView();
      _itemsStackLayout = new StackLayout
     {
          Padding = Padding,
          Spacing = Spacing,
          HorizontalOptions = LayoutOptions.FillAndExpand
     };

     _scrollView.Content = _itemsStackLayout;
     Children.Add(_scrollView);
}

Necesitamos definir la fuente de información, como se verá cada elemento, etc. Para ello, definimos una serie de BindableProperties:

public static readonly BindableProperty SelectedCommandProperty =
     BindableProperty.Create("SelectedCommand", typeof(ICommand), typeof(HorizontalList), null);

public static readonly BindableProperty ItemsSourceProperty =
     BindableProperty.Create("ItemsSource", typeof(IEnumerable), typeof(HorizontalList), default(IEnumerable<object>), BindingMode.TwoWay, propertyChanged: ItemsSourceChanged);

public static readonly BindableProperty SelectedItemProperty =
     BindableProperty.Create("SelectedItem", typeof(object), typeof(HorizontalList), null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);

public static readonly BindableProperty ItemTemplateProperty =
     BindableProperty.Create("ItemTemplate", typeof(DataTemplate), typeof(HorizontalList), default(DataTemplate));

A la hora de utilizar el control:

<Label
     Text="Continue watching"
     Style="{StaticResource TitleStyle}">
</Label>
<controls:HorizontalList 
     ListOrientation="Horizontal" 
     ItemsSource="{Binding Watching}"
     HeightRequest="200">
     <controls:HorizontalList.ItemTemplate>
          <DataTemplate>
               <templates:WatchingItemTemplate />
          </DataTemplate>
     </controls:HorizontalList.ItemTemplate>
</controls:HorizontalList>

Dentro de un StackLayout (apila elementos por defecto verticalmente) repetimos la misma estructura para mostrar diferentes grupos (últimas novedades, películas, series, etc.). El resultado en Android:

Vista principal en Android

Y en iOS:

Vista principal en iOS

El menú principal

¿Recuerdas que anteriormente hablamos ligeramente del menú principal al hablar de la MasterDetailPage?. Es hora de retomarlo. Características:

  • Tenemos una cabecera donde podemos ver el perfil utilizado en la aplicación.
  • A continuación, tenemos un listado con las diferentes secciones de la aplicación.
  • Hay apartados que destacan al contar con separadores entre otros elementos además de icono que refuerza su contenido.

Listado de opciones

Todos los puntos anteriores los podemos conseguir directamente utilizando un ListView junto a una ViewCell personalizada y el Header.

<ListView
     ItemsSource="{Binding MenuItems}" 
     BackgroundColor="{StaticResource MenuBackgroundColor}"
     SeparatorVisibility="None">
     <ListView.ItemTemplate>
          <DataTemplate>
               <ViewCell>
                    <templates:MenuItemTemplate />
               </ViewCell>
          </DataTemplate>
     </ListView.ItemTemplate>
</ListView>

El separador solo aparece con algunos de los elementos. Por este motivo, y aunque el ListView cuenta con la propiedad SeparatorVisibility, creamos el separador en la plantilla que define a cada elemento donde vamos a controlar la visibilidad en base a una propiedad que define cada elemento del menú.

<Grid
     HeightRequest="48">
     <Grid.Triggers>
          <DataTrigger
               TargetType="Grid"
               Binding="{Binding IsEnabled, Mode=TwoWay}"
               Value="False">
               <Setter Property="Opacity" Value="0.6" />
          </DataTrigger>
     </Grid.Triggers>
     <Grid.ColumnDefinitions>
          <ColumnDefinition Width="2" />
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition Width="*" />
     </Grid.ColumnDefinitions>
     <Grid.RowDefinitions>
          <RowDefinition Height="*" />
          <RowDefinition Height="Auto" />
     </Grid.RowDefinitions>
     <Image 
          Grid.Row="0"
          Grid.Column="1"
          Source="{Binding Icon}"
          Style="{StaticResource MenuItemIconStyle}"/>
     <Label 
          Grid.Row="0"
          Grid.Column="2"
          Text="{Binding Title}"
          Style="{StaticResource MenuItemTextStyle}"/>
     <Grid 
          Grid.Row="1"
          Grid.Column="0"
          Grid.ColumnSpan="3"
          HeightRequest="2"
          BackgroundColor="{StaticResource BlackColor}"
          IsVisible="{Binding Separator}"/>
</Grid>

El resultado en Android:

Menú en Android

Y en iOS:

Menú en iOS

La información detallada de un contenido

Llegamos a la vista más compleja de todas las que llevamos.

¿Por qué?.

Analicemos las necesidades:

  • La barra de navegación, donde encontraremos el botón de navegación atrás entre otras opciones, es transparente!. Vamos a necesitar un Custom Renderer para conseguir este objetivo tanto en Android como en iOS.
  • El logo… desaparece. Tenemos que gestionar este cambio. En Android usaremos código específico para acceder a la imagen de logo y jugar con su visibilidad. En iOS, también vamos a utilizar código específico pero en forma de Custom Renderer.
  • La imagen destacada del elemento (película, documental o serie) seleccionada hace efecto Parallax. Gracias a las opciones de transformación de Xamarin.Forms podremos hacer translaciones, jugar con la opacidad o escala. Es decir, podemos conseguir este efecto gestionando el scroll realizado y con código totalmente compartido.
  • Hay un listado de elementos similares mostrado en tres columnas. Aquí volveremos a hacer uso de FlowListView.

Barra transparente

Una de las características principales de la página de detalles es la barra de navegación transparente.

¿Cómo lo conseguimos?.

En Android, vamos a crear un Custom Renderer de NavigationPage.

public class CustomNavigationBarRenderer : NavigationPageRenderer
{

}

Junto al uso de mensajería utilizando FormsToolkit haremos que por defecto el color de la barra de navegación sea de color, menos el la página de detalles, que será transparente.

MessagingService.Current.SendMessage(MessageKeys.ToolbarColor, Color.Transparent);

En el renderer personalizado de la NavigationPage, vamos a verificar si el color es transparente para modificar el tamaño y posición del Layout para conseguir el efecto.

En el caso de iOS, necesitamos de nuevo un Custom Renderer.

public class TransparentNavigationBarPageRenderer : PageRenderer
{
     public override void ViewDidLayoutSubviews()
     {
          base.ViewDidLayoutSubviews();

          if (NavigationController != null)
          {
               NavigationController.NavigationBar.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
               NavigationController.NavigationBar.ShadowImage = new UIImage();
               NavigationController.NavigationBar.BarTintColor = UIColor.Clear;
               NavigationController.NavigationBar.TintColor = UIColor.White;
          }
     }
}

Modificamos el color de la barra, suprimimos la imagen de sombra para evitar cualquier tipo de separación visual entre la cabecera y el contenido para lograr la sensación de continuidad buscado.

Es momento de quitar el logo

De nuevo, hacemos uso de mensajería utilizando FormsToolkit para conseguir este objetivo en Android. Desde la vista de detalles (PCL):

MessagingService.Current.SendMessage(MessageKeys.ChangeToolbar, true);

Y nos suscribimos para recibir el mensaje desde el proyecto Android, en la actividad principal:

MessagingService.Current.Subscribe<bool>(MessageKeys.ChangeToolbar, (page, showLogo) =>
{
     var logo = FindViewById<ImageView>(Resource.Id.logoImageLayout);

     if (showLogo)
     {
          logo.Visibility = ViewStates.Visible;
     }
     else
     {
          logo.Visibility = ViewStates.Invisible;
     }
});

Accedemos a la imagen Toolbar y cambiamos la visibilidad según en caso (mostrar u ocultar).

En el caso de iOS, gracias al uso de Platform Specifics, hacemos la barra traslúcida.

var navigationPage = Parent as Forms.NavigationPage;

if (navigationPage != null)
     navigationPage.On<iOS>().EnableTranslucentNavigationBar();

Además. recuerda que previamente ya vimos el renderer de la NavigationPage aplicado a la página de detalles.

[assembly: ExportRenderer(typeof(DetailView), typeof(TransparentNavigationBarPageRenderer))]

Parallax

Sin duda, lo habrás experimentado ya sea en web o e aplicaciones móviles. Haces scroll y el fondo (o una imagen) se mueve a una velocidad distinta que el contenido, creando un ligero efecto de profundidad.

¿Cómo conseguimos esto?.

Hemos comentado que el efecto se aplica al hacer scroll. Por lo tanto, comenzamos capturando información cada vez que se realiza scroll gracias al evento Scrolled del ScrollView.

ParallaxScroll.Scrolled += OnParallaxScrollScrolled;

Tras hacer scroll vertical, la dirección puede ser en dos sentidos, hacia arriba o hacia abajo:

double translation = 0;

if (_lastScroll < e.ScrollY)
     translation = 0 - ((e.ScrollY / 2));
else
     translation = 0 + ((e.ScrollY / 2));

HeaderPanel.TranslateTo(HeaderPanel.TranslationX, translation);

Dependiendo de la dirección del scroll, se captura la cantidad de scroll realizado con e.ScrollY, para finalmente aplicar una transformación de transladación de la cabecera.

El resultado:

NOTA: Se puede modificar este efecto para conseguir potenciarlo aún más. Habitualmente también se juega con la escala y con la opacidad. Ambas opciones al igual que la transladación son posibles desde código compartido.

Listado con tres columnas

Nada “diferente” a lo ya visto previamente. Hacemos uso de FlowListView:

<flv:FlowListView
     FlowItemsSource="{Binding SimilarMovies}"
     BackgroundColor="{StaticResource BackgroundColor}"
     FlowColumnCount="3" 
     FlowColumnExpand="First"
     SeparatorVisibility="None"
     HasUnevenRows="True"
     HeightRequest="350">
     <flv:FlowListView.FlowColumnTemplate>
          <DataTemplate>
               <templates:MovieItemTemplate />
          </DataTemplate>
     </flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>

Aplicando 3 columnas con la propiedad FlowColumnCount.

El resultado en Android:

Detalles de una pelícucla en Android

Y en iOS:

Detalles en iOS

Puedes descargar el código del ejemplo desde GitHub:

Ver GitHub

¿Qué plugins o componentes se han utilizado?

Se ha utilizado:

  • FFImageLoading – Con el objetivo principal de cachear imágenes. Dado el tipo de aplicación y la importancia de las imágenes, es importante. Aunque recuerda, en este ejemplo todas las imágenes son locales.
  • Xamarin Forms Toolkit – Toolkit para Xamarin.Forms con helpers, converters, etc. Se hace uso principalmente del sistema de mensajería.
  • FlowListView – ListView con soporte a columnas (entre otras características).

Conclusiones

Creo que las capturas son una buena conclusión. Logramos replicar la interfaz de usuario de una aplicación sumamente utilizada y destacada en las diferentes tiendas utilizando exclusivamente lo que proporciona Xamarin.Forms junto a plugins o componentes gratuitos por parte de la comunidad.

Tras pasar varias analíticas podemos ver que en este ejemplo, en Android se llega a compartir un 85,87% de código y un 89.53% en iOS. Podríamos seguir compartiendo gran cantidad de lógica como peticiones HTTP, gestión de errores, etc. Sin embargo, probablemente y de cara a ciertas necesidades de la aplicación, también se requerirían más Custom Renders y/o efectos. La cantidad de código compartida seguiría siendo elevada.

Y llegamos a la parte final del artículo. Es un concepto de artículo que tenía en mente y he decidido a lanzarme a ello tras ver una idea similar por varios compañeros en la comunidad. ¿Qué te parece este tipo de artículos?. Es sumamente divertido preparar una aplicación conocida e intetar “desgranar” cada pasos a realizar. Sin duda, espero repetir esta idea con otras aplicaciones aunque me gustaría saber tu opinión. ¿prefieres artículo habitual, videoblog, otro formato?.

Más información

[Xamarin.Forms] Recopilación de ejemplos con interfaz de usuario atractiva

Introducción

La evolución de Xamarin.Forms es meritoria. En los últimos tiempos se han recibido novedades interesantes como efectos, vistas nativas, Forms Embedding, etc. Sin embargo, en muchos casos se sigue asociado a desarrollos muy simples o formularios básicos.

Realmente, en el estado actual de Xamarin.Forms se pueden conseguir aplicaciones nativas de gran escala, con interfaces cuidadas y con alta integración con la plataforma.

La comunidad de Xamarin.Forms, en los últimos tiempos, ha realizado gran cantidad de ejemplos reproduciendo desde patrones de diseño muy habituales hasta aplicaciones destacadas en cada tienda de aplicaciones y muy utilizadas.

Recopilación de ejemplos

Cada ejemplo reproduciendo una aplicación real o un apartado concreto suele contener un gran conjunto de pequeños detalles, Custom Renderers o efectos. Aspectos como:

  • Añadir logo personalizado en la parte superior.
  • Barra superior transparente.
  • Personalizar mapas.
  • Etc.

El volumen de ejemplos está creciendo (¡y seguirá creciendo!) así que, ¿y si hacemos una recopilación?. Se ha creado un repositorio en GitHub donde se van a ir recopilando todos los ejemplos que busquen como objetivo mostrar como conseguir interfaces de usuario atractivas con Xamarin.Forms.

NOTA: Se buscan ejemplos de código abierto que puedan ayudar al resto de usuarios de la comunidad a conseguir resultados similares.

De cada ejemplo recopilado se buscará:

  • Incluir enlace al autor.
  • Incluir enlace a blog relacionado con el ejemplo (si existe).
  • Enlace al código fuente.
  • Imágenes, gifs o videos.
  • Descripción y principales características.

¿Qué te parece la idea?, ¿echas en falta más información en cada ejemplo?.

Más información

[Xamarin.Forms] Localización de Aplicaciones

Introducción

Cuando desarrollamos nuestras aplicaciones, un factor importante a tener en cuenta es el público objetivo de la misma. Analizando este punto debemos determinar si distribuimos nuestra aplicación a nivel nacional, en multiples países o a nivel mundial. Si decidimos la última opción debemos de tener en cuenta que aunque las probabilidades de llegar a una mayor cantidad de público aumentan considerablemente, no todo el mundo habla español por lo que seguimos restringidos.

¿Qué podemos hacer?

En este artículo vamos a realizar los pasos necesarios para localizar una aplicación Xamarin.Forms , ¿te apuntas?.

Globalización en Apps Xamarin.Forms

El proceso de globalización consiste en preparar nuestra aplicación para “todo el mundo”. La aplicación debe estar preparada para mostrar la información en diferentes idiomas. Los textos y recursos de nuestra aplicación deben ser diferentes en base al idioma configurado por el dispositivo.

Archivos RESX

Para la gestión de textos en cada idioma utilizaremos archivos RESX. Tendremos un archivo de recursos diferente por cada idioma soportado. Cada archivo se basa en clave-valor. Las claves se repetirán en cada archivo mientras que el valor será la cadena localizada al idioma correspondiente.

Creando los archivos RESX

En la librería portable, comenzamos creando una carpeta Resources con el objetivo de mantener todos los archivos organizados. A continuación, crearemos un archivo de recursos por cada idioma soportado. Para crear el archivo de recursos, hacemos clic derecho sobre la recien creada carpeta Resources, Añadir > Nuevo archivo > General > Resource File.

Nuevo archivo de recursos

Nombra al archivo como Resources o AppResources (nombres habituales) para el idioma por defecto, inglés. Por cada idioma soportado, se debe repetir el proceso llamando al archivo AppResources.{nombre cultura}.resx.

NOTA: Puedes ver un listado completo de países, idiomas y su cultura en este enlace.

Añadiendo soporte al idioma español:

Español

Tras ambos archivos, si abrimos un archivo de recurso veremos algo como lo siguiente:

RESX

Añadiremos las claves en la comuna Nombre y el valor localizado a cada idioma en la columna Valor. Posteriormente, accederemos a cada valor localizado utilizando la clave. En base al idioma, se accederá a un archivo de recursos u otro. De esta forma, podremos mantener de forma sencilla los textos localizados y ofecer una aplicación localizada a diferentes idiomas.

Utilizando los archivos desde C#

Tras añadir un valor:

Añadimos valores

Podemos acceder al valor desde código C# de forma sumamente sencilla:

Label label = new Label()
{
     Text = AppResources.LanguageText
};

Si se lanza la aplicación en español y en inglés el valor estará localizado en cada idioma.

Y ahora desde XAML

Utilizar valores localizados utillizando archivos de recursos es rápido y directo desde código C#. Sin embargo, desde XAML necesitamos “algo más”. Por defecto, no tenemos ninguna extensión de marcado que nos permita indicar el valor de la clave que buscamos en el archivo de recursos para permitir localizar la aplicación. Sin embargo, si podemos crear extensiones de marcado personalizadas utilizando la interfaz IMarkupExtension:

[ContentProperty("Text")]
public class TranslateExtension : IMarkupExtension
{
     const string ResourceId = "XamarinFormsLocalization.Resources.AppResources";

     public string Text { get; set; }

     public object ProvideValue(IServiceProvider serviceProvider)
     {
          if (Text == null)
               return null;

          ResourceManager resourceManager = new ResourceManager(ResourceId, typeof(TranslateExtension).GetTypeInfo().Assembly);

          return resourceManager.GetString(Text, CultureInfo.CurrentCulture);
     }
}

Utilizamos la clase ResourceManager para acceder al archivo de recurso correspondiente. A continuación, se utiliza el método GetString para obtener el valor asociado a la clave pasada como parámetro en la propiedad Text.

¿Y cómo lo utilizamos?.

Sencillo, primero declaramos el espacio de nombres en XAML necesario:

xmlns:extensions="clr-namespace:XamarinFormsLocalization.MarkupExtensions"

Y a continuación:

 <Label 
      Text="{extensions:TranslateExtension Text=LanguageText}" />

Utillizamos la extensión pasando como parámetro la clave deseada en la propiedad Text. También podemos utilizar la extensión de marcado de forma menos verbosa:

<Label 
     Text="{extensions:Translate LanguageText}" />

Otros recursos

Una aplicación móvil no se compone exclusivamente de textos. Existen otra serie completa de recursos muy utilizados. Entre los recursos más utilizados, imágenes.

Normalmente se cuentan con imágenes que se pueden ver exactamente igual en diferentes idiomas, pero no así con todas.

¿Cómo gestionamos la localización de imágenes por idioma?

Es una tarea que debemos realizar en cada plataforma de forma específica.

Android

Utilizamos la carpeta drawable dentro de Resources para la gestión de imágenes. Para contar con imágenes diferentes por idioma, podemos crear carpetas con el nombre drawable-{código del idioma}. Android se basa en esta estructura de carpetas con sufijos para localizar imágenes.

Imágenes localizadas en Android

NOTA: Para soportar diferentes imágenes para resoluciones diferentes y además basándonos en el idioma, seguimos utilizando la misma estructura de sufijos en carpetas. Por ejemplo: drawable-es-xdpi.

iOS

En este caso, iOS, utiliza Localization Projects o .lproj para contener imágenes por idioma junto con recursos de cadenas. Dentro de la carpeta Resources debemos crear {códido de idioma}.lproj por cada idioma soportado.

Localización de imágenes en iOS

Cada carpeta correspondiente a un idioma contará con sus versiones de imágenes. En caso de que una carpeta de un idioma no cuenta con imágenes, se utilizarán las correspondientes del idioma por defecto.

NOTA: Para pantallas retina se pueden añadir imágenes @2x y @3x.

UWP

En el caso de aplicaciones universales, organizaremos dentro de la carpeta Assets los recursos por idioma en carpetas con el nombre de la cultura.

Localización de imágenes en UWP

No tenemos un mecanismo que automáticamente seleccione la imagen correspondiente a cada idioma. Por este motivo, vamos a crear un sencillo Custom Renderer.

xmlns:extensions="clr-namespace:XamarinFormsLocalization.MarkupExtensions"
[assembly: ExportRenderer(typeof(Image), typeof(XamarinFormsLocalization.UWP.Renderers.LocalizedImageRenderer))]
namespace XamarinFormsLocalization.UWP.Renderers
{
     public class LocalizedImageRenderer : ImageRenderer
     {
          protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
          {
               base.OnElementChanged(e);

               if (e.NewElement != null)
               {
                    var fileImageSource = e.NewElement.Source as FileImageSource;

                    if (fileImageSource != null)
                    {
                         var fileName = fileImageSource.File;
                         string currentUICulture = CultureInfo.CurrentUICulture.ToString();
                         e.NewElement.Source = Path.Combine("Assets/" + currentUICulture + "/" + fileName);
                    }
               }
          }
     }
}

Creamos un Custom Render en UWP del control Image. Se obtiene la ruta de la imágen a la que se añade la ruta correcta utilizando CurrentUICulture. De esta forma, automáticamente, en base al idioma se accederá a una ruta u otra.

El resultado de la aplicación en inglés:

Inglés

Y en español:

Español

Puedes descargar el código del ejemplo desde GitHub:

Ver GitHub

Existen otra serie de puntos interesantes relacionados con la localización de aplicaciones como por ejemplo la localización del nombre de la aplicación que veremos en otro artículo.

Recuerda, cualquier duda o comentario es bienvenido!

Más información

[Xamarin.Forms] Cambios en la clase Device: RuntimePlatform

Introducción

Xamarin.Forms añade una capa de abstracción sobre la capa de la interfaz de usuario permitiendo definir la misma una única vez siendo válida para todas las plataformas.

Xamarin.Forms

A pesar de definir la interfaz de usuario una única vez para todas las plataformas, tenemos la posibilidad de realizar personalizaciones y adaptaciones para ofrecer la mejor experiencia posible en cada una de las plataformas soportadas.

La clase Device

La clase Device sin duda alguna es una de las claves a la hora de personalizar la interfaz de usuario por plataforma. Esta clase contiene diversas propiedades y métodos para personalizar la UI y la funcionalidad en base a la plataforma.

TargetPlatform

Previamente ya conocimos en el blog a esta clase. ¿Por qué volvemos a revisarlo?. Sencillo, en el proceso de actualización de Xamarin.Forms normalmente se incluyen novedades sin afectar a lo existente y en ocasiones, como esta, afectan a algo existente.

Dentro de la clase Device, lapropiedad OS permitía identificar la plataforma en la que se ejecuta la aplicación. Podía ser un valor de la enumeración TargetPlatform. Sin embargo, si lo utilizas verás que te indica que es algo obsoleto. En lugar de OS, ahora se debe utilizar RuntimePlatform que puede tener un valor de la enumeración TargetPlatform con uno de los siguientes valores:

  • Android
  • iOS
  • macOS
  • UWP

NOTA: Ante la futura llegada de nuevos backends como GTK# o WPF, es de esperar recibir nuevos valores en TargetPlatform.

if(Device.RuntimePlatform == Device.iOS)
{
     this.Padding = new Thickness (0, 12, 0, 0);
}

¿Y en XAML?

La interfaz de usuario de las aplicaciones Xamarin.Forms podemos definirla en C# o desde código XAML. Desde XAML también podemos realizar personalizaciones en base a la plataforma utilizando el método OnPlatform.

OnPlatform

De forma similar, Device.OnPlatform ha sido reemplazado por OnPlatform y las APIs On. Vienen a facilitar las mismas posibilidades vistas previamente pero en XAML.

<StackLayout.Margin>
      <OnPlatform x:TypeArguments="Thickness">
           <On Platform="Android, iOS" Value="0,20,0,0" />
           <On Platform="Windows" Value="0,0,0,0" />
      </OnPlatform>
</StackLayout.Margin>

NOTA: Como puedes ver, se utilizan cadenas para especificar cada plataforma. Ante un valor incorrecto de plataforma ningún error o excepción se lanzará. Sencillamente no se ejecutará el código específico de la plataforma que se aplica incorrectamente.

Más información

[Xamarin] Reporte de errores y analíticas con Mobile Center

Introducción

Una vez desarrollada una aplicación, recibir feedback sobre la misma es sumamente útil. Sería interesante saber información como cuanto tiempo estan los usuarios con nuestra aplicación, por que páginas navega, por donde nunca pasa el usuario, desde que dispositivos accede, errores, etc. Con esta información podemos sacar muchas conclusiones como detectar problemas de UX, añadir un mayor esfuerzo en zonas de la aplicación donde el usuario pasa la mayor parte del tiempo, esforzarnos por facilitar y promover el acceso a zonas apenas accedidas, corrección de bugs, etc.

¿Cómo podemos obtener toda esa información?

En este artículo, vamos a ver paso a paso como integrar una aplicación Xamarin.Forms con Visual Studio Mobile Center con el objetivo de descubrir y analizar errores en nuestras aplicaciones.

Mobile Center

Mobile Center es un centro de control de nuestras aplicaciones móviles. Mobile Center soporta tanto aplicaciones Xamarin como aplicaciones nativas con Java, Objective-C o Swift además de aplicaciones React Native.

Incluye:

  • Build: Integración y entrega continua.
  • Test: Pruebas automáticas en dispositivos reales.
  • Reporte de errores: Analíticas de errores en tiempo real.
  • Distribución: Despliegue a usuarios o grupos.
  • Analíticas: Métricas de uso.
  • Autenticación: Integración sencilla con métodos comunes.
  • EasyTables: Crear almacenamiento de forma muy rápida.

Crear la App

Accedemos al portal de Mobile Center.

Mobile Center

NOTA: Si no tienes cuenta de Mobile Center, puedes crear una desde este enlace.

Tras acceder al portal, debemos crear una nueva aplicación.

Nueva App

Se debe introducir el nombre de la aplicación, elegir Xamarin como plataforma y sistema operativo (iOS, Android o Windows). En este ejemplo, seleccionaremos Android.

Tras crear la aplicación, tenemos información disponible de que hacer para integrar Mobile Center en nuestra aplicación.

Pasos a realizar

Vamos a ello!

Preparar la App

Debemos gestionar los paquetes NuGet a nivel de solución (todos los proyectos que componen la solución Xamarin) para añadir las siguientes referencias:

  • Microsoft.Azure.Mobile.Analytics
  • Microsoft.Azure.Mobile.Crashes
Microsoft.Azure.Mobile.Analytics
Microsoft.Azure.Mobile.Crashes

Es hora de inicializar las analíticas. En la librería portable (PCL), en el archivo App.xaml.cs se deben añadir los siguientes using:

using Microsoft.Azure.Mobile;
using Microsoft.Azure.Mobile.Analytics;
using Microsoft.Azure.Mobile.Crashes;

A continuación, en el método OnStart que se lanzará al iniciar la App:

MobileCenter.Start("android={Insert App secret here}", typeof(Analytics), typeof(Crashes));

El código anterior, inicializa Mobile Center SDK en Android. Sin embargo, estamos en una aplicación Xamarin.Forms, ¿qué courre con el resto de plataformas?. Podemos inicializar más de una plataforma especificándola:

MobileCenter.Start("ios={Insert iOS App secret here};uwp={Insert UWP App secret here};android={Insert Android App secret here}", typeof(Analytics), typeof(Crashes));

Llegados a este punto, recibiremos analíticas en el portal como:

  • Actividad de usuarios
  • Sesiones por usuario diarias
  • Durración de cada sesión
  • Dispositivos más usados
  • Países
  • Actividad por versiones
  • Errores

Vamos a ver a continuación como registrar eventos personalizados o excepciones. Creamos una interfaz muy simple que nos permita hacer pruebas de registro de eventos y excepciones:

Nuestra App

Para registrar eventos personalizados utilizamos el método TrackEvent. Además de pasar una cadena con el nombre del evento, podemos utilizar un Dictionary para capturar diferentes parámetros.

var properties = new Dictionary<string, string>
{
     { "Parameter", "Data" }
};

Analytics.TrackEvent("EventBtn Clicked", properties);

¿Y qué debemos hacer para registrar excepciones?. En el arranque de la App inicializamos ya el registro de excepciones, no se requiere nada más. Si lanzamos con el segundo botón una excepción:

 throw new Exception("Exception information");

Quedará registrada.

Revisar analíticas

Accediendo al portal de Mobile Center, y entrando en nuestra App, tendremos acceso a analíticas desde los apartados Crashes y Analytics.

En Analytics tendremos información como:

  • Usuarios activos.
  • Sesiones diarias.
  • Duración decada sesión.
  • Dispositivos.
  • Versiones del sistema operativo.
  • Países.
  • Lenguajes.
Analíticas

Dentro del apartado de Analytics encontramos los eventos personalizados en Events:

Eventos

De nuevo tenemos información detallada como:

  • Listado de eventos.
  • Total de veces que se lanza el evento por usuario o por sesión.
  • Listado de parámetros.

Y llegamos a uno de los apartados más interesantes, Crashes:

Errores

Tenemos la traza del error detallado además de información extra que nos puede ayudar bastante como el dispositivo o versión del sistema operativo.

Tenéis el código fuente del ejemplo utilizado disponible en GitHub:

Ver GitHub

Más información