[Windows 10] Password Vault

Introducción

En muchas de las Apps que desarrollamos contamos con opciones relacionadas con la seguridad
donde debemos afrontar problemas como almacenar usuario y contraseña,
encriptar la información, gestionar múltiples dispositivos, etc.

Era un proceso “habitual” pero que requiere tener en cuentas
bastantes aspectos.  En este artículo vamos a ver lo sencillo que lo
tenemos utilizando las APIs Credential Locker disponibles en Windows.Security.Credentials.

NOTA: Estas APIs ya las teníamos disponibles desde Windows 8.1.

El almacén de credenciales

El almacén de credenciales nos permite almacenar y administrar de forma segura
contraseñas de usuarios de una aplicación o servicio específico de modo
que por un lado, los datos almacenados de una aplicación se transfieren
automáticamente a los otros dispositivos de confianza del usuario,
simplificando el proceso de autenticación tanto a los usuarios como a
nosotros, y por otro lado, no es posible desde una aplicación o servicio
acceder a los credenciales asociados con otra aplicación o servicio.

Password Vault

Crearemos un nuevo proyecto UAP:

Nueva App UAP

Nueva App UAP

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 sera muy sencillo. Nuestra aplicación de ejemplo
pedirá fuente, usuario y contraseña permitiéndo con tres sencillos
botones, añadir, recuperar y eliminar credenciales utilizando la API
Credential Locker.

Definiendo la interfaz de usuario

Comenzamos definiendo la interfaz de usuario:

<StackPanel Margin="12">
     <StackPanel
                Margin="0, 12">
                <TextBlock
                    Text="PasswordVault"
                    FontSize="32" />
     </StackPanel>
     <StackPanel Orientation="Vertical">
          <TextBox Header="Source"
                   PlaceholderText="https://facebook.com" />
          <TextBox Header="User"
                   PlaceholderText="user@mail.com" />
          <PasswordBox Header="Password"
                       PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal"
                 HorizontalAlignment="Center"
                 Margin="0, 12">
          <Button Content="Save" />
          <Button Content="Read" Margin="12, 0" />
          <Button Content="Delete" />
     </StackPanel>
     <ScrollViewer>
          <TextBlock />
     </ScrollViewer>
</StackPanel>

Permitimos obtener la información de seguridad requerida y contamos con tres botones de acción. En la viewmodel correspondiente contaremos con propiedades para obtener la información escrita en cada una de las cajas de texto:

// Variables
private string _source;
private string _user;
private string _password;
private string _info;
  
public string Source
{
     get { return _source; }
     set { _source = value; }
}
  
public string User
{
     get { return _user; }
     set { _user = value; }
}
  
public string Password
{
     get { return _password; }
     set { _password = value; }
}
  
public string Info
{
     get { return _info; }
     set
     {
          _info = value;
          RaisePropertyChanged("Info");
     }
}

Y cada botón, ejecutará un comando en la viewmodel:

// Commands
private ICommand _saveCommand;
private ICommand _readCommand;
private ICommand _deleteCommand;
  
public ICommand SaveCommand
{
     get { return _saveCommand = _saveCommand ?? new DelegateCommand(SaveCommandDelegate); }
}
  
public ICommand ReadCommand
{
     get { return _readCommand = _readCommand ?? new DelegateCommand(ReadCommandDelegate); }
}
  
public ICommand DeleteCommand
{
     get { return _deleteCommand = _deleteCommand ?? new DelegateCommand(DeleteCommandDelegate); }
}
  
public void SaveCommandDelegate()
{
  
}
  
public void ReadCommandDelegate()
{
  
}
  
public void DeleteCommandDelegate()
{
  
}

De modo que nuestra interfaz bindeada a las propiedades y comandos correspondientes quedara como podemos ver a continuación:

<StackPanel Margin="12">
     <StackPanel
                Margin="0, 12">
                <TextBlock
                    Text="PasswordVault"
                    FontSize="32" />
     </StackPanel>
     <StackPanel Orientation="Vertical">
          <TextBox Text="{Binding Source, Mode=TwoWay}"
                   Header="Source"
                   PlaceholderText="https://facebook.com" />
          <TextBox Text="{Binding User, Mode=TwoWay}"
                   Header="User"
                   PlaceholderText="user@mail.com" />
          <PasswordBox Password="{Binding Password, Mode=TwoWay}"
                       Header="Password"
                       PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal"
                 HorizontalAlignment="Center"
                 Margin="0, 12">
          <Button Content="Save" Command="{Binding SaveCommand}" />
          <Button Content="Read" Margin="12, 0" Command="{Binding ReadCommand}" />
          <Button Content="Delete" Command="{Binding DeleteCommand}" />
     </StackPanel>
     <ScrollViewer>
          <TextBlock Text="{Binding Info}"/>
     </ScrollViewer>
