Uno de los usos más frecuentes de la API externa es el de permitir a las aplicaciones ActionScript comunicarse con un navegador web. Gracias a la API externa, los métodos de ActionScript pueden llamar a código escrito en JavaScript y viceversa. A causa de la complejidad de los navegadores y al modo en el que representan internamente las páginas, no hay manera de garantizar que un documento SWF registrará sus funciones de repetición de llamada antes de que se ejecute el primer fragmento de código JavaScript de la página HTML. Por ese motivo, antes de llamar a las funciones del documento SWF desde JavaScript, es aconsejable que el documento SWF llame siempre a la página HTML para notificarle que está listo para aceptar conexiones.
Por ejemplo, mediante una serie de pasos efectuados por la clase IMManager, Introvert IM determina si el navegador está listo para la comunicación y prepara el archivo SWF para la comunicación. El último paso, que consiste en determinar cuándo está listo el navegador para la comunicación, ocurre en el constructor de IMManager del modo siguiente:
public function IMManager(initialStatus:IMStatus)
{
_status = initialStatus;
// Check if the container is able to use the external API.
if (ExternalInterface.available)
{
try
{
// This calls the isContainerReady() method, which in turn calls
// the container to see if Flash Player has loaded and the container
// is ready to receive calls from the SWF.
var containerReady:Boolean = isContainerReady();
if (containerReady)
{
// If the container is ready, register the SWF's functions.
setupCallbacks();
}
else
{
// If the container is not ready, set up a Timer to call the
// container at 100ms intervals. Once the container responds that
// it's ready, the timer will be stopped.
var readyTimer:Timer = new Timer(100);
readyTimer.addEventListener(TimerEvent.TIMER, timerHandler);
readyTimer.start();
}
}
...
}
else
{
trace("External interface is not available for this container.");
}
}
En primer lugar, el código comprueba si la API externa está disponible en el contendor actual utilizando la propiedad
ExternalInterface.available
. En caso afirmativo, inicia el proceso de establecimiento de la comunicación. Dado que pueden producirse excepciones de seguridad y otros errores al intentar comunicarse con una aplicación externa, el código se escribe dentro de un bloque
try
(los bloques
catch
correspondientes se han omitido del listado en aras de la brevedad).
A continuación, el código llama al método
isContainerReady()
, que se muestra aquí:
private function isContainerReady():Boolean
{
var result:Boolean = ExternalInterface.call("isReady");
return result;
}
El método
isContainerReady()
usa a su vez el método
ExternalInterface.call()
para llamar a la función de JavaScript
isReady()
del modo siguiente:
<script language="JavaScript">
<!--
// ------- Private vars -------
var jsReady = false;
...
// ------- functions called by ActionScript -------
// called to check if the page has initialized and JavaScript is available
function isReady()
{
return jsReady;
}
...
// called by the onload event of the <body> tag
function pageInit()
{
// Record that JavaScript is ready to go.
jsReady = true;
}
...
//-->
</script>
La función
isReady()
simplemente devuelve el valor de la variable
jsReady
. Inicialmente, la variable tiene el valor
false
; una vez que el evento
onload
de la página web se ha activado, el valor de la variable cambia a
true
. Dicho de otro modo, si ActionScript llama a la función
isReady()
antes de que se cargue la página, JavaScript devuelve
false
a
ExternalInterface.call("isReady")
y, por lo tanto, el método
isContainerReady()
de ActionScript devuelve
false
. Una vez que la página se ha cargado, la función
isReady()
de JavaScript devuelve
true
, de modo que el método
isContainerReady()
de ActionScript también devuelve
true
.
De vuelta en el constructor de IMManager ocurre una de las dos cosas siguientes, en función de la disponibilidad del contenedor. Si
isContainerReady()
devuelve
true
, el código simplemente llama al método
setupCallbacks()
, que completa el proceso de configuración de la comunicación con JavaScript. Por otra parte, si
isContainerReady()
devuelve
false
, el proceso se pone en espera. Se crea un objeto Timer y se le indica que llame al método
timerHandler()
cada 100 milisegundos del modo siguiente:
private function timerHandler(event:TimerEvent):void
{
// Check if the container is now ready.
var isReady:Boolean = isContainerReady();
if (isReady)
{
// If the container has become ready, we don't need to check anymore,
// so stop the timer.
Timer(event.target).stop();
// Set up the ActionScript methods that will be available to be
// called by the container.
setupCallbacks();
}
}
Cada vez que se llama al método
timerHandler()
, este vuelve a comprobar el resultado del método
isContainerReady()
. Una vez que se inicializa el contenedor, el método devuelve
true.
En ese momento, el código detiene el temporizador y llama al método
setupCallbacks()
para terminar el proceso de configuración de las comunicaciones con el navegador.