Desarrollo de Apps Cross-Platform con Xamarin.Forms

Publicado en

Autor

Xamarin es una plataforma para desarrollar aplicaciones para plataformas iOS, Android , Windows Phone , Windows Store y Mac usando el lenguaje de programación C#. Cabe aclarar que en este artículo sólo trataremos el desarrollo de Android e iOS por ser las plataformas de terceros. Para Windows Phone o Windows Store, si somos desarrolladores de .NET no se nos complica en lo absoluto, es muy parecido a lo que ya sabemos desarrollar, sólo que con diferentes estándares de desarrollo de la UI (User Interface). Es importante mencionar que Xamarin dispone de una versión para estudiantes, con la que se puede compilar y probar las aplicaciones utilizando Xamarin Studio. Adicionalmente se anunció hace algunos meses la firma de colaboración entre Xamarin y Microsoft, que además de tener un equipo de trabajo dedicado a optimizar y explotar mejor los recursos de las diferentes plataformas, se tendrá disponible desde la versión Visual Studio Community 2015 la Free Xamarin Starter Edition for Visual Studio Users, es decir, podremos compilar, ejecutar y probar las aplicaciones para Android e iOS, por lo que si había duda de qué tan fuerte está Xamarin en el mercado, con los recientes anuncios por parte de ambas compañías vemos una seria consolidación en el mundo de desarrollo de aplicaciones multiplataforma y se despeja la interrogante.

Xamarin nos da la posibilidad de tener una base de código compartido que contiene entidades de negocio, lógica de negocio, acceso a servicios, etcétera, y simplemente tener código distinto para los detalles de interfaz de usuario para la capa de cliente en cada plataforma. Básicamente es como desarrollar al mismo tiempo para todas las plataformas, por  lo que minimizamos tiempos de desarrollo. Por ejemplo, tradicionalmente tenemos que desarrollar la aplicación en Java para Android y en Objective-C para iOS la misma funcionalidad, lo cual es tedioso y repetitivo, con Xamarin podemos reutilizar el código en un 75-85% según fuentes oficiales. Esto no quiere decir que no tengamos que saber detalles de cada plataforma, de hecho lo mejor es conocer al menos conceptos básicos del manejo de recursos, configuraciones, etcétera, ya que al final el proceso es como si estuviéramos desarrollando una aplicación nativa respectivamente, pues se genera una .APK para Android y un .IPA para iOS; y se le debe dar el tratamiento normal a cada una para probar en dispositivos o emuladores para posteriormente publicar. Otro punto importante es que para Android por ejemplo, si tenemos algunos componentes en java podemos utilizarlo por medio de lo que llamamos Java Integration, para hacer un Java Bindings Library (una clase wrapper del tipo en java) para hacer referencia desde C# hacia los archivos .jar; así como también un Java Native Interface (JNI) que permite realizar llamadas a código java corriendo en la JVM (Java Virtual Machine) desde aplicaciones no escritas en java, por lo cual Xamarin.Android utiliza JNI para crear sus bindings en el codigo C#.

Por ejemplo para Android, al construir el proyecto nos generará el archivo .APK, el cual podremos ejecutar en un emulador, en un dispositivo o incluso en la tienda de google realizando el proceso tradicional.

La figura 2 ilustra la arquitectura típica de una aplicación Xamarin.

Figura 1. Arquitectura de aplicación Xamarin.

Lo que muestra la figura 1 es que tenemos un proyecto o librería compartida que contiene los componentes de las capas de negocio, servicios y datos. Por otro lado, tenemos distintas aplicaciones para cada tipo de cliente, que utilizan las librerías y componentes nativos de la User Interface de cada plataforma. Las aplicaciones cliente acceden al código compartido para interactuar con las capas de negocio, servicios y datos.

Para desarrollar las aplicaciones nativas para cada plataforma, Xamarin ofrece dos estrategias:

  • La primera es crear aplicaciones específicas para cada plataforma por ejemplo utilizando Xamarin.iOS y Xamarin.Android, dependiendo del caso. Esto permite aprovechar los elementos de UI específicos de cada plataforma y construir así interfaces de usuario avanzadas y personalizadas para cada una.

  • La segunda estrategia es Xamarin.Forms. Una serie de componentes que permite definir interfaces de usuario para distintas plataformas desde una misma base de código. Xamarin.Forms está orientado a construir aplicaciones con interfaces de usuario sencillas, donde es más importante la capacidad de compartir código que el brindar interfaces de usuario avanzadas y personalizadas para cada plataforma, sin embargo, existe la posibilidad de hacer la personalización de los componentes a cada plataforma heredando nuestro componente básico de Xamarin.Forms a uno que se implementara en el proyecto de iOS y Android , y ahi podemos usar instrucciones típicas (equivalentes en .NET) de Objective-C y Java respectivamente.

Primera aplicación Xamarin.Forms

A continuación mostraremos cómo se construye una aplicación con Xamarin.Forms. Por ahora solo crearemos para iOS y Android como se mencionó antes. Haremos esto en Visual Studio.

  1. Visual Studio –> Nuevo Proyecto.

  2. Seleccionamos aplicación en blanco de tipo Xamarin.Forms.Portable.

  3. En el nombre de la solución, escribimos “SG”.

Enseguida tenemos 3 proyectos:

El primero es SG, un proyecto portable en el que vamos a escribir el código común. En los proyectos SG.Android y SG.iOS vamos a escribir lo requerido por cada plaforma. La figura 2 muestra la estructura generada.

Figura 2. Estructura del proyecto.