</StackPanel>

Hasta aqui, la interfaz y estructura básica de nuestro ejemplo.

Nuestra interfaz

Nuestra interfaz

Gestión de credenciales

Para realizar la gestión de credenciales utilizaremos las APIs Credential Locker disponibles en Windows.Security.Credentials. Vamos a crear un servicio con la siguiente definición:

public interface IPasswordVaultService
{
     void Save(string resource, string userName, string password);
  
     PasswordCredential Read(string resource, string userName);
  
     IReadOnlyList<PasswordCredential> GetAll();
  
     void Delete(string resource, string userName);
}

NOTA: El servicio será inyectado por Ioc en nuestra viewmodel.

El servicio contará con cuatro métodos:

  • Save: Nos permitirá guardar credenciales.
  • Read: Nos permitirá recuperar un credencial concreto.
  • GetAll: Recupera todos los credenciales que tengamos almacenados en el Credential Locker.
  • Delete: Eliminará un credencial concreto almacenado previamente.

Nos centramos a continuación en la implementación de cada método. Comenzamos por el método Save:

public void Save(string resource, string userName, string password)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = new PasswordCredential(resource, userName, password);
     vault.Add(cred);
}

Primero, obtenemos una referencia al Credential Locker usando on objeto de tipo PasswordVault definido en el namespace Windows.Security.Credentials. Continuamos creando un objeto de tipo PasswordCredential
que representará el credencial a almacenar con la referencia a nuestra
Aplicación o el tipo de Login utilizado además de los credenciales en
si, usuario y contraseña. Añadiremos el credencial creado al almacén de
credenciales utilizando el método PasswordVault.Add.

Continuamos con el método Read:

public PasswordCredential Read(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
  
     return vault.Retrieve(resource, userName);
}

Contamos con una gran variedad de opciones para recuperar
credenciales del almacén. En el código de la parte superior utilizamos
la forma más simple posible. Contando con el nombre de la App o tipo de
Login además del nombre de usuario, podemos recuperar la información
utilizando el método PasswordVault.Retrieve.

En el método GetAll utilizamos el método PasswordVault.RetrieveAll  para recuperar todos los credenciales almacenados en la Aplicación:

public IReadOnlyList<PasswordCredential> GetAll()
{
     PasswordVault vault = new PasswordVault();
  
     return vault.RetrieveAll();
}

Además de las dos formas utilizadas contamos con otras opciones para recuperar credenciales:

Por último, nos centramos en el método Delete, que como podemos imaginar se encargará de eliminar un credencial en concreto:

public void Delete(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = vault.Retrieve(resource, userName);
     vault.Remove(cred);
}

De nuevo, es un proceso muy sencillo que podemos hacer con pocas
líneas. Accedemos de nuevo al almacén de credenciales mediante un objeto
de tipo PasswordVault y utilizamos el método PasswordVault.Remove  para eliminar el credencial almacenado pasado como parámetro.

Con nuestro servicio para gestionar el almacén de credenciales
preparado, solo nos falta definir la acción de cada comando. Al guardar
el credencial:

public void SaveCommandDelegate()
{
      if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User) || string.IsNullOrEmpty(Password))
      {
          Info += "The Source, the User and the Password are required." + "rn";
          return;
      }
 
      try
      {
          _passwordVaultService.Save(Source, User, Password);
          Info += string.Format("Credentials saved. Resource: {0}, User: {1}, Password: {2}",
                  Source, User, Password) + "rn";
      }
      catch(Exception ex)
      {
          Info += ex.Message + "rn";
      }
}
Credencial guardado

Credencial guardado

Para recuperar un credencial:

public void ReadCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
     {
          Info += "The Source and the User are required." + "rn";
          return;
     }
 
     try
     {
          var cred = _passwordVaultService.Read(Source, User);
          Info += string.Format("Data recovered successfully. Resource: {0}, User: {1}, Password: {2}",
                  cred.Resource, cred.UserName, cred.Password) + "rn";
      }
      catch (Exception ex)
      {
         Info += ex.Message + "rn";
      }
}
Recuperando credenciales

Recuperando credenciales

Utilizaremos tras validar la información, el método Read de nuestro servicio. Y por último, en el comando para eliminar credenciales:

