PhotoRanker: Making of a WinRT App

Este es un post en el que quiero compartirles la experiencia de publicar una app en el store de Windows 8 desde el punto de vista de un desarrollador estándar que ha sufrido en el proceso y ha dejado huella de sus heridas en el código que escribió… mostraré no solo los aspectos técnicos que se tuvieron que superar, sino también los procedimientos de publicación requeridos por el store. Tengan en cuenta sin embargo, que esta no es una guía que enseña a desarrollar apps y que parto del hecho de que ya se sabe como tener una cuenta en el Windows Store, pues tampoco explico cómo se abre una de ellas aquí.

Objetivo

PhotoRanker es una app con un único y claro objetivo… como todas las apps deberían ser. El objetivo es poner rating a las fotografías (estrellas) de una forma rápida y eficiente. De esa manera sabes cuáles realmente merecen ser editadas y cuales otras no valen ni un centavo y mejor borrarlas de una.

Una app debe tener claro su objetivo, para poder de esa manera ser clara en su implementación y clara en su uso. Estamos en un mundo de cientos de miles de apps. En este mundo cada app solo tiene una oportunidad. Si no es buena a primera vista, lo más probable es que genere una desinstalación inmediata. De hecho, personalmente me he visto haciendo eso como consumidor de apps que soy. Así que si no encuentro de inmediato cómo manejar la app, me frustro y le doy uninstall… suerte es que le digo.

Release Often, Release Fast

Otra ventaja de tener bien claro el objetivo, es que tu app va a salir rápido al store. No van a pasar eones mientras por fin terminas de implementar las toneladas de funcionalidad que pueden ir pegadas a una app. De hecho, esta app me consumió 9 horas de desarrollo incluyendo dificultades técnicas, ya que no es un simple RSS. Lo importante, es que pude salir al aire pronto con mi app. Esta nueva tendencia de la industria nos lleva al famoso: “Release often. Release fast”. Naturalmente, cuando publicamos nuestra app con su funcionalidad principal claramente establecida, es fácil comenzar a ver los puntos de mejora y extensión para liberar nuevas versiones. Anyway el update de una app no vale nada… solo es necesario subir la nueva versión y por experiencia os digo, que la liberación de un update tarda mucho menos que la del estreno de la app. Además como usuario, uno se siente muy agradado de recibir updates de las apps que usa, pues solo la mera curiosidad de ver qué mejoró, me hace entrar de nuevo a la app. Sentimos entonces como usuarios que el developer está pendiente de la app y que cada vez encontraremos mejoras en ellas; al final esto se ve representado en buenos rating, mercadeo viral y por ende, más descargas.

Diseño

Tal vez este sea el requisito más trillado en el tema de apps. Si una app es fea, le va pasando algo parecido a cuando es difícil de manejar: produce frustración y el peor de los males desinstalación, acompañado tal vez de un @#$%^&*( en los reviews, que para nada nos favorece. Para Windows 8 hay muchas guías de diseño. Tener un amigo o socio o equipo diseñador, es lo más recomendado. Pero si somos Hard Die Alone Developers, tal vez tengamos que desarrollar ciertos skills de diseño, para hacer toda la app por nuestra propia cuenta; o al menos los bosquejos de la misma. Para este proceso además de alguito de talento, necesitaremos algunas tools que nos facilitarán la vida.

Entonces es cuando recomiendo que comiencen a pensar en vectores. Olviden el dibujito jpg…. literalmente no escala y cuando escala se pixela. Recuerdan la premisa de que la app debe ser linda y así se debe ver en cualquier tipo de resolución? Pues bien; una de las grandes características de los gráficos vectoriales es que escalan muy bien y es fácil generarlos para varias resoluciones. Los gráficos vectoriales vienen en versiones como *.SVG que ya es un estándar. Y pueden exportarse fácilmente a los formatos convencionales. Además al igual que los *.PNG, soportan muy bien las transparencias. Desafortunadamente las apps como tal no soportan gráficos *.SVG. Siempre tenemos que pasarles las versiones *.PNG preferiblemente.

