One of the most common uses for the external API is to allow
ActionScript applications to communicate with a web browser. Using
the external API, ActionScript methods can call code written in
JavaScript and vice versa. Because of the complexity of browsers
and how they render pages internally, there is no way to guarantee
that a SWF document will register its callbacks before the first
JavaScript on the HTML page runs. For that reason, before calling
functions in the SWF document from JavaScript, your SWF document
should always call the HTML page to notify it that the SWF document
is ready to accept connections.
For example, through a series of steps performed by the IMManager
class, the Introvert IM determines whether the browser is ready
for communication and prepares the SWF file for communication. The
first step, determining when the browser is ready for communication,
happens in the IMManager constructor, as follows:
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.");
}
}
First of all, the code checks whether the external API is even
available in the current container using the
ExternalInterface.available
property.
If so, it begins the process of setting up communication. Because
security exceptions and other errors can occur when you attempt
communication with an external application, the code is wrapped
in a
try
block (the corresponding
catch
blocks
were omitted from the listing for brevity).
The code next calls the
isContainerReady()
method,
listed here:
private function isContainerReady():Boolean
{
var result:Boolean = ExternalInterface.call("isReady");
return result;
}
The
isContainerReady()
method in turn uses
ExternalInterface.call()
method
to call the JavaScript function
isReady()
, as follows:
<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>
The
isReady()
function simply returns the value
of the
jsReady
variable. That variable is initially
false
;
once the
onload
event of the web page has been
triggered, the variable’s value is changed to
true
.
In other words, if ActionScript calls the
isReady()
function
before the page is loaded, JavaScript returns
false
to
ExternalInterface.call("isReady")
,
and consequently the ActionScript
isContainerReady()
method
returns
false
. Once the page has loaded, the JavaScript
isReady()
function
returns
true
, so the ActionScript
isContainerReady()
method
also returns
true
.
Back in the IMManager constructor, one of two things happens
depending on the readiness of the container. If
isContainerReady()
returns
true
,
the code simply calls the
setupCallbacks()
method,
which completes the process of setting up communication with JavaScript.
On the other hand, if
isContainerReady()
returns
false
,
the process is essentially put on hold. A Timer object is created
and is told to call the
timerHandler()
method every 100
milliseconds, as follows:
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();
}
}
Each time the
timerHandler()
method gets called,
it once again checks the result of the
isContainerReady()
method.
Once the container is initialized, that method returns
true.
The
code then stops the Timer and calls the
setupCallbacks()
method
to finish the process of setting up communication with the browser.