public void DeleteCommandDelegate()
{
      if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
      {
          Info += "The Source and the User are requiered." + "rn";
          return;
      }
 
      try
      {
          _passwordVaultService.Delete(Source, User);
          Info += string.Format("Data successfully removed. Resource: {0}, User: {1}, Password: {2}",
                  Source, User, Password) + "rn";
      }
      catch (Exception ex)
      {
          Info += ex.Message + "rn";
      }
}

Eliminando credenciales

Eliminando credenciales

Utilizamos el método Delete del servicio.

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

También tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordar que podéis dejar en los comentarios cualquier tipo de sugerencia o pregunta.

Conclusiones

Bajo el namespace Windows.Security.Credentials contamos con una API llamada Credential Locker
que nos permite gestionar credenciales de usuario con suma facilidad.
La gran ventaja de utilizar la API es que nos almacena la información en
un almacén seguro, la información es encriptada al ser almacenada. Además, otra de las grandes ventajas de utilizar la API es el roaming de los credenciales entre dispositivos de confianza bajo la misma cuenta Microsoft.

A tener en cuenta

El almacén de credenciales esta pensado para facilitar la tarea de la
gestión de la seguridad en nuestras aplicaciones. No se recomienda su
uso para almacenar grandes cantidades de información. Contamos con otras
APIs válidas y más adecuadas para esta necesidad.

Más información

[Windows 10] Novedades XAML: x:DeferLoadStrategy

Introducción

Cuando desarrollamos aplicaciones móviles buscamos múltiples
objetivos, que sean atractivas visualmente, intuitivas, fluidas, ágiles,
etc. Habitualmente se le suele dar mucho peso a nivel funcional e
incluso en el aspecto visual pero en ocasiones, se deja la fluidez y agilidad de la App en un segundo plano realizando mejoras en fases finales y en ocasiones como mejoras futuras.

En este aspecto entran en juego herramientas fundamentales para el
análisis de rendimiento.  Consumo de CPU, memoria o red donde se suelen
apreciar métodos no asíncronos o pesados, la necesidad de cache para
reducir consumo de red, etc.

Con herramientas como el Visual Tree Explorer también se puede intuir y detectar casos de interfaz innecesariamente pesada donde los tiempos de carga
se elevan más de lo deseado. Hablamos de interfaces complejas. Por
ejemplo, vistas con diferentes paneles donde suele estar uno de ellos
visible y el resto ocultos o en un segundo plano a la espera de cierta
condición.

¿Qué podemos hacer en estos casos?

En este artículo vamos a desgranar el uso de x:DeferLoadStrategy que nos permitirá mejorar situaciones como las descritas anteriormente.

x:DeferLoadStrategy

x:DeferLoadStrategy nos permite retrasar la creación de un
elemento y sus elementos hijos lo que reduce los tiempos necesarios para
la creación de la UI y por lo tanto de carga. Sin embargo, nada en la
vida es gratis. A cambio, incrementamos levemente el consumo de memoria.

NOTA: Cada elemento que retrasamos en su inicialización con x:DeferloadStrategy añade 600 Bytes en el consumo de memoria.

Podemos deducir que a mayor cantidad de elementos que nos ahorremos
del árbol visual, en menor tiempo se realizara la inicialización de la
vista pero aumentando el consumo de memoria. Por lo tanto, el uso de la
etiqueta es recomendado aunque requiere un análisis mínimo.

Crearemos un nuevo proyecto UAP:

Nueva App UAP

Nueva App UAP

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.

Definimos nuestra interfaz:

<StackPanel Margin="12">
     <TextBlock
          Text="x:DefeLoadStrategy"
          FontWeight="Black"/>
     <TextBlock
          Text="x:DeferLoadStrategy nos permite retrasar la creación de un elemento y sus elementos hijos lo que reduce los tiempos necesarios para la creación de la UI y por
 
lo tanto de carga. Sin embargo, nada en la vida es gratis. A cambio, incrementamos levemente el consumo de memoria."
          TextWrapping="WrapWholeWords" />
     <Grid>
           <Image
                Stretch="UniformToFill"
                Source="ms-appx:///Assets/NinjaCat.jpg" />
     </Grid>
     <Button
          Content="Realize"
          Command="{Binding RealizeElementsCommand}"/>
</StackPanel>

Vamos a retrasar la creación del Grid que contiene la imagen para crearlo bajo nuestro propio interés al pulsar el botón. El uso es sencillo:

<Grid x:Name="DeferredPanel"  
      x:DeferLoadStrategy="Lazy">
      <Image
           Stretch="UniformToFill"
           Source="ms-appx:///Assets/NinjaCat.jpg" />