En el proyecto SG tendremos el programa App.cs cuyo código base se muestra en el listado 1.

Listado 1. App.cs

El listado 2 muestra el el código del MainActivity.cs en el proyecto de Android, y el listado 3 muestra AppDelegate.cs para el proyecto iOS.

 

Listado 2. MainActivity.css

 

Listado 3.  AppDelegate.cs

 

Notemos que en los proyectos SG.Droid y SG.iOS se tiene la instrucción:

 Xamarin.Forms.Forms.Init(this, bundle);

Este código inicializa los componentes necesarios para que todo esto funcione.

Si quisiéramos hacer una forma de captura, por ejemplo un login con usuario/contraseña, incluiríamos un código similar al del listado 4 en nuestro proyecto portable, sin necesidad de tener que mover un dedo sobre el código de iOS  y Android. La figura 3 muestra cómo se despliega esta forma tanto en iOS como en Android. Nótese que en cada caso se aplica automáticamente el estilo default de la plataforma correspondiente.

Listado 4. Forma de login.

Figura 3. Ejemplo de pantallas de login.

Inyección de dependencia

Un punto importante es que aún en el proyecto Portable podemos especificar un comportamiento diferente para cada plataforma utilizando la directriz #ifdef, por ejemplo  #ifdef __ANDROID__ significa que el siguiente código será válido sólo para Android desde el momento de la compilación.

Una segunda  forma es utilizar la clase Device y TargetPlatform, como se muestra en el listado 5.

Listado 5. Consultar plataforma.

Una tercera forma es utilizar inyección de dependencias. La forma de lograr esto es que en el proyecto portable definimos las interfaces de nuestras clases, y éstas se implementarán en cada plataforma (iOS y Android para nuestro caso), utilizando DependencyService de Xamarin para instanciar las implementaciones o si se requiere algo mucho más robusto podemos utilizar Unity , TinyIOC,  Autofac entre otras que se pueden obtener desde Nuget.

Las principales clases candidatas a ser implementadas por medio de inyección de dependencias son las que utilizarán recursos propiamente de la plataforma como: acceder a la ruta de la aplicación en el dispositivo móvil para almacenar un archivo, acceso a los recursos de redes, preferencias,  creación y acceso a una base de datos de SQLite, preferencias de la aplicación en el dispositivo, personalizar un control como un botón, un grid, procesamiento de una imagen, etcétera.

DependencyService es el medio por el cual podemos resolver las interfaces cuya implementación se encuentra en cada plataforma. Al utilizar:

[assembly:Dependency(typeof( Clase))]

estamos indicando a .Net que esa clase podrá resolverse mediante DependencyService tomando la implementación en la plataforma en ejecución.

A continuación mostraré un ejemplo para realizar la funcionalidad de localización de recursos para soportar multilenguaje.

Primero, en el proyecto portable declaramos un interfaz llamado ILocalizeService. El listado 6 muestra el código.

Listado 6. Definición de interfaz.

Lo que sigue es codificar la implementación puntual de esta funcionalidad en cada plataforma. El listado 7 contiene la implementación para Android, y el listado 8 la implementación para iOS.

 

Listado 7. Servicio de localización en Android.

Teniendo estas implementaciones, basta con poner desde nuestro código portable algo como:

var language = DependencyService.Get<ILocale>().GetCurrent();

Personalización de controles

Otro tema muy importante en Xamarin.Form es que es posible personalizar los controles UI específicos para cada plataforma utilizando Custom Renderers. Esto se realiza mediante la directriz ExportRenderer. A continuación veremos un ejemplo donde personalizamos un control para cada plataforma.

En nuestro proyecto portable definimos un CustomEntry de la siguiente forma:

public class CustomEntry: Entry { }

Posteriormente, implementamos la personalización de dicho control en Android e iOS. El listado 9 tiene la personalización para Android, y el 10 para iOS.

Listado 9. CustomEntryRenderer en Android.

Listado 10. CustomEntryRenderer en iOS.

Analizando el código, podemos darnos cuenta que existen diferencias irreconciliables entre plataformas por la forma en que procesan sus datos y la arquitectura, por lo que es necesario que en funcionalidades como estas desarrollemos el código específico para la plataforma.

Estilos

Podemos definir estilos que determinen los aspectos visuales de nuestra interfaz de usuario tales como colores, tipografías, tamaños, etcétera; de tal manera que no estemos redefiniendo dichos estilos en cada pantalla. Para lo cual creamos una clase donde definimos los estilos y de ahí los vamos colocando según se requiera.

El listado 11 muestra el código de un programa AppStyles.cs que define un estilo para objetos Label. Este código es independiente de la plataforma así que sólo se fija una vez en nuestro proyecto portable.

Listado 11. Definición de estilos.

Entonces cuando creamos un objeto Label, podemos establecer su estilo de la siguiente forma:

var nameLabel = new Label () {
 Text = "Name",
 Style = AppStyles.LabelStyle
};

 

Conclusión

En este artículo hemos visto cómo por medio de Xamarin.Forms podemos construir aplicaciones móviles que reutilicen elementos de código común para generar aplicaciones nativas para cada plataforma, y también hemos visto algunas formas en que podemos ajustar el comportamiento y estilo de cada plataforma.—

El código generado durante este tutorial está disponible como un repositorio en: https://github.com/pacificIT/SG.Xamarin

Bio

Alder López es ingeniero de software e investigador en la empresa Advanced Technology Research. Se especializa en el desarrollo de aplicaciones móviles. https://mx.linkedin.com/in/alder1sismty