[Universal App] Roaming Settings, compartiendo datos entre plataformas

SynchronizeIntroducción

Algo muy habitual en cualquier tipo de aplicación móvil es trabajar con distntos tipos de datos, datos locales de la aplicación, archivos de configuración, etc. Segun el tipo de dato debemos proporcionar un tratamiento diferente pero siempre buscando facilitar el uso de la aplicación por parte del usuario.

Ante un mundo lleno de múltiples dispositivos para distintas situaciones (PCs, Tablets, móviles, Bands, etc.) es cada vez más habitual que un mismo usuario se instale la misma aplicación en diferentes dispositivos. Ante este tipo de situación el usuario espera que los datos básicos y de configuración se mantengan sincronizados y no tener que establecer su configuración básica una y otra vez.

¿Cómo lo conseguimos?

Almacenamiento de datos de aplicación

Tanto en aplicaciones Silverlight 8.1 como en aplicaciones Windows XAML tenemos disponible las siguientes carpetas:

  • LocalFolder: Un viejo conocido. Ya lo teníamos disponible en Windows Phone 8 e incluso era la carpeta usada como Isolated Storage desde Windows Phone 7. Guardaremos información que persiste entre actualizaciones de la aplicación y entra dentro de los datos guardados al realizar un backup del sistema.
  • RoamingFolder: Almacenamiento muy útil. Al guardar datos en RoamingData, la información estará disponible en todos los dispositivos donde la aplicación este instalada (con el mismo id). Ideal para guardar la configuración de la aplicación y mantenerla sincronizada entre la aplicación Windows Phone y la Windows Store por ejemplo.
  • TemporaryFolder: Aqui guardaremos información sin tener la necesidad de borrarla más tarde. La información se guardará entre las distintas sesiones pero cuando el sistema requiera espacio (Ejemplo: poca memoria disponible), eliminará la información.  Es un lugar idóneo donde guardar datos obtenidos de peticiones web, servicios o imágenes por ejemplo.

Roaming Data

Si un usuario obtiene la aplicación en múltiples dispositivos, Windows y Windows Phone, es fantástico para el que la configuración de la misma se comparta. De modo que, cualquier cambio realizado en la configuración de la Aplicación uno de los dispositivos se vea reflejado en el otro. Esto lo podemos conseguir utilizando Roaming Data entre aplicaciones Windows Phone 8.1 y Windows 8.1 que compartan el mismo PFN (Package Family Name).

El Roaming de datos nos proporciona una forma de compartir y sincronizar datos entre distintos dispositivos físicos de manera sencilla.

NOTA: Si publicamos dos versiones de la misma aplicación (una para la Windows Store y otra para la Windows Phone Store) podemos compartir configuración e información utilizando el mismo PFN en cada aplicación.

Roaming Data

Roaming Data

Utilizaremos diccionarios (clave / valor) que automáticamente se almacenarán en el OneDrive del usuario. El tamaño máximo de los datos Roaming viene establecido en la propiedad ApplicationData.RoamingStorageQuota (normalmente 100KB).

NOTA: Los datos de Roaming no afecta al tamaño de almacenamiento del usuario.

Manos a la obra

Comenzamos creando un nuevo proyecto:

Nueva Aplicación Universal

Nueva Aplicación Universal

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo en este ejemplo sera simular una opción de configuración sencilla, como por ejemplo, el color básico utilizado en la aplicación y utilizar datos Roaming para mantener el color seleccionado por el usuario sincronizado entre las aplicaciones Windows y Windows Phone.

Vamos a tener una configuración de colores por lo tanto empezaremos definiendo… el color. En nuestra carpeta Models crearemos la siguiente clase:

public class Accent
{
     public string Name { get; set; }

     public string Hex { get; set; }
}

Nos permite definir el nombre y valor hexadecimal de cada color. A continuación, en nuestra viewmodel tendremos una colección de colores:

private Accent _current;
private ObservableCollection<Accent> _accents;

public ObservableCollection<Accent> Accents
{
     get { return _accents; }
     set { _accents = value; }
}

public Accent Current
{
     get { return _current; }
     set
     {
          _current = value;
          RaisePropertyChanged("Current");
     }
}

Al entrar en la vista, utilizaremos un método para obtener el listado de colores disponibles:

_accents = new ObservableCollection<Accent>
{
     new Accent { Name = "Blue", Hex= "#1BA1E2" },
     new Accent { Name = "Brown", Hex= "#A05000" },
     new Accent { Name = "Green", Hex= "#339933" },
     new Accent { Name = "Pink", Hex= "#E671B8" },
     new Accent { Name = "Purple", Hex= "#A200FF" },
     new Accent { Name = "Red", Hex= "#E51400" },
     new Accent { Name = "Teal", Hex= "#00ABA9" },
     new Accent { Name = "Lime", Hex= "#A2C139 " },
     new Accent { Name = "Magenta", Hex= "#D80073 " }
};

Todo preparado para poder definir la interfaz:

<ListView
     Grid.Row="1"
     ItemsSource="{Binding Accents}"
     SelectedItem="{Binding Current, Mode=TwoWay}">
     <ListView.ItemsPanel>
         <ItemsPanelTemplate>
             <WrapGrid MaximumRowsOrColumns="3" />
         </ItemsPanelTemplate>
     </ListView.ItemsPanel>
     <ListView.ItemTemplate>
         <DataTemplate>
             <Grid Background="{Binding Hex}"
                   Height="100"
                   Width="100"
                   Margin="5">
                 <TextBlock Text="{Binding Name}"
                            VerticalAlignment="Bottom"/>
             </Grid>
         </DataTemplate>
     </ListView.ItemTemplate>
</ListView>

Hasta aqui nuestro ejemplo básico. Un listado de colores que el usuario seleccionará àra utilizar como color principal en la aplicación. Utilizamos datos Roaming para guardar el color seleccionado. Para ello, comenzamos…

Asociando la aplicación con la Store

Para que la infraestructura de datos Roaming funcione (datos en OneDrive), debemos asociar la aplicación con la tienda.

NOTA: No es necesario publicar la aplicación para realizar pruebas.

Para asociar la aplicación con la tienda haremos clic derecho sobre la misma y elegiremos la opción “Associate App with the Store…”:

Reservar un nombre de App

Reservar un nombre de App

Nos aparecerá una ventana modal como la siguiente:

Asociar la App con la Store

Asociar la App con la Store

Registraremos un nombre de Aplicación:

Nombre de la App

Nombre de la App

Al finalizar el proceso, nuestra aplicación quedará asociada a la tienda y tendremos un resumen de todos los valores correctos a utilizar en el archivo de manifiesto:

Resumen

Resumen

Una vez realizado el proceso en la aplicación Windows Store o Windows Phone, debemos repetir lo mismo en la otra seleccionando el nombre reservado previamente. Antes de continuar sería oportuno revisar el archivo de manifiesto de cada aplicación para asegurar que el PFN (Package Family Name) es el mismo.

Misma cuenta Microsoft en Windows/Phone

Para que la sincronización de datos funcione correctamente, ambos dispositivos deben utilizar la misma cuenta Microsoft. Esto que es sencillo, en el punto final es fácil de cumplir pero quizas no tanto en el desarrollo. En la máquina de desarrollo tendremos una cuenta Microsoft establecida pero probablemente no en el emulador de Windows Phone. Recuerda utilizar la misma cuenta en el emulador para garantizar que todo funcione o utiliza un dispositivo físico.

Usando Roaming Settings

Llegamos a la parte central del artículo, el uso de Roaming. Para utilizar Roaming en nuestro ejemplo vamos a crear un servicio llamado RoamingSettingsService con la siguiente definición:

/// <summary>
/// Almacenar y recuperar configuraciones y archivos desde el almacén de datos móviles de aplicaciones.
/// </summary>
public interface IRoamingSettingsService
{
     void SaveData(string key, string value);

     void SaveData(string container, string key, string value);

     void SaveData(string key, ApplicationDataCompositeValue value);

     bool ContainsKey(string key);

     object GetData(string key);

     object GetData(string container, string key);

     ApplicationDataCompositeValue GetDataComposite(string key);

     void RemoveData(string key);

     ApplicationDataContainer CreateContainer(string container);

     void RemoveContainer(string container);
}

Ahora nos centramos en la definición del servicio. Comenzamos creando una propiedad RoamingSettings que accederá a la propiedad ApplicationData.RoamingSettings para obtener la configuración.

/// <summary>
///  Almacenar y recuperar configuraciones y archivos desde el almacén de datos móviles de aplicaciones.
///
/// Más info: http://msdn.microsoft.com/es-es/library/windows/apps/xaml/hh700362.aspx
/// </summary>
public class RoamingSettingsService : IRoamingSettingsService
{
     internal ApplicationDataContainer RoamingSettings
     {
         get { return ApplicationData.Current.RoamingSettings; }
     }
}

Definimos el método que nos permitirá guardar datos Roaming. Ya comentamos previamente que trabajaremos con diccionarios con clave y valor. El método para guardar datos recibirá la clave y el valor a almacenar:

/// <summary>
/// Escribir datos en una configuración.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void SaveData(string key, string value)
{
     RoamingSettings.Values[key] = value;
}

NOTA: Podríamos pasar un tercer parámetro para indicar la prioridad utilizando la propiedad HighPriority pero solo tendría efecto en la aplicación Windows Store.

Antes de almacenar un valor nos puede interesar verficar si ya existe un valor almacenado con la clave otorgada. Definiremos un sencillo método que nos haga esta verificación:

/// <summary>
/// Verifica si existe algun dato relacionado con la clave facilitada.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool ContainsKey(string key)
{
     return RoamingSettings.Values.ContainsKey(key);
}