Pero en ese caso, cómo se logra el escalado para cada tipo de resolución?

Muy sencillo. Windows 8 soporta que pongamos varias versiones de un mismo archivo de imagen en la carpeta en donde los estemos almacenando. La idea es que cada archivo tenga una escala específica para cada tipo de monitor. En Windows 8 se han definido varias escalas. Normal (basada en una pantalla de 1366x768) o 100%, luego viene una mediana que es de 140% y finalmente la grande de 180% que soporta resoluciones HD sin distorsionar las imágenes. Y dependiendo de la resolución detectada, Windows 8 carga automáticamente el archivo adecuado. Nosotros solo lo referenciamos con la raíz del nombre y Windows 8 escoge el adecuado; otra opción es usar la convención de un folder por cada tipo de escala. Entonces al final implementaríamos de alguna de estas dos maneras:

image

 

Supongan entonces que se han bajado Visual Studio Express for Windows 8 que es totalmente gratuito y permite comercializar sin problemas las apps que con éste diseñemos. Pues bien… si pagamos 0 por esa herramienta, deberíamos de pagar un montón por una buena herramienta de dibujo y manejo vectorial? Hacerla de piratas y arriesgar nuestra máquina a que se llene de malware tratando de bajar una versión pirata de dicho editor gráfico? Por supuesto que no! Así que en este punto me permito recomendar una gran herramienta free y OSS llamada Inkscape. Con capacidades similares a las de Illustrator, es de manejo muy sencillo y da productividad rápida. La verdad es que yo no sabía mucho de edición de vectores, pero en poco tiempo ya estaba cómodo con la interfaz que me permite manejar capas, hacer operaciones entre objetos (adicionarlos, sustraerlos, intersectarlos), exportar y muchas cosas más. Efectivamente con esa herramienta junto con Paint.Net una tool free creada con .NET y que podría definir como un mspaint con esteroides o PhotoShop light que permite ya manejar los mapas de bits finales (no vectoriales), generé todo el arte requerido para el store de Windows 8, cuando subía a certificación PhotoRanker.

SiteHeader

Logo

entre otras…

The Store

Ya que hablamos del arte requerido para el store, algunos puntos al respecto:

Primero, podría mencionar que es muy fácil ejecutar el proceso de publicación una vez se ha terminado la app. Existe un archivo dentro del proyecto de nuestra app que contiene toda la información relevante con este fin. Ese archivo es el Package.appxmanifest. Visual Studio provee un amigable editor para configurar este archivo antes de subirlo al store. En este, podemos por ejemplo especificar las imágenes de arte a usar para que nuestra app se liste gráficamente en el store, para los tiles, las capacidades de los dispositivos que la app requerirá y muchos otros más.

oldpackagemanifest

Vemos allí como se nos piden los diversos archivos de arte y otra metadata para el store. De aquí quiero hacer la primera salvedad. En este diálogo no se nos pide un logo para el store. Así que si no hacemos algo al respecto, nos aparecerá nuestra app con un horrible logo con una X dentro de un cuadrado. Créanlo… a mí me pasó…

image

Y así quedará publicada nuestra app. Para corregir esto, lo que debemos hacer es cambiar la imagen existente en Assets\StoreLogo.png, por la imagen personalizada que generalmente es un PNG de 50x50: (tuve que lanzar una nueva versión al store solo por esto)

StoreLogo

Afortunadamente, acabo de notar que tras la instalación del Update 1 de Visual Studio 2012, esta situación mejoró sustancialmente al proveerse un nuevo diálogo para este archivo, que permite hasta especificar las imágenes de arte en distinta escala:

NewPackageManifest

Vean más detalles en este post.

Existen muchas otras condiciones para tener en cuenta en la publicación, como las que enumero en este post. Pero luego las leen. Por ahora continuemos con la experiencia en general.

Versiones y Apps Huérfanas:

Son ustedes padres desalmados? Por favor  no dejen huérfanas sus apps. No se trata de subirlas y dejarlas en el store sin nadie que las mantenga. Cada minuto que empleen ustedes en hacer una app, es un potencial minuto que puede traerles retorno de la inversión… ganancia. Si dejan su app sin mantener, están desperdiciando esos minutos que invirtieron previamente.