</Grid>

Utilizamos la etiqueta x:DeferLoadStrategy=”Lazy” en nuestro Grid. De esta forma indicamos que retrasamos la creación del panel y todo su contenido. Para utilizar la etiqueta debemos:

  • Definir un nombre con x:Name. Para iniciar posteriormente la incialización utilizaremos el nombre.
  • Podemos utilizarlo con cualquier elemento visual derivado de UIElement. No podemos utilizarlo con Page o UserControl.
  • no podremos utilizar con XAML XamlReader.Load.

Definimos en la ViewModel de la vista el comando a ejecutar cuando pulsemos el botón:

private ICommand _realizeElementsCommand;
 
public ICommand RealizeElementsCommand
{
     get { return _realizeElementsCommand = _realizeElementsCommand ?? new DelegateCommand(RealizeElementsCommandExecute); }
}
 
private void RealizeElementsCommandExecute()
{
 
}

Nos centramos ahora en el código que se ejecutará en la ejecución del
comando. Tenemos varias formas de crear el elemento que hemos retrasado:

var frame = (Frame)Window.Current.Content;
var page = (Page)frame.Content;
 
page.FindName("DeferredPanel");

La forma más habitual será utilizar el método FindName pasándole el nombre del elemento. Otras formas disponibles son:

  • Utilizar una propiedad del elemento retrasado en un Setter o StoryBoard de un VisualState.
  • Utilizar el elemento retrasado en una animación.
  • Utilizando el método GetTemplateChild pasándole el nombre del elemento.

Si ejecutamos la App veremos:

Antes de crear el Grid con imagen

Al pulsar el botón:

Tras crear Grid

El panel que retrasamos se crea. En este momento:

  • Se lanza el evento Loaded del panel.
  • Se evalúan los Bindings establecidos en el elemento.

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

También tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordar que podéis dejar en los comentarios cualquier tipo de sugerencia o pregunta.

Más información

[Tips and Tricks] Emulador Android de Visual Studio en VMWare Fusion

Introducción

Desde Visual Studio 2015 contamos con múltiples opciones para desarrollar Apps Android, C++, Cordova y C# con Xamarin. Sea cual sea el lenguaje utilizado, una herramienta necesaria será un emulador que nos permita arrancar y probar detalles de forma rápida y efectiva aumentando el ritmo de desarrollo.

NOTA: Recordar que el emulador nunca, repetimos,
nunca puede reemplazar a un dispositivo físico real siendo necesario
realizar pruebas en uno antes de lanzar la App en la tienda.

Emulador Android

Emulador Android

Con Visual Studio 2015 contamos con un emulador Android x86
compatible con Hyper-V integrado con Visual Studio aunque utilizable en
otros IDEs. Soporta múltiples versiones Android, resoluciones,
simulaciones de sensores, etc.

El problema

Realizando desarrollo multiplataforma, una opción interesante es un
mac potente que nos permita acceder a las herramientas de desarrollo iOS
y el resto de opciones de forma sencilla con virtualización utilizando
Parallels o VMWare Fusion.

Con la segunda de las opciones, VMWare Fusion, al intentar arrancar el emulador, obtenemos un error de arranque.

¿Qué ocurre?

El emulador no funciona al no tener soporte OpenGL en entornos virtualizados, como en el caso de VMWare Fusion.

La solución

Vamos a deshabilitar el soporte a OpenGL teniendo en cuenta que
podremos encontrarnos algunas características que no funcionen en este
modo.

Accedemos a la ruta:

C:Program Files (x86)Microsoft XDE10.0.10240.0SKUsAndroid

Abrimos el archivo xdesku.xml y borramos la línea:

GuestDisplayProvider="VsEmulator.OpenGLGuestDisplay"

Listo!.

Más información

[Windows 10] ”Project Westminster”, de la Web a App Universal

Introducción

Windows 10 ha llegado como la culminación en el viaje hacia la convergencia en el desarrollo entre plataformas Windows. Ahora hablamos de Apps Universales
escritas una única vez con un código común tanto para la lógica de
negocio como para la interfaz de usuario. Además, generamos un único
paquete que mantendrá una interfaz consistente y familiar para el
usuario pero adaptada a cada plataforma.

Windows 10

Windows 10

Podemos crear apps que funcionen en todo tipo de
dispositivos como teléfonos, tabletas, portátiles, dispositivos IoT,
Surface Hub e incluso HoloLens. Para ello tenemos las vías utilizadas
hasta este momento, es decir, u
tilizando C# y XAML (o VB, C++, etc).

