24 abril 2009

Widget LG Arena

Hoy voy a contaros las aventuras y desventuras de la creacion de un widget AIR para la presentacion del nuevo telefono LG Arena.

Si quereis verlo completo y descargar el widget, podeis hacerlo desde aqui.

El reto

Un buen dia, mi director creativo me llega y me dice, necesitamos un widget para la presentacion del LG arena, que sea un cubo en 3D, y donde en cada cara, conectaremos un un servicio 2.0, Youtube, Flickr, Musica, RSS Feed, etc... debe funcionar en web y tambien descargarse como AIR para instalarse en escritorio. Ah, y una semana para hacerlo que se presenta el telefono y debe estar online.

Ni habia usado AIR, ni habia usado los API 2.0 de Youtube, Flickr, etc... todo un mundo de I+D e implementacion para 1 semana de trabajo, ademas de coordinarlo todo con Papervision para que este en 3D.

Los problemas

Aunque al final el resultado ha sido muy bueno, yo al menos me siento bastante satisfecho y orgulloso de el, el camino no ha sido facil, entre los problemas del Sandbox de Flash, los bugs de AIR y los maravilloso cuelgues sistematicos de Flash CS4 (Sr. Adobe, se ha lucido con esta version), se ha conseguido.

Pasa a contaros algunos de los problemas que he encontrado, para que pueda servir de ayuda a otros.

Problema: El Sandbox y los bitmap.
Si, existe... pensabais que el sandbox solo afecta a las cargas crossdomain y demas?? Pues yo he descubierto que un bitmap cargado desde una url externa, no es manipulable, la sandbox no lo permite. Os pongo un ejemplo de como afecta este problema. Creais un Sprite y dentro de el, cargais una foto, por ejemplo, directamente desde Flickr. Carga y todo perfecto. Ahora, decidimos usar ese Sprite como MovieMaterial o BitmapMaterial en papervision.. chassss FALLA!!! por que?? porque no puede ser manipulado lo cargado como bitmap por culpa de la sandbox. La retorcida explicacion de esto por parte de las eminentes mentes de Adobe es la siguiente. Imaginemos un caso de un documento o foto que se encuentra dentro de una red privada en una empresa, no es accesible desde el exterior. Asi que unos un piratas, crean una animacion divertida, que busca en redes internas por dicho documento. La animacion se viraliza y un dia llega a manos de un empleado de la compañia que tiene el documento, la aplicacion lo encuentra, lo carga, lo convierte en bitmap y lo manda como byteArray a un servidor y el documento ha sido robado/copiado. Para evitar esto, la sandbox no permite la re-conversion y manipulacion de elementos cargados de direcciones externas (de fuera de tu dominio).

La solucion
:
Usar LoaderContext.checkPolicyFile = true en cada carga y si el servicio al que llamas (lease en mi caso, Flickr or Youtube) tiene un crossdomain.xml que te lo permita, entonces, puedes manipular los bitmaps y contenidos cargados.

Problema: Campos dinamicos de texto y el buttonMode
Bueno, este problema ya he encontrado alguna documentacion de otros blogeros, pero añado mi contribucion. Si creamos un boton dinamicamente, con un campo de texto y aplicamos el buttonMode = true, tenemos una elevada probabilidad (segun le coge al Flash y si el viento sopla hacia el noreste a 3,2 grados) de que donde se encuentra el texto, no aparezca la manita, aunque el texto tenga la propiedad de selectable = false, sigue sin aparecer la manita, aunque funciona como boton, pero no sabes que es un boton.

La solucion:
Añadir al boton las siguientes propiedades:
myclip.buttonMode = true;
myclip.mouseChildren= false;

y en ocasiones tambien:
myclip.myTextField.mouseEnabled = false;

Y aun asi, aumentais las probabilidades de que funcione, pero no siempre.


Problema: El garbage collector y los Tween
Una de las cosas maravillosas del AS3 es el garbage collector, borra de la memoria todo aquello que no esta en uso, asi que nos libera la aplicacion de cosas inutiles que afectan al rendimiento. Pero tambien nos causa problemas. Si dentro de una funcion declaro una variable donde almaceno un Tween, que dura x tiempo y antes de que se complete el Tween, el player corre un ciclo del garbage collector, el Tween se queda parado, nunca dispara el evento de que ha terminado y por tanto, vuestra aplicacion, no sigue.

La solucion: En este caso, hay dos, la primera es declarar la variable en la clase y no en la funcion y luego protegerla, pero te ves forzado ha tener tantas (o un array) como Tweens simultaneos tengas. La otra, para mi mucho mejor, es utilizar el API de caurina.transitions que son estaticas, temporales y el garbage no las destruye.

Problema: El garbage collector de AIR y el codigo "sucio"
Si, es muy bonito trabajar todo en clases, empaquetadas y demas, pero a veces y sobre todo con prisas, yo hago codigo sucio, es decir, introduzco codigo de pequeños eventos o pequeñas funciones directamente en la linea de tiempo de un movieclip. No es lo idea, pero para esas pequeñas cosas, acelaras la produccion y sobre todo si cuentas con poco tiempo. En este caso que nos ocupa. En cada cara del widget, por ejemplo en la de youtube, justo abajo hay un boton para buscar video, cuando se pulsa, aparece un campo de entrada y boton buscar. La forma en que lo hice es un movieclip, donde el primer fotograma tiene el boton y el segundo el campo de texto con su boton de buscar. En la linea de tiempo, tienen el codigo que controla los botones para avanzar de fotograma en el primer caso y una llamada a una funcion de la clase principal en el segundo.

En principio, esto en Flash no me ha causado nunca ningun problema. Pues en AIR si, cuando se pulsa por primera vez el boton, avanza al siguiente fotograma y se prepara para la busqueda y entonces, el garbaje elimina el codigo del primer fotograma, asi, por las buenas y tras realizar una busqueda, y regresar al primer fotograma, nunca vuelve a funcionar.

La solucion:
Aunque parezca increible la solucion, vamos a rizar el rizo. Resulta, que primer fotograma, contenia un boton animado, que parpadeaba para captar la atencion del usuario. La solucion es quitarle la animacion al boton y dejarlo estatico "de los de toda la vida", y el garbage no elimina el codigo. No tiene logica, pero funciona.

Obviamente, la otra solucion es programar una clase que gestiones dicho clip. O gestionarlo directamente desde la clase principal. Pero entonces, no seria un problema con el codigo sucio jejejeje