Una vez guardado datos desearemos recuperarlos posteriormente… creamos el método que nos permite recuperar el valor de una clave otorgada:

/// <summary>
/// Leer datos desde una configuración.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object GetData(string key)
{
     return RoamingSettings.Values[key];
}

Utilizamos la propiedad ApplicationDataContainer.Values para acceder al valor almacenado con la clave dada.

Para eliminar una configuración, utilizaremos el método ApplicationDataContainerSettings.Remove:

/// <summary>
/// Eliminar configuraciones.
/// </summary>
/// <param name="key"></param>
public void RemoveData(string key)
{
     RoamingSettings.Values.Remove(key);
}

Utilizando el servicio en nuestra viewmodel, al cargar el color seleccionado verificaremos si esta ya guardado como una configuración almacenada en Roaming y en caso afirmativo, recuperaremos el valor. En caso de no existir, seleccionamos el primer color del listado:

if (_roamingSettingsService.ContainsKey(Key))
{
     var hex = _roamingSettingsService.GetData(Key).ToString();
     Current = Accents.First(c => c.Hex.Equals(hex));
}
else
     Current = Accents.First();

Cada vez que el usuario cambie de color, guardaremos el mismo:

public Accent Current
{
     get { return _current; }
     set
     {
          _current = value;
          _roamingSettingsService.SaveData(Key, _current.Hex);

          RaisePropertyChanged("Current");
     }
}
Configuración de color de la App

Configuración de color de la App

Recibiendo la notificación de cambio en los datos

El evento DataChanged se lanzará cada vez que los datos Roaming cambien siempre y cuando la aplicación este activa en el momento del cambio.

Debemos suscribirnos al evento:

ApplicationData.Current.DataChanged -=
                new TypedEventHandler<ApplicationData, object>(DataChangeHandler);

Hemos establecido DataChangeHandler como el controlador para cambios de datos móviles:

void DataChangeHandler(ApplicationData appData, object args)
{

}

Podéis descargar el ejemplo realizado a continuación:

Más opciones utilizando Roaming Data

Hasta este punto hemos visto todo lo necesario para utilizar datos en Roaming de manera simple, tal y como hemos usado en nuestro ejemplo. Sin embargo, tenemos muchas otras opciones disponibles. Si recordáis la definición de nuestro servicio veréis muchos otros métodos que no hemos usado hasta ahora. Vamos a revisarlos uno a uno.

Utilizamos el método ApplicationDataContainer.CreateContainer para crear un contenedor de configuraciones:

/// <summary>
/// Crea o abre el contenedor de configuración especificado.
/// </summary>
/// <param name="container"></param>
/// <returns></returns>
public ApplicationDataContainer CreateContainer(string container)
{
     return RoamingSettings.CreateContainer(container, ApplicationDataCreateDisposition.Always);
}

Utilizamos el método ApplicationDataContainer.DeleteContainer para eliminar el contenedor de configuraciones:

/// <summary>
/// Elimina el contenedor de configuración especificado.
/// </summary>
/// <param name="container"></param>
public void RemoveContainer(string container)
{
     RoamingSettings.DeleteContainer(container);
} 

Guardamos el valor value para acceder a la configuración dada por el parámetro key del contenedor container:

/// <summary>
/// Escribir datos en una configuración.
/// </summary>
/// <param name="container"></param>
/// <param name="key"></param>
/// <param name="value"></param>
public void SaveData(string container, string key, string value)
{
     RoamingSettings.Containers[container].Values[key] = value;
}

Usamos la propiedad ApplicationDataContainer.Values para acceder a la configuración dada por el parámetro key del contenedor container:

/// <summary>
/// Leer datos desde una configuración de un contenedor de configuración especificado.
/// </summary>
/// <param name="container"></param>
/// <param name="key"></param>
/// <returns></returns>
public object GetData(string container, string key)
{
     return RoamingSettings.Containers[container].Values[key];
}

Podemos guardar settings utilizando un objeto ApplicationDataCompositeValue que contiene un conjunto de  configuraciones:

/// <summary>
/// Escribir datos en una configuración.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void SaveData(string key, ApplicationDataCompositeValue value)
{
     RoamingSettings.Values[key] = value;
}

Consejos al usar Roaming Data

A la hora de utilizar Roaming Data es aconsejable que tengas en cuenta:

  • La sincronización de los datos se realiza en background.
  • Utilizar datos en Roaming es ideal para poca cantidad de información como por ejemplo la configuración de la aplicación, o pequeños volúmenes de datos relacionados con actividad reciente. Sin embargo, NO se debe utilizar Roaming para grandes cantidades de información.
  • La propiedad HighPriority para forzar una sincronización rápida solo esta disponible en Windows, no tiene efecto en Windows Phone.
  • A la hora de depurar aplicaciones que hagan uso de Roaming, si hay problemas en la sincronización, asegúrate que ambos dispositivos usan la misma cuenta Microsoft, que en el archivo de manifiesto tenemos el mismo PFN y la misma versión.

Más información

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s