Sin embargo, Windows 10 tiene como objetivo ser una plataforma
potente pero versátil y accesible para cualquier tipo de desarrollador
sin tener en cuenta su origen de partida.

Universal Windows Platform Bridges

Llegar a Windows es mucho más sencillo que nunca. Si tienes una web,
si tienes una App en iOS o Android e incluso si partes de una App Win32,
existen nuevas opciones destinadas a facilitar la llegada de esas Apps a
Windows de la forma más sencilla posible. Estamos hablando de los Windows Bridge toolkits.

Tenemos a nuestra disposición cuatro Bridges diferentes:

  • Project Westminster: Permite crear Apps Windows empaquetando una página web pudiendola publicar en la Store.
  • Project Islandwood: Windows Bridge para iOS
    (también conocido como proyecto Islandwood) es una herramienta que
    permite importar proyectos XCode para crear una App Windows 10
    reutilizando la mayor cantidad de código Objective C posible.
  • Project Astoria: Windows Bridge para Android
    (también conocido como proyecto Astoria) es una herramienta que permite
    comprobar la cantidad de código java a reutilizar, de modo que, nos
    permite crear App Windows 10 reutilizando código.
  • Project Centennial: Windows Bridge para App
    clásicas permite empaquetar y publicar Apps basadas en .NET y Win32 como
    Apps Windows Store. Además, permite el acceso a servicios o APIs UWP.
Universal Windows Platform Bridges

Universal Windows Platform Bridges

NOTA: Al momento de leer estas líneas solo
Project Westminster (Web) y Project Islandwood (iOS) están disponibles.
Project Astoria (Android) llegará en breve y para Project Centennial
(Win32) debemos esperar algo más, hasta final de año.

Project Westminster

El Bridge Windows para Apps web o también conocido como proyecto
Westminster permite crear y publicar una App Windows 10 utilizando una
web responsive para ello. Se reutiliza el código de la web para crear
una App disponible para teléfonos, tablets, PCs, Xbox, Raspberry Pi,
etc.

Entre las principales características tenemos:

  • Opción de reescalar y adaptar la App para ofrecer la mejor experiencia en cada familia de dispositivo.
  • Tenemos la posibilidad de acceso a APIs Windows desde Javascript.
    Por ejemplo, integrar comandos de voz con Cortana, añadir Live Tiles o
    notificaciones.
  • Podemos depurar con las herramientas de desarrollo de Microsoft Edge.
  • Publicar en la Store con acceso a analíticas, reviews, etc.
  • Monetizar añadiendo In-App Purchases.

Para poder crear nuestra App Windows 10 desde una web necesitamos unos requisitos mínimos:

  • Visual Studio 2015
  • Herramientas desarrollo Windows 10

De la Web a App!

1º Creamos App Universal Javascript

Comenzamos creando un nuevo proyecto de tipo Windows Universal Javascript:

Creamos nuevo proyecto

Creamos nuevo proyecto

Una vez creado tendremos la siguiente estructura en el proyecto:

Estructura inicial

Estructura inicial

2º Borramos todo excepto recursos y manifiesto

Procedemos a borrar todo el contenido exceptuando la carpeta images
con recursos y el archivo de manifiesto. La estructura del proyecto se
quedara:

Borramos lo necesario

Borramos lo necesario

3º Editamos el manifiesto

La página de inicio del archivo de manifiesto estara asignada a un archivo que acabamos de borrar:

Archivo de manifiesto

Archivo de manifiesto

Realizamos el cambio por la página web que vayamos a utilizar como App:

Página a utilizar

Página a utilizar

Además, añadimos una regla de contenido a nuestra URI para especificar la posibilidad de navegación y tipo de acceso:

URI de contenido

URI de contenido

4º Ejecutamos

Todo listo. Ejecutamos nuestra App:

Voila!

Voila!

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

También tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordad que podéis dejar cualquier comentario, sugerencia o duda en los comentarios.

¿Y ahora?

Ahora la parte más importante de todas, hacer de la App, una App
Windows de la máxima calidad. Podemos añadir integración con Cortana,
notificaciones, etc. Nos centraremos en opciones de esta índole en otro
artículo.

Más información

[Tips and Tricks] Xamarin Android Player en Windows 10

Introducción

Xamarin Android Player es un emulador Android
utilizando una máquina virtual x86 con aceleración por hardware y
OpenGL. Es significativamente más rápido que los emuladores Android
instalados por defecto.

