Estrategias de código de portable : #3 Universal Apps | C#

Intermedio

Artículos relacionados

Estrategias de código de portable : #1 PCL - Portable Class Library | C#

Estrategias de código de portable : #2 Código Vinculado | C#

Este es el último artículo de la serie y nos concentraremos en Universal Apps, nuestra tercera estrategia de código portable.

Código fuente de esta serie de artículos

JuanKRuiz GitHub

El código fuente completo de esta seria de artículos se encuentra disponible en GitHub, incluye proyectos de Apps con todos los casos expuestos.

https://github.com/JuanKRuiz/Estrategias-de-Codigo-Portable

Universal Apps es en escencia un concepto que define como un mismo conjunto de API's nos permite compartir código a traves de varios dispositivos diferentes aunque su sistema operativo no sea el mismo.

Pero en que se diferencia esto si lo comparamos con Portable Class Libraries ?

Bien en concepto de Universal Apps va más allá.

Proyecto Compartido

En el artículo anterior revisamos la estratégia de código vinculado, lo cual nos permite fácilmente tener códígo en proyecto y hacerlo visible desde un proyecto aparte.

Esta estrategia evoluciona aún más y ahora Visual Studio nos permite crear una solución de Universal Apps.

Universal Apps Solution

Una vez creada nos damos cuenta que aparecen tres proyectos:

  • Windows 8
  • Windows Phone
  • Proyecto Compartido

Folder compartido - Universal Apps

Los proyectos de Windows Phone y WinRT generan cada unos sus propios ensamblados al compilar y adicionalmente comparten la misma API, profundizaremos en esto más adelante.

El proyecto compartido no genera ningún ensamblado, su utilidad es básicamente compartir código. Tal como lo hacemos con los archivos vinculados podemos asumir que todos los archivos que se encuentran en el proyecto compartido están vinculados con el proyecto de WinRT y el de Windows Phone.

Compartir los archivos y tener la misma API nos abre la posibilidad de escenarios donde incluso se comparta hasta el 100% del código fuente y de los archivos, en otras palabras podemos llegar a hacer 2 Apps con el mismo código sin requerir ninguna modificación adicional.

Las secciones o archivos de código que no son comunes se deben dejar en cada preoyecto al que correspondan.

Universal Apps es 100% compatible con las otras estrategias de código portable que hemos visto:

  • Librerias Portables
    • Patrones de diseño
  • Código vinculado
    • Clases y métodos parciales
    • Compilación condicional

Lenguajes soportados

Universal Apps te permite trabajar Apps con cualquiera de estos lenguajes

* C# / XAML
* HTML / JS
* C++

De arranque esto ya es una diferencia importante, ya que las PCL solo están disponibles para C#.

Compartir archivos de código

Universal Apps nos permite compartir XAML y de paso todos los demás tipos de archivo de acuerdo al tipo de proyecto.

Archivos

  • .cs
  • .js
  • .cpp
  • .h

Markup

  • .xaml
  • .html
  • .config

Recursos

  • .png
  • .jpg
  • .resw
  • .xml
  • etc…

API Universal

Los archivos vínculados desde el folder compartido ofrecen muchas facilidades, sin embargo solo se le puede sacar verdero provecho aumentando al máximo la compatibilidad entre API's, un API Universal nos da hasta un 100% de compatibilidad, aunque en muchos escenarios la compatibilidad efectiva será del 98% apróximadamente.

Porqué?

Porque, por ejemplo hay APIs que solo tienen sentido en Windows Phone por ejemplo:

  • Pivot
  • AutoSuggestBox
  • ContentDialog
  • Maps
  • System Chrome
    • Progress area
    • in-call UI

Algunas otras solo tienen sentido en WinRT

  • SearchBox
  • SettingsFlyout

Nivel de compatibilidad:

Universal Apps Shared API

Universal Apps Shared API

Implementación

Ya con esta información nos ponemos en marcha para hacer nuestro ejemplo.

A continuación veremos la versión más simple de programar este requerimiento en cada una de las plataformas:

Código WinRT

 //LocalSettingsManager.cs
using System.Diagnostics;  
using Windows.Storage;

namespace WinRTApp.Manager  
{
    public class LocalSettingsManager
    {
        public void Set(string key, string value)
        {
            ValidateSecurity();
            ApplicationData.Current.LocalSettings.Values[key] = value;
            Audit();
        }

        public void ValidateSecurity()
        {
            //TODO a lot of things
        }

        public void Audit()
        {
            Debug.WriteLine("Parameter Set on WinRT");
            //TODO a lot of things
        }
    }
}
 //MainPage.xaml.cs [fragment]
private void Page_Loaded(object sender, RoutedEventArgs e)  
{
    var lsm = new LocalSettingsManager();
    lsm.Set("Last start:", DateTime.Now.ToString());
}

Código Windows Phone

 //LocalSettingsManager.cs
using System.Diagnostics;  
using System.IO.IsolatedStorage;

namespace WinPhoneApp.Manager  
{
    public class LocalSettingsManager
    {
        public void Set(string key, string value)
        {
            ValidateSecurity();
            IsolatedStorageSettings.ApplicationSettings[key] = value;
            Audit();
        }

        public void ValidateSecurity()
        {
            //TODO a lot of things
        }

        public void Audit()
        {
            Debug.WriteLine("Parameter Set on WindowsPhone");
            //TODO a lot of things
        }
    }
}
 //MainPage.xaml.cs [fragment]
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)  
{
    var lsm = new LocalSettingsManager();
    lsm.Set("Last start:", DateTime.Now.ToString());
}

Output

 Parameter Set on WinRT  
Parameter Set on WindowsPhone  

Ahora lo convertiremos a Universal Apps, creamos una solución de Universal Apps.

Por defecto el MainPage es creado en cada proyecto

MainPage creado por defecto

Arrastramos uno de los dos hasta el folder compartido, el otro lo borramos.

MainPage en Folder compartido

Ahora en el proyecto compartido creamos la clase LocalSettingsManager de la siguiente forma (Fíjense en la sección con compilación condicional.):

 //LocalSettingsManager.cs
using System.Diagnostics;  
using Windows.Storage;

namespace UniversalApp.Manager  
{
    public partial class LocalSettingsManager
    {
        public void Set(string key, string value)
        {
            ValidateSecurity();
            ApplicationData.Current.LocalSettings.Values[key] = value;
            Audit();
        }

        public void ValidateSecurity()
        {
            //TODO a lot of things
        }

        public void Audit()
        {
#if WINDOWS_APP
            Debug.WriteLine("Parameter Set on WinRT");
#elif WINDOWS_PHONE_APP
            Debug.WriteLine("Parameter Set on Windows Phone");
#endif
            //TODO a lot of things
        }
    }
}

Y modificamos el evento Load del MainPage así

 private void Page_Loaded(object sender, RoutedEventArgs e)  
{
    var lsm = new LocalSettingsManager();
    lsm.Set("Last start:", DateTime.Now.ToString());
}

Eso es todo ahora ejecutamos las Apps y este es el resultado

Output

 Parameter Set on WinRT  
Parameter Set on Windows Phone  

Conclusiones

La estrategia de portabilidad con base en Universal Apps permite crear rápidamente y con baja complejidad técnica código portable.

De cierta forma es una evoluación del modelo de código vinculado y el de PCL, ambos al tiempo.

Es mi alternativa de código portable favorita y se la recomiendo a todos. Actualmente el concepto de Universal Apps también ha sido adoptado por Xamarin para crear Apps con iOS para iPhone y iPad constituyéndose en una de las alternativas de portabilidad más poderosas.