Pídale a sus amigos que le den opiniones de la app. Qué cosas ven que estaría bien que incluyeran. Ustedes mismos pueden tener sus propias ideas. Comiencen implementando una por una… o si está muy fácil, suban un grupo de tres nuevos features. El Store facilita mucho el proceso. Entre otras cosas, pide que pongan los detalles de las novedades  de la versión.

Personalmente, le cree un portal a mi app. Lo creé gratuitamente en Windows Azure a través de Windows Azure Websites. En este sitio web, puse una sección de Version History, en la cual muestro la evolución de mi app en cada versión. Esto me permite mostrar que la app está en continua evolución… esto obviamente fideliza a mis actuales usuarios y me trae nuevos. Imaginen que están vendiendo ads publicitarios en sus apps (sé de apps de desarrolladores independientes que han llegado a hacer USD$100.000 en solo ads); en ese caso hay que hacer todo lo posible por que permanezcan con nuestra app. Precisamente esto me lleva al otro punto de este post.

Cuida tu código:

Siendo el desarrollador independiente de hoy, querrás estar en permanente movilidad y que el código que hagas vaya contigo a todo lado. Que esté actualizado y que además puedas manejar versionamiento de una manera bastante cómoda…. correcto, te estoy hablando de tener un administrador de código fuente… y sí en Microsoft también ofrecemos un manejador gratuito: Team Foundation Server Express, que gratuitamente les soporta hasta 5 developers. Se lo pueden bajar e instalar, pero yo prefiero usar la versión online que me evita la fatiga de la instalación y me permite tenerlo everywhere. Solo hay que registrarse aquí. Luego de esto, solo queda hacer checkins, checkouts y terminar nuestra app.

Cuida tus clientes:

Efectivamente si queremos que nuestra app nos dé ganancia, hay que dar un valor agregado a los usuarios. Por esto es bueno tener un portal dedicado a nuestra app en el que podamos tener flexibilidad para acompañarla con información adicional, avisos, y demás. Una vez tengamos el portal, obviamente es requerido que dentro de nuestra app le demos la posibilidad al usuario de saber que este portal existe y obviamente de acceder al mismo. Un sitio adecuado para esto, es en el About, dentro del charm de settings de la app. No lo vayan a poner grandote en todas las páginas de su app, porque eso no es nice. En el peor de los casos, al menos háganle una página en FB. Es gratis y sirve para enganchar conversaciones que le dan buzz a tu app. Aprovecha los logos oficiales del Windows Store que encuentras aquí para poner el link a tu app en el store (te llega por correo una vez es aprobada; te recomiendo que de una vez le saques un short url pues es complejo) y por favor sigue las reglas de uso de esos logos que están ahí no los vayas a deformar, recortar ni adornar con maripositas.

Explota la plataforma

Windows 8 tiene una gran cantidad de features para enamorar al usuario. Es un total desperdicio entonces terminar haciendo apenas una app lectora de rss que no tiene en cuentas estos features. En la creación de PhotoRanker he tratado de incluir la mayor cantidad de features de Windows 8 que tenga sentido para este tipo de app. Algo muy válido eso sí, es que la primera versión salga muy sencilla, pero luego le vamos agregando estos features que realmente harán que nuestros usuarios se sientan muy agradado de usar nuestra app. Por ejemplo, en mi primera versión no soportaba portrait ni snap view mode. Tampoco guardaba settings de la app. Pero ya en la tercera, todo esto está soportado. Y por supuesto la idea es en futuras versiones incorporar más features. Por ejemplo un live tile que muestre fotografías rankeadas con 5 estrellas, la posibilidad de buscar fotografías por número de estrellas usando el charm de search y usar el charm de share para compartir determinada fotografía.

Modos de presentación:

Las apps de Windows 8 tienen 3 modos de presentación principales: Full o Landscape, Snap y Portrait. La utilidad de Snap hace mucho sentido en esta app, pues es bien viable que uno por ejemplo esté rankeando sus imágenes mientras ve por ejemplo un video al mismo tiempo. En Windows 8 la mayoría del trabajo de presentación en Snap View se hace automáticamente, pero casi siempre quedan pequeños detalles por corregir. Por ejemplo, en mi app cuando está en fullscreen mode, la fotografía se centra verticalmente:

image

Pero al pasar a Snap, si dejo el comportamiento automático, la imagen se reduce también y al ser pequeña, se ve muy afectada por la superposición de las estrellas:

 

image

La imagen queda perdida en el control.

En este caso algunos ajustes adicionales al modo snap son requeridos. Es muy fácil ejecutarlos una vez identificamos el sitio donde se maneja este evento de cambio de posicionamiento:

 public void OnSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs args)
 {
    switch (ApplicationView.Value)
    {
       case ApplicationViewState.FullScreenLandscape:
            VisualStateManager.GoToState(this, "Full", false);
            break;
       case ApplicationViewState.Snapped:
            VisualStateManager.GoToState(this, "Snapped", false); 
            break;
       case ApplicationViewState.FullScreenPortrait:
            VisualStateManager.GoToState(this, "Portrait", false); 
            break;
       default:
            break;
    }
 } 

Como se observa, solo basta interceptar el evento de OnSizeChanged y luego con un sencillo case actuar de acuerdo al cambio experimentado. En este caso, para corregir el pequeño error del snap view, lo que hago es en el respectivo case, cambiar la alineación vertical de la imagen, y ponerla en TOP:

image

Ese pequeño cambio que hice, significa una mejora sustancial en la experiencia del usuario, ya que aprovecho mejor el espacio y la imagen se ve completamente despejada. Además noten cómo dejo los controles abajo, de manera que ergonómicamente hablando, están muy accesibles para el usuario. Un inconveniente que experimenté en la vista de Snap View,  fue a través del uso del folder picker cuando está en esta vista. Sucede que si abrimos un folder picker y la app está en snap view, se genera una excepción, porque el folder picker no puede trabajar en este modo. Es por esto que con código debemos obligar a la app a expandirse antes de abrir el folder picker. En este post explico cómo hacerlo.

Del portrait mode puedo mencionarles que no requirió ningún ajuste porque la auto organización que da WinRT ya es suficiente:

image

Pero sí quiero hacer una salvedad y es que no olviden además de manejar el código requerido para portrait dentro del manejador del evento OnSizeChanged, especificar en el Package.appxmanifest que la app soporta portrait mode (yo lo olvidé porque creí que con sólo escribir el código bastaba):

image

También les cuento que acabo de notar que aunque controlo muy bien el comportamiento de la ventana principal (donde manipulo las imágenes) en las distintas presentaciones, olvidé controlar la presentación de la primera pantalla en Portrait y Snap, así que se ve algo desquiciado en estos momentos (pruébenlo por ustedes mismos y observen qué cosas deberían corregirse; traten de pensar cómo lo harían). Para la versión 4 estaré corrigiendo esto y agregando un par de funcionalidades más.

Manejo de Estados:

Como novedad para la versión 3 de PhotoRanker, incluí que la app recordará en que foto íbamos. De manera que si el usuario se sale de la app o la cierra, cuando vuelva a abrirla, tenga la posibilidad de escoger si arranca desde donde estaba la última vez:

image

Como ven, tengo un botón destinado para esto. Así el usuario decide si arranca un trabajo nuevo o continúa con el último que estaba haciendo. Esto es muy útil, pues en realidad le da mucha agilidad a la app. En otros escenarios, no es tan lógico preguntar si se quiere arrancar desde el último estado, sino que de inmediato cuando se vuelve a abrir la app, pasamos a este estado. Aquí en mi app sin embargo, sí quise dar la opción. Otros asuntos que guardo, es por ejemplo la elección del usuario de hacer auto-advance mientras hace rating a las fotos. Esta opción de auto-advance, permite que tan pronto el usuario hace tap sobre una estrella para calificar, la siguiente foto sea cargada inmediata y automáticamente, para agilizar así aún más el proceso. Así pues, el valor de esta opción queda almacenado y la app siempre lo recuerda y usa, hasta que el usuario cambie dicho valor.

