Librerías Portables: Comparte código entre múltiples plataformas
Cuando desarrollamos una aplicación que queremos que funcione en varias plataformas como son Windows, Windows Phone, Android e iOS (estas dos últimas gracias a Xamarin), tenemos en las Librerías Portables (Portable Class Libraries o PCLs) un aliado de excepción.
Estas librerías nos garantizan que todo el código que contienen funcionará en todas las plataformas que elijamos de entre las que tenemos disponibles, y nos ayudarán a maximizar la cantidad de código que podemos compartir entre ellas.
Plataformas Soportadas
En el artículo Cross-Platform Development with the Portable Class Library puedes ver las plataformas disponibles actualmente en las últimas versiones de Visual Studio, a las que habría que añadir Xamarin.Android y Xamarin.iOS si tienes Xamarin instalado. Y estas son las que vienen seleccionadas por defecto al crear un nuevo proyecto de tipo Class Library (Portable) ya sea en C# o en Visual Basic con Visual Studio 2013 ó 2015:
Con esta configuración puedo crear una librería que después podré utilizar por ejemplo en una aplicación de escritorio de Windows hecha con WPF, en una app Universal para Windows 8.1 y Windows Phone 8.1, y en una app de Android e iOS.
Una vez creada una de estas librerías, podrás cambiar las plataformas soportadas en cualquier momento.
Funcionalidades Soportadas
Con la configuración por defecto mostrada anteriormente para los proyectos de tipo Class Library (Portable) podremos aprovecharnos de toda la potencia del Framework de .NET y de sus lenguajes incluso cuando trabajamos con Android e IOS. Podremos usar por ejemplo asincronía, LinQ, los tipos anónimos, los genéricos, las colecciones, las Expresiones Lambda y las Expresiones de LinQ de C#, etc.
Todo el código que pongamos en la librería deberá de poder ser utilizado en todas las plataformas, si no directamente no compilará. Un truco: si IntelliSense te muestra la propiedad o método que quieres utilizar, es que está soportado en la librería para todas las plataformas elegidas.
En el artículo Cross-Platform Development with the Portable Class Library puedes ver una tabla que te indica qué funcionalidades del Framework puedes utilizar en función de las plataformas seleccionadas. También podrás ver otras consideraciones sobre los tipos y miembros soportados en este tipo de librerías, en especial cuando trabajamos con plataformas más antiguas como p.ej. .NET Framework 4.
Trabajando con MVVM
Cuando creamos aplicaciones con WPF, o apps para Windows 8/8.1 ó Windows Phone 8/8.1, lo más habitual es que estemos utilizando el Patrón Model-View-View Model (MVVM):
En general el código que podemos poner en las Librerías Portables es independiente de plataforma, es decir, que con las plataformas seleccionadas por defecto no podremos llamar a APIs del sistema (p.ej. no hay APIs comunes entre WinRT y Android), o incluir código del interfaz de usuario (p.ej. no es igual el XAML de las apps Universales al XAML de WPF o al XML de Android). Por tanto estas librerías serán perfectas para incluir todo el código de nuestros vista-modelo y nuestros modelos, y después en los proyectos particulares de cada plataforma que usen la librería crearemos las vistas personalizadas para cada una de ellas. Y todo esto es posible gracias a que clases como System.Collections.ObjectModel.ObservableCollection<T> e interfaces como System.ComponentModel.INotifyPropertyChanged utilizados con MVVM están soportados en este tipo de librerías. ¡Podremos reutilizar toda la lógica de negocio de nuestra app en todas las plataformas!
Ahora, si sólo seleccionásemos las plataformas de Windows 8.1 y Windows Phone 8.1, podríamos también incluir el código de las vistas e incluso su XAML, así como llamadas a APIs de WinRT (¡esta es la magia de las Apps Universales!). Y si utilizamos Xamarin.Forms para crear apps para Android, iOS y Windows Phone 8, también podremos incluir código y XAML del interfaz de usuario en la Librería Portable. ¡Podremos reutilizar mucho más que nuestra lógica de negocio!
Puedes encontrar más información aquí: Using Portable Class Library with Model-View-View Model y Cross-Platform Development with the Portable Class Library.
Abstrayéndonos de la plataforma
Como ya hemos visto, las Librerías Portables nos abstraen de la plataforma con la que trabajamos. Ahora, en algunas ocasiones el código de estas librerías tiene que poder llamar a código dependiente de la plataforma. Por ejemplo, nuestro vista-modelo podría necesitar llamar a alguna API del sistema. Si las plataformas que hemos elegido nos impiden hacer estas llamadas directamente en la Librería Portable, por fortuna tenemos varios mecanismos que podemos utilizar.
Por ejemplo el artículo Platform Abstraction with the Portable Class Library nos propone una manera de hacerlo mediante clases abstractas.
Ahora, la solución más extendida es utilizar Inversión de Control (Inversion of Control o IoC) e Inyección de Dependencias (Dependency Injection o DI). Inversión de Control significa que un objeto no crea otros objetos de los que depende para hacer su trabajo. En su lugar, obtiene los objetos que necesita de una fuente externa. E Inyección de Dependencias significa que esto se consigue sin intervención del objeto en sí, usualmente gracias a un componente de un Framework que pasa las dependencias al objeto por su constructor o cambiando sus propiedades. Este gran artículo explica todo esto en detalle (sus ejemplos son en Java pero todos los principios aplican a .NET): Inversion of Control Containers and the Dependency Injection pattern.
Más abajo podrás encontrar ejemplos prácticos de todo esto.
Tipos Especiales de Librerías Portables
En Visual Studio 2013 y 2015 podrás encontrar otros tipos de proyectos además del ya mencionado Class Library (Portable) que te permitirán crear tipos especiales de Librerías Portables:
- Class Library (Portable for Universal Apps) : Se trata de una Librería Portable estándar que tiene como plataformas soportadas por defecto Windows 8.1 y Windows Phone 8.1 e incluye una referencia a la librería de Windows. En ellas podremos incluir código del interfaz de usuario y XAML de Windows, así como llamadas a APIs de Windows. Dejaremos de poder hacerlo si añadimos más plataformas.
- Class Library (Xamarin.Forms Portable) : Se trata de una Librería Portable estándar que soporta por defecto las mismas plataformas que el proyecto Class Library (Portable) menos Windows Phone 8.1, ya que Xamarin Forms todavía no soporta la creación de apps de Windows Phone 8.1, sólo de Windows Phone 8. Además referencia a las librerías Xamarin.Forms.Core y Xamarin.Forms.Xaml, lo que nos permite incluir en ella código del interfaz de usuario y XAML de Xamarin Forms (que no es igual al XAML de Windows).
- Windows Runtime Component (Portable for Universal Apps) : Se trata de una Librería Portable que tiene como únicas plataformas soportadas Windows 8.1 y Windows Phone 8.1, pero que no se compila como una librería de clases, si no como un Componente de Windows Runtime (WinRT). Podrá usarse en apps de Windows 8.1 y Windows Phone 8.1 independientemente del lenguaje utilizado para crearlas: C#, VB.NET, JavaScript o C++.
Y si en lugar de usar C# o VB.NET quisiéramos usar F#, las opciones se reducen a las siguientes combinaciones de plataformas de Microsoft:
Librerías que puedo referenciar
Una Librería Portable puede referenciar cualquier otra Librería Portable que soporte como mínimo las plataformas soportadas por ella. Por ejemplo, una librería que soporte estas plataformas:
podrá referenciar otra que soporte estas plataformas:
Por suerte para nosotros hay muchas librerías de uso común que podremos utilizar en nuestras propias Librerías Portables, permitiéndonos maximizar la cantidad de código que podemos reutilizar y compartir. A continuación tienes algunos ejemplos de paquetes NuGet con librerías que funcionan con todas las plataformas que vienen por defecto en el proyecto Class Library (Portable) de Visual Studio 2013/2015:
De Microsoft
- Microsoft HTTP Client Libraries (Microsoft.Net.Http) para realizar peticiones HTTP.
- Microsoft Compression (Microsoft.Bcl.Compression) para trabajar con archivos ZIP.
- Microsoft Composition (Microsoft.Composition) para trabajar con el Managed Extensibility Framework (MEF).
- Microsoft Immutable Collections (Microsoft.Bcl.Immutable) para trabajar con colecciones inmutables.
- ODataLib for ODATA v1-3 (Microsoft.Data.OData) para trabajar con OData.
- Reactive Extensions - Main Library (Rx-Main) para trabajar con Reactive Extensions.
- Unity Application Block (Unity) para inyección de dependencias.
- Windows Azure Mobile Services (WindowsAzure.MobileServices) para trabajar con Microsoft Azure Mobile Services.
- Live SDK (LiveSDK) para acceder a OneDrive y Outlook.com.
De terceros
- SQLite.Net PCL (SQLite.Net-PCL) y SQLite.Net.Async PCL (SQLite.Net.Async-PCL) para trabajar con SQLite.
- AutoMapper para convertir objetos de un tipo a otro.
- Json.NET (Newtonsoft.Json) para trabajar con JSON.
- MVVM Light (GalaSoft.MvvmLight), un conjunto de utilidades para trabajar con MVVM. Incluye inyección de dependencias (SimpleIoc), implementaciones de ICommand (RelayCommand) e INotifyPropertyChanged (ObservableObject), envío de mensajes entre diferentes partes de nuestra app (Messenger), etc.
- MvvmCross, un Framework MVVM con el que podremos p.ej. utilizar databindings con los XML de Android y los XIBs de iOS cuando trabajemos con Xamarin.
- Reactiveui, un Framework MVVM basado en Reactive Extensions.
- Ninject for Portable Class Libraries (Portable.Ninject) para inyección de dependencias.
- Autofac para inyección de dependencias.
- Akavache para almacenamiento persistente de pares clave-valor.
- Splat para trabajar con imágenes y colores.
- MetroLog Lightweight Logging for Portable and WinJS (MetroLog), un Framework de logging.
- Bouncy Castle PCL (Portable.BouncyCastle), una API criptográfica.
Puedes encontrar más Librerías Portables aquí:
- PCL and .NET NuGet Libraries are now enabled for Xamarin
- Cross-Platform Portable Class Libraries with .NET are Happening.
- Top 20 NuGet packages for portable
Nota: algunas de ellas podrían no soportar todas las plataformas que necesites.
Por otro lado la gente de Xamarin también ha creado un proyecto open source llamado Xamarin Forms Labs que puede interesarte si trabajas con Xamarin.Forms, e incluye numerosos paquetes NuGet con librerías que puedes utilizar para trabajar con inyección de dependencias (Xamarin Forms Labs IoC Ninject), con SQLite (Xamarin Forms Labs - Caching), con JSON (Xamarin Forms Labs Serialization Json.Net), con criptografía (Xamarin Forms Labs Cryptography), etc.
Ejemplos
Además de los enlaces que puedes encontrar en este artículo, te recomiendo que le eches un vistazo a este ejemplo que hicimos hace poco para nuestros #retosMSDN: Creando una aplicación para resolver Sudokus con Visual Studio. Este ejemplo muestra cómo usar Librerías Portables para hacer apps Universales, y qué tipo de código podemos incluir en ellas: partes de MVVM, conexión a APIs REST, procesamiento de Json, etc. También muestra cómo puedes llamar a código dependiente de la plataforma desde la Librería Portable.
También puede serte de utilidad el webcast que hicimos sobre desarrollo móvil multi-plataforma con Xamarin como parte de nuestras Christmas Mobile Apps Sessions donde puedes ver, entre otras cosas, cómo utilizar las Librerías Portables para crear apps Universales y apps para Android e iOS con Xamarin y Xamarin.Forms, todo siguiendo el patrón MVVM y compartiendo todo el código posible.
Un saludo,
Alejandro Campos Magencio (@alejacma)
Technical Evangelist
PD: Mantente informado de todas las novedades de Microsoft para los desarrolladores españoles a través del Twitter de MSDN, el Facebook de MSDN, el Blog de MSDN y la Newsletter MSDN Flash.
Comments
- Anonymous
October 02, 2016
Me encanto