En web es muy habitual que un SWF principal cargue SWFs externos desde un servidor, ya sea el mismo (donde no tendremos ningún problema) u otro diferente (donde aprece ya el interesante mundo de los sandbox de seguridad de flash). Si esto lo llevamos a una aplicación AIR, nos topamos con un extra que es el sandbox de la propia aplicación.
Una de las grandes caracterísiticas de flash es la capacidad de cargar películas que a su vez pueden funcionar como aplicaciones. Esta situación, además de común, nos permite estructurar las aplicaciones de forma modular y lograr una independencia interesante entre la base instalada, los contenidos y los datos que estos manejan. Extender aplicaciones al vuelo, o actualizarlas es una de las grandes virtudes que tendría este sistema.
Si bien Adobe AIR tiene la capacidad de detectar la versión instalada de la aplicación, contrastarla con un control de versiones en el servidor y auto descargarse y actualizarse con un código bastante sencillo, la tentación de tener los contenidos de forma externa a la aplicación, es demasiado grande, asi que el planteamiento está claro: una base instalada que sirve sólo como eso, base, para albergar módulos que funcionan como aplicaciones «independientes» y que al estar en el servidor, pueden ser actualizadas de manera totalmente transparente al usuario. ¿suena bien, no?
La clave está en «independientes»… ya que muy raro tiene que ser que lo que carguemos realmente no tenga nada que decirle a la base, o la base a lo que carguemos. Normalmente siempre se necesita una comunicación, por muy básica que sea. Ahi nos encontramos con un sandbox que nos limita, que es el de la aplicación AIR, y las técnicas habituales de allowDomain que funcionan en web, no nos sirven en este caso. (Más sobre sandboxes)
Documentándote sobre el tema darás en la referencia de AS3 con sharedEvents y con parentSandboxBridge y childSandboxBrige. El primero funciona, nos permite a través de esta propiedad lanzar y escuchar eventos entre la base y el módulo cargado, pero hasta donde yo he podido trabajar, solamente permite Eventos básicos y no todos, menos aun no personalizados, con lo que si quieres pasar determinada información no te va a ser suficiente. Un ejemplo válido podría ser que la base detecte cuando se ha cerrado el módulo cargado, para liberarlo totalmente de memoria.
ParentSandboxBridge y childSanboxBridge forman el «bridge» que se ha ideado en AIR para que esta comunicación pueda producirse, pero su uso no es tan trivial como se pinta en la ayuda (en AIR a partir de HTML está bastante más documentado), y saca a la luz problemas que no se mencionan en la ayuda, y que pueden desesperar a más de uno (no se si se nota el tono de «yo soy uno de esos quemaos», y me consuelo viendo que no soy el único).
Estas propiedades, que son dos objetos genéricos de la propiedad loaderInfo cuando hacemos una carga de un SWF, solamente están presentes cuando estamos compilando para Adobe AIR, pero para que la comunicación mediante el bridge (que no es más que dos clases que se exponen a través de estas propiedades, y que cada una de ellas da acceso a los métodos públicos de ambas partes, parent a los de la aplicación AIR y child a los de la película SWF cargada) pueda producirse de forma completa, es evidente que las tenemos que usar en la película cargada. Esta es la teoría.
La realidad nos dice que no podrás compilar tu pelicula SWF que será cargada si pones algo como esto (sacado de la ayuda directamente) en la clase que la controle:
package { import flash.display.Sprite; import flash.system.Security; public class PriceQuoter extends Sprite { private var storeRequester:Object; public function PriceQuoter() { storeRequester = loaderInfo.parentSandboxBridge; } } }
En cuanto tratas de compilar el SWF, que obviamente no está siendo compilado para AIR, te dice que parentSandboxBridge no es una propiedad de LoaderInfo, y con toda la razón, porque esa propiedad solo está disponible en AIR. Entonces ¿para qué coño me crean un bridge que no puedo usar? FAIL total de la ayuda. La verdad que la ayuda aqui se ha quedado más que coja, aqui os pego, más o menos, el código que he empleado en mi último proyecto :
package com.qinteractiva.blog.AIRmodules { import flash.display.Sprite; import flash.events.Event; import flash.text.TextField; public class Modulo extends Sprite { public var texto_txt:TextField; private var _isInApp:Boolean; private var _bridge:Object; public function Modulo() { addEventListener(Event.ADDED_TO_STAGE, init); try { accederAplicacion(); } catch(e:Error) { trace("Excepción: SWF fuera de un entorno AIR"); _isInApp = false; } } private function accederAplicacion():void { if(loaderInfo['parentSandboxBridge'] != null) { _isInApp = true; _bridge = loaderInfo['parentSandboxBridge']; } else { _isInApp = false; } } private function init(ev:Event):void { removeEventListener(Event.ADDED_TO_STAGE, init); if (_isInApp) { texto_txt.text = _bridge.getTexto(); } else { texto_txt.text = 'No estamos en AIR'; } } } }
Este código no solo evita el problema del error de compilación (y cuidado con el camelCase en el nombre de parentSandboxBridge, que me estoy aun acordando de mi «parentSandBoxBridge»), sino que además controla si se está ejecutando en un entorno de una App AIR o directamente de forma independiente, para evitar errores de ejecución. Desde aquí muchas graciasa los consejos de un amigo sorpresa que me salió por twitter , y que me ayudó a enfocar mejor este tema :)
Adicionalmente, existe una técnica que me parece la más potente, pero que implica determinadas situaciones y mecanismos que en muchas ocasiones pueden ser más que sobrantes, y que se explica perfectamente por Ethan Malasky, que básicamente consiste en descargars el SWF en binario, y guardarlo en el sandbox de la aplicación, para posteriormente cargarlo, y dado que ya forma parte de la misma no tener ninguna limitación (evidentemente teniendo cuidado con los riesgos de seguridad que ello conlleva). No obstante en mi opinión, para determinadas comunicaciones, esto se va totalmente del ámbito.
De regalito os dejo los ficheros fuentes del ejemplo para ver la comunicación completa entre una aplicación AIR y un módulo SWF cargado externamente desde un servidor remoto a través del bridge que AIR nos da. Lo debéis proba en el entorno de Flash, ya que no os he preparado la aplicación AIR como tal, no era el objetivo del ejemplo.
Source Code