@lvbernal

Desarrollo // Telecomunicaciones // Colombia

2018/05/26

Xamarin - Lecciones aprendidas 4

Esta es la cuarta parte de las lecciones aprendidas con Xamarin. Espero que puedan tomar algo útil de esta serie de contenidos.

A veces es útil el “uso desmedido” de los Converters:

Los Converters son componentes que permiten establecer una propiedad de un elemento xaml, a partir de un valor que podría no ser del mismo tipo que el requerido por la propiedad. Yo los uso para poner logos (Image) dependiendo del tipo de item (int/string), colores de fondo (Color) dependiendo de si el elemento está seleccionado o no (bool), etc.

Hace unos días tuve que hacer una app a contrarreloj: una calculadora de tasas de espectro, que sirve para definir el valor del espectro radioeléctrico dependiendo de ciertas variables de uso y de los servicios que se van a prestar, basado en el documento de UIT-D “Guidelines for the review of spectrum pricing methodologies and the preparation of spectrum fee schedules”.

Lo importante era velocidad (10 días), pero la app debía tener cierta interacción porque las variables para el cálculo dependen del servicio… velocidad + interacciones = código spaghetti. Entonces decidí, en lugar de usar muchas condicionales, usar muchos Converters.

El código de la Page se ve así:

https://github.com/i2tResearch/SpectrumFees/blob/master/SpectrumFees/Pages/SpectrumFeesPage.xaml

Pero el ViewModel quedó muy simple:

https://github.com/i2tResearch/SpectrumFees/blob/master/SpectrumFees/ViewModels/MainViewModel.cs

Cambiar la versión del assembly antes de (intentar) publicar:

Todas las aplicaciones Android tienen un archivo AndroidManifest.xml que contiene las propiedades de la aplicación, incluyendo versionCode (version number en Visual Studio) y versionName (version name en Visual Studio). El primero es un número secuencial interno que determina si una versión es más reciente que otra. Y el segundo es el número que se le muestra al usuario final (ej. 1.1.4).

Eso debe ser conocido por todos los desarrolladores Android. Lo importante es que en Xamarin también tenemos el archivo AssemblyInfo.cs, cuya propiedad AssemblyVersion debe coincidir con versionName.

[assembly: AssemblyVersion("1.1.4")]

Si los valores no coinciden, la aplicación no se puede publicar.

2018/03/07

Xamarin - Lecciones aprendidas 3

Esta es la tercera parte de las lecciones aprendidas con Xamarin. Aquí están la primera y la segunda.

Quiero insistir, especialmente en este post, que no quiero hablar de "buenas prácticas" sino de cosas que me han ayudado a solucionar situaciones específicas. Esta vez son los códigos QR como opción para "iniciar sesión" en las apps.

Autorización usando QR.

Algunas apps tienen un portal para mostrar reportes, modificar parámetros, registrar usuarios, etc. que ya está protegido por contraseña. Ese portal se puede aprovechar para mostrar un código QR que contiene el token de autorización para consumir servicios web. Es como "implementar la segunda parte de OAuth2" (aquí está bien explicado todo el protocolo OAuth2). Esto fue lo que hice:


Genero el código siguiendo la documentación de asp.net core sobre Hash Codes y me aseguro que sólo el usuario autorizado pueda verlo, usando Authorization Handlers. Tiene nombre de la app, el id del recurso y el token de autorización. Del lado del servidor, almaceno el token y valido cada solicitud del API.

Por ejemplo, si suponemos que el usuario tiene un único ítem y que el token es una propiedad del ítem y no del usuario, el código quedaría así:

[HttpGet]
public async Task<IActionResult> Get(int id)
{
    var appCode = Request.Headers["<SomeHeaderName>"].ToString();
    var (isAuthorized, item) = await CodeIsValid(appCode, id);
    if (!isAuthorized)
    {
        return BadRequest();  // Puede ser Unauthorized();
    }

    return Ok(item);
}

...

protected async Task<(bool, Item)> CodeIsValid(string appCode, int itemId)
{
    var item = await Context.Item.SingleOrDefaultAsync(

        i => i.Id == itemId &&
        i.AppCode == appCode);
    return (item != null, item);
}



Dependiendo de la aplicación, el token puede ser una propiedad del usuario, del perfil, de un ítem de más bajo nivel, etc. Se puede generar usando el Id del usuario, el SecurityStamp o un GUID aleatorio. Se debe regenerar cada vez que el usuario desee o cuando cambie la contraseña. Y se deben desconectar todas las aplicaciones que no tengan un código válido.

Del lado del cliente uso ZXing.Net.Mobile.Forms para escanear el QR y Xam.Plugins.Settings para almacenar el token.

2018/02/01

Xamarin - Lecciones aprendidas 2

Esta es la segunda parte de las lecciones aprendidas con Xamarin. Aquí está la primera parte.

API Keys, URLs y otras variables importantes:

Las API Keys, App URLs, Client IDs, etc. se deben manejar con mucho cuidado, especialmente para no publicarlas en repositorios de git, svn o tfs. Ese error es todo un dolor de cabeza.

Todavía estoy buscando la forma de utilizar variables de entorno en proyectos Xamarin desde Visual Studio for Mac. La idea es definir variables por consola (ej. export MY_AZURE_URL=https://myazureurl.azurewebsites.net) y luego usarlas en la aplicación (ej. var myAzureUrl = Environment.GetEnvironmentVariable("MY_AZURE_URL");), como en cualquier framework web decente.

En Xamarin es distinto porque Environment.GetEnvironmentVariable() lee variables locales, en este caso del teléfono, en lugar de cargarlas durante la compilación. Y Visual Studio for Mac todavía no tiene funciones "tan avanzadas".

Por ahora hago lo siguiente:
  1. Creo una clase estática como DemoApp.Infrastructure.AzureConfig para poner las variables, inicialmente con valores falsos.
  2. Subo el archivo al VCS (git en este caso).
  3. Ignoro todos los cambios futuros usando el comando git update-index --skip-worktree AzureConfig.cs. Aquí está la documentación del comando y aquí un ejemplo rápido.
Es importante que esas variables queden en una clase separada que se modifique muy de vez en cuando. Al principio las tenía directamente en el servicio de acceso a datos (ej. DataService.cs), que por supuesto editaba todo el tiempo... eso alcanzó a generarme un par de problemas.