El proceso de almacenamiento de settings y valores de variables es supremamente sencillo:

 Windows.Storage.ApplicationData.Current.
 LocalSettings.Values["AutoAdvance"] = true; Windows.Storage.ApplicationData.Current.
 LocalSettings.Values["LastIndex"] = 45;

Y recuperar los valores es exactamente igual, eso sí haciendo el respectivo Convert, dado que los valores son almacenados como objetos.

Splash Screen Animado

Una muy buena forma de arrancar impactando con nuestra app, es extendiendo el splash screen para que no sea una simple imagen estática, sino que podemos agregar una animación que “entretenga” al usuario mientras ejecutamos por ejemplo algunas cargas iniciales.

Por naturaleza el Splash Screen de WinRT no se puede animar. Lo que sí se puede hacer, es una simulación de animación, ubicando una nueva página que inicialmente se vea exactamente igual al Splash Screen y luego allí haciendo las animaciones requeridas.

Esto es fácil de lograr comprendiendo el mecanismo.

Sucede que cuando la app arranca, se dispara un evento llamado OnLaunched en el App.xaml.cs. Ese evento trae unos argumentos args. Y dentro de estos argumentos, viene una referencia al SplashScreen que no es más que la imagen que especificamos en el manifiesto de la app para serlo.

Este objeto splash screen tiene entre otros atributos, un rectángulo llamado ImageLocation que determina exactamente las coordenadas en las que se encuentra la imagen que hemos escogido para mostrar. Obviamente, la importancia de este rectángulo radica en que basados en sus coordenadas, ubicaremos la imagen en una nueva página que es donde ejecutaremos la animación:

 

 
var splashImageRect = splash.ImageLocation;
extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.X); 
extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Y); 
extendedSplashImage.Height = splashImageRect.Height; 
extendedSplashImage.Width = splashImageRect.Width;

De esta manera obtenemos una página idéntica al Splash Screen, sobre la cual ejecutaremos una animación mientras hacemos la carga inicial.

Asincronía

Y ya que mencioné animaciones mientras se carga “algo”, de inmediato se me viene a la mente la asincronía. Porque efectivamente estoy hablando de un hecho en el cual asíncronamente se muestra una animación mientras se cargan elementos en memoria por ejemplo. Todo esto sin bloquear la interfaz del usuario, para que éste no sienta que la app es un ladrillo lento y no se aburra… y no desinstale… y recomiende. Es por esto que la asincronía es tan importante en las apps de WinRT. Es un mecanismo súper importante para lograr apps Fast and Fluid. Premisa número 1 de las Windows Store Apps. Sin ella, la interfaz se congelaría a menos de que usaramos complejos procesos con threads y demás.

Precisamente para aprovechar el splash screen y cargar los settings del usuario, lo que hago es generar una animación, mientras en otro hilo a través de un método asíncrono inicio la ejecución del proceso de carga de una manera muy sencilla.

Para comprender mejor este tema, les recomiendo este post, donde explico de una manera bien elemental éste proceso.

De manera similar resuelvo situaciones en las que la app debe tomarse su tiempo, para que el usuario siempre sienta que la app le responde adecuadamente (por ejemplo cuando se lee el directorio con las fotos que se van a rankear)

Conclusiones

He tratado en este artículo de mostrar de una manera bastante informal, las principales experiencias que he tenido publicando una app con cierto nivel de complejidad en el Windows Store. La idea es que ustedes se puedan llevar algo de este conocimiento y que además les sirva para tener nuevas ideas a implementar en sus apps.

Espero a medida de que mi app va evolucionando, ir escribiendo continuaciones a este post que sirvan para enriquecer el conocimiento de la comunidad en cuanto a apps se refiere.

Las apps, a diferencia de otros tipos de desarrollo, son individualizadas con un dueño perfectamente identificado… por eso afirmo que una app es un hijo digital del developer… es su descendencia.

Procuremos tener una descendencia remarcable. Sonrisa