Además, Xamarin Android Player esta disponible para Windows y OSX integrado tanto con Visual Studio como con Xamarin Studio.

El problema

Sin duda una opción potente a utilizar en nuestros desarrollos. sin embargo, tras actualizar a Windows 10 o instalándolo en Windows 10 obtenemos el siguiente error al intentar arrancar:

Could not configure host-only network. Please reboot the system…

Could not configure host-only network. Please reboot the system...

Could not configure host-only network. Please reboot the system…

Cada vez que intentamos arrancar el emulador se intenta crear un
nuevo adaptador de red, fallando una y otra vez. El reinicio de la
máquina no soluciona el problema. Si abrimos VirtualBox y nos dirimos a
las preferencias y red, veremos un adaptador por cada vez que intentamos
arrancar el emulador…

NOTA: XAP (Xamarin Android Player) no logra crear automáticamente el adaptador de red necesario.

La solución

Para poder arrancar el emulador debemos:

  • Desintalar Xamarin Android Player y VirtualBox por completo, incluidos datos relacionados con nuestro usuario.
  • Volvemos a instalar de nuevo Xamarin Android Player. Instalará VirtualBox.

NOTA: No arrancamos e instalamos aún emuladores, debemos realizar unos cambios antes de poder hacerlo.

  • Instalamos la última versión de VirtualBox (5.0.X)
  • Abrimos VirtualBox y accedemos a las preferencias de red, Redes solo-anfitrión:
Xamarin Android Player W10 03

Configuración adaptador red

  • Hacemos doble clic sobre el adaptador para editar la configuración e introducimos:
    • IPv4 Address: 10.71.34.1
    • IPv4 Network Mask: 255.255.255.0
  • Arrancamos!. Podremos instalar emuladores. Cada emulador debe arrancar sin problemas y con acceso a la red.
Xamarin Android Player en Windows 10

Xamarin Android Player en Windows 10

Más información

[Windows 10] Probando “Project Islandwood”, reutilizando código Objective-C en App Windows 10

Introducción

Windows 10 ha llegado como la culminación en el viaje hacia la convergencia en el desarrollo entre plataformas Windows. Ahora hablamos de Apps Universales
escritas una única vez con un código común tanto para la lógica de
negocio como para la interfaz de usuario. Además, generamos un único
paquete que mantendrá una interfaz consistente y familiar para el
usuario pero adaptada a cada plataforma.

Windows 10

Windows 10

Podemos crear apps que funcionen en todo tipo de
dispositivos como teléfonos, tabletas, portátiles, dispositivos IoT,
Surface Hub e incluso HoloLens. Para ello tenemos las vías utilizadas
hasta este momento, es decir, u
tilizando C# y XAML (o VB, C++, etc).

Sin embargo, Windows 10 tiene como objetivo ser una plataforma
potente pero versátil y accesible para cualquier tipo de desarrollador
sin tener en cuenta su origen de partida.

Universal Windows Platform Bridges

Llegar a Windows es mucho más sencillo que nunca. Si tienes una web,
si tienes una App en iOS o Android e incluso si partes de una App Win32,
existen nuevas opciones destinadas a facilitar la llegada de esas Apps a
Windows de la forma más sencilla posible. Estamos hablando de los Windows Bridge toolkits.

Tenemos a nuestra disposición cuatro Bridges diferentes:

  • Project Westminster: Permite crear Apps Windows empaquetando una página web pudiendola publicar en la Store.
  • Project Islandwood: Windows Bridge para iOS
    (también conocido como proyecto Islandwood) es una herramienta que
    permite importar proyectos XCode para crear una App Windows 10
    reutilizando la mayor cantidad de código Objective C posible.
  • Project Astoria: Windows Bridge para Android
    (también conocido como proyecto Astoria) es una herramienta que permite
    comprobar la cantidad de código java a reutilizar, de modo que, nos
    permite crear App Windows 10 reutilizando código.
  • Project Centennial: Windows Bridge para App
    clásicas permite empaquetar y publicar Apps basadas en .NET y Win32 como
    Apps Windows Store. Además, permite el acceso a servicios o APIs UWP.
Universal Windows Platform Bridges

Universal Windows Platform Bridges

NOTA: Al momento de leer estas líneas solo
Project Westminster (Web) y Project Islandwood (iOS) están disponibles.
Project Astoria (Android) llegará en breve y para Project Centennial
(Win32) debemos esperar algo más, hasta final de año.

Project Islandwood

Project Islandwood es el Bridge Windows para iOS. Permite importar proyectos existentes iOS para crear Apps Windows reutilizando la mayor cantidad de código Objective-C posible.

