使用跨边界事件
跨边界事件允许不同两个安全域中的swf以广播和侦听事件,因此不用使用导入加载的方式分配应用程序域。即载入swf模块后,不必导入到应用程序的安全域中,当也无需构建应用程序域的树级结构。保留各自的安全域后,主应用程序和模块之间无法访问到各自的应用程序域,因此不能使用getDefinition()方法获取任何定义。主应用程序和模块之间只能通过事件交换数据。实现事件广播侦听的对象时loaderInfo对象的sharedEvents属性,由于loaderInfo对象被加载器和加载的swf共享,因此sharedEvent引用的EventDispatcher对象也被两者共享。下图描述了这个过程:
安全域 |
主应用程序 |
loaderInfo对象
sharedEvents |
安全域 |
模块文档类 |
这里的安全不同的安全域不是指AlplicationAdomain.Current 和其子域,以及新域!!
而是域名的域Domain !! 例如我们可以加载任何一个网站的图片或者swf !却不能访问里面的数据!除非你被作者授权了或者有策略文件!!假如 没授权 怎么实现两个不同 域Domain(不同地址url) 的 swf信息互访!!通过loaderInfo.sharedEvents实现!!!
前提两个swf都需要相应应的事件接口!dispatchEvent.......
举个跨边界事件交换数据的例子,创建一个发送事件的lib.fla,在帧上写如下代码:
//lib.fla
var timer:Timer=new Timer(50,100);
timer.addEventListener(TimerEvent.TIMER,onTimer);
timer.start();
function onTimer(event:TimerEvent):void
{
loaderInfo.sharedEvents.dispatchEvent(event);
}
再创建一个主应用程序main.fla,在舞台上放置一个名为mc的影片剪辑,在帧上写如下代码:
var urlRequest:URLRequest=new URLRequest("libSwf.swf");
//main.fla
var loader:Loader=new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderComplete);
loader.load(urlRequest);
function loaderComplete(event:Event):void
{
loader.contentLoaderInfo.sharedEvents.addEventListener(TimerEvent.TIMER,onTimer);
}
function onTimer(event:TimerEvent):void
{
mc.x++;
}
可以发现侦听到sharedEvents广播的事件后,mc在缓缓向右移动。
跨边界事件是个实用技巧,即使两个swf互不信任,也不妨碍事件的广播侦听。载入到相同安全域或分配到任意应用程序域后也与跨边界事件无关。例如需要编写的模块swf能够在外部单独运行,所有的模块又能够被组织成一个大型应用程序。此时可以使用跨边界事件进行主应用程序和模块之间的通信。这种用跨边界实现的模块组合一般不使用RSL共享库,因为模块需要能单独运行。
如果模块不需要单独运行,就有使用RSL的可能性。使用跨边界事件的方式真的不能使用不同安全域中的定义吗?否也,我们不能使用getDefinition()方法获取定义,但是不能把定义传过来吗?答案是肯定的。我们可以自定义一个事件,使用事件属性把类的定义传过来。下面来实际演示一下,为了简化操作,我们还是使用flash为编写工具,以上面lib.fla和main.fla为例,如下:
在lib.fla新建一个类名为Mc的影片剪辑,使用ActionScript导出,导出类名也为Mc,在第一帧,舞台上不要放置任何影片。在帧上添加代码:
//lib.fla帧代码
loaderInfo.addEventListener(Event.COMPLETE,loadComplete);
function loadComplete(event:Event):void
{
loaderInfo.sharedEvents.dispatchEvent(new ApplicationEvent(ApplicationEvent.DOMAIN_DEFINE,Mc));
}
//main.fla帧代码
var loader:Loader=new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,mcLoad);
loader.load(new URLRequest("http://localhost:8080/upload.swf"));
function mcLoad(event:Event):void
{
loader.contentLoaderInfo.sharedEvents.addEventListener(ApplicationEvent.DOMAIN_DEFINE,getDomain);
}
function getDomain(event:Event):void
{
txt.text=String((Object(event).defineClass));
}
//ApplicationEvent是自定义事件
package
{
import flash.events.Event;
public class ApplicationEvent extends Event
{
public static var DOMAIN_DEFINE="defineDomain";
public var defineClass:Class;
public function ApplicationEvent(type:String,defineClass:Class)
{
super(type);
this.defineClass=defineClass;
}
public override function toString():String
{
return formatToString("type","bubbles","cancelable","defineClass");
}
public override function clone():Event
{
return new ApplicationEvent(ApplicationEvent.DOMAIN_DEFINE,defineClass);
}
}
}
把lib.swf放到网络上,这里直接放到本机iis中。lib.fla注意更改沙箱类型为“只能访问网络”。测试lib.swf代码,发现输出了main.swf中的Mc定义。有个地方解释一下,在main.fla中使用Event为事件接受类型而不是ApplicationEvent,因为ApplicationEvent事件被看成两个不同命名空间中的类,这是应为lib.swf和main.swf是被单独编译的,ApplicationEvent被编译了两次。由于lib.swf中的定义在不同的安全域中,不能以共享方式获取,这里解决的办法是以基类Event作为类型,Event又不是一个动态类,所以转化为Object来引用applicationDomain属性。
不要幻想把lib.swf中的应用程序域传递过来,因为as3在使用applicationDomain的getDefinition()发放时发现applicationDomain不在安全域时会报错。