外部 API 最常见的用途之一就是允许 ActionScript 应用程序与 Web 浏览器进行通信。使用外部 API 时,ActionScript 方法可以调用使用 JavaScript 编写的代码,反之亦然。由于浏览器的复杂性及其内部呈示页的方式,因此根本无法保证 SWF 文档能够在 HTML 页中的第一个 JavaScript 运行之前注册它的回调。出于这个原因,在从 JavaScript 调用 SWF 文档中的函数之前,SWF 文档应总是调用 HTML 页,以通知它 SWF 文档已准备好接受连接。
例如,通过 IMManager 类执行的一系列步骤,Introvert IM 可确定浏览器是否做好了通信的准备,并为通信准备 SWF 文件。第一个步骤(确定浏览器是否已做好通信准备)是在 IMManager 构造函数中执行的,如下所示:
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.");
}
}
首先,代码使用
ExternalInterface.available
属性检查外部 API 是否还可在当前容器中使用。如果可用,它将开始建立通信的过程。由于尝试与外部应用程序通信会产生安全异常及其他错误,因此将代码包括在
try
块中(为了简便起见,列表中省略了相应的
catch
块)。
然后,代码调用
isContainerReady()
方法,如下所示:
private function isContainerReady():Boolean
{
var result:Boolean = ExternalInterface.call("isReady");
return result;
}
isContainerReady()
方法又使用
ExternalInterface.call()
方法来调用 JavaScript 函数
isReady()
,如下所示:
<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>
isReady()
函数仅返回
jsReady
变量的值。该变量最初为
false
;一旦触发了网页的
onload
事件,该变量的值即更改为
true
。也就是说,如果 ActionScript 在加载页之前调用
isReady()
函数,则 JavaScript 对
ExternalInterface.call("isReady")
返回
false
,因此使得 ActionScript
isContainerReady()
方法返回
false
。加载页之后,JavaScript
isReady()
函数将返回
true
,从而使得 ActionScript
isContainerReady()
方法也返回
true
。
回到 IMManager 构造函数中,根据容器的准备情况,将发生两种情况之一。如果
isContainerReady()
返回
true
,则代码调用
setupCallbacks()
方法,该方法将完成与 JavaScript 建立通信的过程。另一方面,如果
isContainerReady()
返回
false
,实际上会使该过程陷入停顿状态。创建 Timer 对象,并指示其每隔 100 毫秒调用
timerHandler()
方法一次,如下所示:
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();
}
}
每次调用
timerHandler()
方法时,它都会再次检查
isContainerReady()
方法的结果。初始化容器后,该方法返回
true。
然后,代码停止 Timer,并调用
setupCallbacks()
方法来完成与浏览器建立通信的过程。