NOTA: En estos momentos no se soporta Swift.

Windows Bridge para iOS

Windows Bridge para iOS

Las bondades de la herramienta son:

  • Se soporta Objective-C tanto a nivel de compilación como Runtime.
  • Tenemos herramienta en línea de comandos para importar proyectos.
  • A nivel de editor (Visual Studio) contamos con opciones de coloreado, autocompletado, etc. Es decir, el lenguaje esta soportado.
  • Contamos con opciones de depuración (puntos de ruptura, etc), stacktraces, etc.
  • Opciones de configuración. La configuración del proyecto importado es compartida.
  • Podemos añadir características Windows a la App.

Crear Apps Windows reutilizando código Objective-C

Para utilizar el Bridge necesitamos:

  • Windows 10
  • Visual Studio 2015 (puede ser versión Community)
  • El SDK winobjc

Nuestro proyecto iOS

Llegados a este punto, tenemos claro nuestro objetivo, ¿cierto?.
Vamos a tomar una App iOS utilizando Objective-C y vamos a utilizar
WinObjc para crear una App Windows 10 reutilizando el código de la App
iOS.

Estaría genial entrar de lleno al uso, posibilidades y limitaciones del Bridge pero antes de eso necesitamos…una App iOS.

Vamos a crear una App simple, muy simple, podríamos decir que haremos
uno de los clásicos “Hola mundo”. Tendremos una caja de texto donde el
usuario pondrá su nombre de modo que al pulsar un botón se mostrará un
mensaje saludándole.

Abrimos XCode y creamos un nuevo proyecto iOS:

Nuevo proyecto

Nuevo proyecto

Seleccionamos la plantilla “Single View Application” y Objective-C como lenguaje a utilizar:

Configuración básica del proyecto

Configuración básica del proyecto

Proyecto creado. En el AppDelegate definimos opciones básicas de la ventana y establecemos el controlador a utilizar:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.backgroundColor = [UIColor lightGrayColor];
     
    MainViewController *viewController = [[MainViewController alloc] init];
    self.window.rootViewController = viewController;
     
    [self.window makeKeyAndVisible];
    return YES;
}

Añadiremos una caja de texto junto a un botón:

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    // Text field
    self.textField = [[UITextField alloc]
                              initWithFrame:CGRectMake(10.0f, 50.0f, 300.0f, 30.0f)];
    self.textField.delegate = self;
     
    self.textField.borderStyle = UITextBorderStyleRoundedRect;
     
    // Add the text field to the view
    [self.view addSubview:self.textField];
     
    // Button
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
     
    // Button's frame
    button.frame = CGRectMake(100.0f, 80.0f, 120.0f, 30.0f);
     
    // Action
    [button addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
     
    [button setTitle:@"Press Me!" forState:UIControlStateNormal];
     
    // Add the button to the view
    [self.view addSubview:button];
}

Utilizamos el evento UIControlEventTouchUpInside para mostrar una alerta:

- (void)buttonPressed {
    // Show AlertView
    UIAlertView *helloWinObjcAlert = [[UIAlertView alloc]
                                      initWithTitle:@"Hello, WinObjc!" message:[@"Hello " stringByAppendingString:self.textField.text] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
     
    [helloWinObjcAlert show];
}

En la alerta, mostramos un saludo junto al valor introducido en la caja de texto. Si ejecutamos nuestra App:

iOS App

iOS App

Introduciendo un nombre y pulsando el botón:

Mostrar saludo

Mostrar saludo

Simple, ¿verdad?. Cierto pero suficiente para probar el Bridge. Podéis descargar el ejemplo completo realizado a continuación:

También tenéis el código fuente disponible e GitHub:

Ver GitHub

Creando la App Windows 10

Con la App iOS a migrar esperándonos, ahora si, nos lanzamos a
utilizar el Bridge. Comenzamos clonando o descargando como zip el SDK a
nuestra máquina de desarrollo:

WinObjc en GitHub

WinObjc en GitHub

NOTA: Podemos tener el SDK en cualquier ruta de nuestro equipo. La única limitación es no tener espacios en la ruta.

Antes de utilizar la herramienta para importar nuestro proyecto
XCode, es recomendable echar un vistazo a los ejemplos incluidos en la
carpeta Samples. Sobretodo, es muy interesante para ver posibilidades ej
ejemplo WOCCatalog:

WOCCatalog

WOCCatalog

Utilizando vsimporter

Vamos a importar nuestro proyecto XCode. Tras descargar el SDK precompilado de este enlace, y descomprimirlo en una ruta:

c:winobjc

Creamos una carpeta “Import” donde copiamos nuestro proyecto XCode. A continuación, abrimos la línea de comandos.

Accedemos a la carpeta donde tenemos nuestro proyecto:

c:winobjcImportHelloIslandwood

Ejecutamos la herramienta vsimporter:

c:winobjcImportHelloIslandwood> ....binvsimporter.exe

NOTA: Es recomendable utilizar rutas relativas con la herramienta. Rutas absolutas pueden ocasionar problemas.

Esta herramienta comenzará a migrar nuestor proyecto creando una solución Visual Studio.

Una vez terminada, si accedemos a la carpeta.

Proyecto creado por vsimporter

Proyecto creado por vsimporter

Voila!.

Otras opciones

Como hemos visto, vsimporter es una herramienta de línea de comandos. Cuenta con importantes parámetros como:

  • -i: Habilita el modo interactivo donde se permite seleccionar la configuración específica del proyecto XCode.
  • -format: La opción más interesante. Por defecto, la herramienta
    convierte el proyecto XCode a Windows 10. Con esta opción podemos elegir
    si migrar a Windows 10 (winstore10) o Windows 8.1 (winstore8.1 o winphone8.1).
  • -help: No necesita mucha explicación, muestra un listado de opciones para ayudar en el uso de la herramienta.

Un vistazo al proyecto creado

Abrimos el proyecto creado:

Estructura del proyecto

Estructura del proyecto

Tenemos una solución con dos proyectos, el principal y otro que
contiene los archivos .h, las cabeceras. Cetrándonos en el proyecto
principal, el código principal de la App se encuentra dentro de una
carpeta con el nombre de la App, en nuestro ejemplo HelloIslandwood. El código sigue siendo el mismo que en el proyecto Objective-C que analizamos previamente.

NOTA: Importante resaltar que tenemos reconocimiento de tipo de archivos, coloreado, etc. desde Visual Studio.

Probando la App

Si ejecutamos nuestro proyecto:

Nuestra App iOS en Windows 10!

Nuestra App iOS en Windows 10!

Tras poner el nombre en la caja de texto y pulsar el botón:

Funciona!

Funciona!

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

También tenéis el código fuente disponible e GitHub:

Ver GitHub

Limitaciones

No es oro todo lo que reluce…

La herramienta esta bajo desarrollo, tenemos disponible la primera versión pública y no soporta muchas opciones como:

  • Storyboards. Quizás una de las limitaciones más
    importantes debido al impacto que ocasiona en infinidad de posibles
    apps. Tras múltiples pruebas realizadas, la migración se realiza, crea
    el proyecto Visual Studio pero, no veremos nada (pantalla en negro) al
    ejecutar la App.
  • Sólo x86. No se soporta aún ARM. Otra limitación importante.
  • MapKit
  • AssetsLibrary
  • Ads
  • Etc

Como podemos ver, aun faltan opciones importantes que afectan a
priori a bastantes Apps, tampoco se soportan todas las APIs sino un
subconjunto de las más importantes y utilizadas. Por último, recordad de
nuevo, proyecto en desarrollo no esta excento de Bugs.

¿Y ahora?

Ahora la parte más importante de todas, hacer de la App, una App Windows de la máxima calidad. Tenemos interoperabilidad con APIs Windows.
Podemos integrar la App con el sistema, utilizar opciones Windows para
compartir, mostrar notificaciones en el Action Center, etc. Nos
centraremos en opciones de esta índole en otro artículo.

Más información

[Offtopic] Nuevos retos profesionales!

Nuevos retos

No suelo compartir nada que no sea directa o indirectamente técnico
mediante el Blog. Pero esta ocasión creo que merece que la comparta con
todos vosotros. En ocasiones, cuando menos te lo esperas, se te cruza
una oportunidad en tu camino que no puedes dejar pasar. A mi se me ha
presentado esa oportunidad. Un gran grupo con grandes ideas, grandes
proyectos, mucha energía y ganas, etc. Por ello, he tomado la decisión
de cambiar de empresa. Tras un tiempo en Bravent donde
sin duda he aprendido y crecido donde dejo a amigos y profesionales,
comenzaré con tremenda ilusión y muchas ganas un nuevo camino en Plain Concepts.

El conocer al equipo humano que me rodeará, los proyectos en los que
podré embarcarme y las posibilidades de crecimiento presentadas han
provocado mi actual decisión. Espero estar a la altura de las
circustancias. Sin duda, daré el 101%.

Más información