与其他 Flash Player 和 AIR 实例通信

Flash Player 9 和更高版本,Adobe AIR 1.0 和更高版本

LocalConnection 类支持在 Adobe® AIR® 应用程序之间以及在浏览器中运行的 SWF 内容之间进行通信。您也可以使用 LocalConnection 类在 AIR 应用程序与在浏览器中运行的 SWF 内容之间进行通信。使用 LocalConnection 类,您可以构建能在 Flash Player 和 AIR 实例之间共享数据的通用应用程序。

关于 LocalConnection 类

LocalConnection 类用于开发 SWF 文件,这些文件无需使用 fscommand() 方法或 JavaScript 即可向其他 SWF 文件发送指令。LocalConnection 对象只能在同一客户端计算机上运行的 SWF 文件间进行通信,但是它们可以在不同的应用程序中运行。例如,虽然放映文件维护本地信息,而基于浏览器的 SWF 文件进行的是远程连接,但在浏览器中运行的 SWF 文件和在放映文件中运行的 SWF 文件可以共享信息。(放映文件是以可作为独立应用程序运行的格式保存的 SWF 文件 — 即,放映文件嵌入在可执行文件中,因此不需要安装 Flash Player。)

可以使用 LocalConnection 对象在使用不同 ActionScript 版本的 SWF 之间进行通信:

  • ActionScript 3.0 LocalConnection 对象可以与使用 ActionScript 1.0 或 2.0 创建的 LocalConnection 对象进行通信。

  • ActionScript 1.0 或 2.0 LocalConnection 对象可以与使用 ActionScript 3.0 创建的 LocalConnection 对象进行通信。

Flash Player 可自动处理不同版本 LocalConnection 对象间的通信。

最简便的 LocalConnection 对象使用方法是只允许位于同一个域或同一 AIR 应用程序中的 LocalConnection 对象之间进行通信。这样,您就不必担心安全问题了。但如果您需要在不同域之间进行通信,则可采用多种方法来实施安全措施。有关详细信息,请参阅用于 Adobe Flash Platform 的 ActionScript 3.0 参考中列出的 send() 方法的 connectionName 参数和 LocalConnection 类中的 allowDomain()domain 条目的介绍。

可以使用 LocalConnection 对象在一个 SWF 文件中收发数据,但是 Adobe 不建议这样做。而推荐使用共享对象。

可以使用三种方式将回调方法添加到 LocalConnection 对象中:

  • 使 LocalConnection 类成为子类,并添加方法。

  • LocalConnection.client 属性设置为实现方法的对象。

  • 创建扩展 LocalConnection 的动态类,并动态附加方法。

添加回调方法的第一种方式是扩展 LocalConnection 类。您在自定义类中定义方法,而不是将它们动态添加到 LocalConnection 实例中。下面的代码说明了此方式:

package 
{ 
    import flash.net.LocalConnection; 
    public class CustomLocalConnection extends LocalConnection 
    { 
        public function CustomLocalConnection(connectionName:String) 
        { 
            try 
            { 
                connect(connectionName); 
            } 
            catch (error:ArgumentError) 
            { 
                // server already created/connected 
            } 
        } 
        public function onMethod(timeString:String):void 
        { 
            trace("onMethod called at: " + timeString); 
        } 
    } 
}

要创建 CustomLocalConnection 类的新实例,您可以使用以下代码:

var serverLC:CustomLocalConnection; 
serverLC = new CustomLocalConnection("serverName");

添加回调方法的第二种方式是使用 LocalConnection.client 属性。这包括创建自定义类和将新实例分配给 client 属性,如下面的代码所示:

var lc:LocalConnection = new LocalConnection(); 
lc.client = new CustomClient();

LocalConnection.client 属性指示应调用的对象回调方法。在上面的代码中,client 属性设置为自定义类 CustomClient 的新实例。client 属性的默认值是当前 LocalConnection 实例。如果有两个具有同一方法集但是行为不同的数据处理函数,则可以使用 client 属性 — 例如,在某个应用程序中,一个窗口中的按钮切换另一个窗口中的视图。

要创建 CustomClient 类,可以使用下面的代码:

package 
{ 
    public class CustomClient extends Object 
    { 
        public function onMethod(timeString:String):void 
        { 
            trace("onMethod called at: " + timeString); 
        } 
    } 
}

添加回调方法的第三种方式是创建动态类并动态附加该方法,这与在早期版本的 ActionScript 中使用 LocalConnection 类非常相似,如下面的代码所示:

import flash.net.LocalConnection; 
dynamic class DynamicLocalConnection extends LocalConnection {}

通过使用下面的代码,可以将回调方法动态添加到此类中:

var connection:DynamicLocalConnection = new DynamicLocalConnection(); 
connection.onMethod = this.onMethod; 
// Add your code here. 
public function onMethod(timeString:String):void 
{ 
    trace("onMethod called at: " + timeString); 
}

不建议使用上面这种添加回调方法的方式,因为该代码不是非常易于移植。另外,使用此方法创建本地连接会导致性能问题,因为访问动态属性比访问密封属性慢得多。

isPerUser 属性

isPerUser 属性添加到 Flash Player (10.0.32) 和 AIR (1.5.2) 中,旨在解决多个用户登录到 Mac 计算机时发生的冲突。在其他操作系统上,将忽略此属性,因为本地连接始终限制为单个用户。在新代码中应该将 isPerUser 属性设置为 true。但是,目前的默认值为 false 以实现向后兼容。在以后的运行时版本中此默认值可能会更改。

在两个应用程序之间发送消息

可使用 LocalConnection 类在不同的 AIR 应用程序之间以及在浏览器中运行的不同 Adobe® Flash® Player (SWF) 应用程序之间进行通信。还可使用此 LocalConnection 类在 AIR 应用程序和在浏览器中运行的 SWF 应用程序之间进行通信。

例如,可以在网页中包含多个 Flash Player 实例,或者让 Flash Player 实例从弹出窗口中的 Flash Player 实例检索数据。

以下代码定义了一个用作服务器的 LocalConnection 对象,负责接受从其他应用程序传入的 LocalConnection 调用:
package 
{ 
    import flash.net.LocalConnection; 
    import flash.display.Sprite; 
    public class ServerLC extends Sprite 
    { 
        public function ServerLC() 
        { 
            var lc:LocalConnection = new LocalConnection(); 
            lc.client = new CustomClient1(); 
            try 
            { 
                lc.connect("conn1"); 
            } 
            catch (error:Error) 
            { 
                trace("error:: already connected"); 
            } 
        } 
    } 
}

此代码首先创建一个名为 lc 的 LocalConnection 对象,然后将 client 属性设置为对象 clientObject。当其他应用程序调用此 LocalConnection 实例中的方法时,运行时会在 clientObject 对象中查找此方法。

如果已存在具有指定名称的连接,则会引发 Argument Error 异常,指出由于已经连接了该对象,连接尝试失败。

当 Flash Player 实例连接到此 SWF 文件并尝试调用指定本地连接的任何方法时,系统会将请求发送到 client 属性指定的类(该属性被设置为 CustomClient1 类):

package 
{ 
    import flash.events.*; 
    import flash.system.fscommand; 
    import flash.utils.Timer; 
    public class CustomClient1 extends Object 
    { 
        public function doMessage(value:String = ""):void 
        { 
            trace(value); 
        } 
        public function doQuit():void 
        { 
            trace("quitting in 5 seconds"); 
            this.close(); 
            var quitTimer:Timer = new Timer(5000, 1); 
            quitTimer.addEventListener(TimerEvent.TIMER, closeHandler); 
        } 
        public function closeHandler(event:TimerEvent):void 
        { 
            fscommand("quit"); 
        } 
    } 
}

若要创建 LocalConnection 服务器,请调用 LocalConnection.connect() 方法并提供唯一的连接名称。如果已存在具有指定名称的连接,则会生成 ArgumentError 错误,指出由于已经连接了该对象,连接尝试失败。

以下代码段说明如何创建名为 conn1 的 LocalConnection:
try 
{ 
    connection.connect("conn1"); 
} 
catch (error:ArgumentError) 
{ 
    trace("Error! Server already exists\n"); 
}
从辅助应用程序连接到主应用程序要求您首先在发送 LocalConnection 对象中创建一个 LocalConnection 对象;然后使用连接名称和要执行的方法名称来调用 LocalConnection.send() 方法。例如,要向您早期创建的 LocalConnection 对象发送 doQuit 方法,可使用以下代码:
sendingConnection.send("conn1", "doQuit");

此代码使用连接名称 conn1 连接到现有 LocalConnection 对象,并调用远程应用程序中的 doMessage() 方法。如果想要将参数发送到远程应用程序,可以在 send() 方法中的方法名称后指定附加参数,如以下代码段所示:

sendingConnection.send("conn1", "doMessage", "Hello world");

连接到不同域中的内容和 AIR 应用程序

若要只允许从特定域进行通信,可以调用 LocalConnection 类的 allowDomain()allowInsecureDomain() 方法,并传递包含允许访问此 LocalConnection 对象的一个或多个域的列表,以便传递允许的一个或多个域名。

在早期版本的 ActionScript 中,LocalConnection.allowDomain()LocalConnection.allowInsecureDomain() 是必须由开发人员实现的、且必须返回布尔值的回调方法。在 ActionScript 3.0 中,LocalConnection.allowDomain()LocalConnection.allowInsecureDomain() 都是内置方法,开发人员可以像调用 Security.allowDomain()Security.allowInsecureDomain() 那样调用这两个内置方法,传递要允许的一个或多个域的名称。

Flash Player 8 对本地 SWF 文件引入了安全限制。可以访问 Internet 的 SWF 文件还不能访问本地文件系统。如果指定 localhost,则任何本地 SWF 文件都可以访问 SWF 文件。如果 LocalConnection.send() 方法试图从调用代码没有访问权限的安全沙箱与 SWF 文件进行通信,则会调度 securityError 事件 (SecurityErrorEvent.SECURITY_ERROR)。若要解决此错误,可以在接收方的 LocalConnection.allowDomain() 方法中指定调用方的域。

可以向 LocalConnection.allowDomain()LocalConnection.allowInsecureDomain() 方法传递两个特殊值:*localhost。星号值 (*) 表示允许从所有域访问。字符串 localhost 允许将从应用程序资源目录之外的本地安装内容调用应用程序。

如果 LocalConnection.send() 方法尝试从调用代码没有访问权限的安全沙箱与应用程序进行通信,则会调度 securityError 事件 (SecurityErrorEvent.SECURITY_ERROR)。若要解决此错误,可以在接收方的 LocalConnection.allowDomain() 方法中指定调用方的域。

如果仅在同一个域中的内容之间实现通信,可以指定一个不以下划线 (_) 开头且不指定域名的 connectionName 参数(例如 myDomain:connectionName)。在 LocalConnection.connect(connectionName) 命令中使用相同的字符串。

如果要实现不同域中的内容之间的通信,可以指定一个以下划线开头的 connectionName 参数。指定下划线使具有接收方 LocalConnection 对象的内容更易于在域之间移植。下面是两种可能的情形:

  • 如果 connectionName 字符串不以下划线开头,则运行时会添加一个包含超级域名和冒号的前缀(例如 myDomain:connectionName)。虽然这可以确保您的连接不会与其他域中具有同一名称的连接冲突,但任何发送方 LocalConnection 对象都必须指定此超级域(例如 myDomain:connectionName)。如果将具有接收方 LocalConnection 对象的 HTML 或 SWF 文件移动到另一个域中,则运行时会更改前缀,以反映新的超级域(例如 anotherDomain:connectionName)。必须手动编辑所有发送方 LocalConnection 对象,以指向新超级域。

  • 如果 connectionName 字符串以下划线开头(例如 _connectionName),则运行时不会向该字符串添加前缀。这意味着接收方和发送方 LocalConnection 对象都将使用相同的 connectionName 字符串。如果接收方对象使用 LocalConnection.allowDomain() 来指定可以接受来自任何域的连接,则可以将具有接收方 LocalConnection 对象的 HTML 或 SWF 文件移动到另一个域,而无需更改任何发送方 LocalConnection 对象。

    connectionName 中使用下划线名称的缺点是存在潜在冲突,例如当两个应用程序使用同一 connectionName 同时尝试连接时。第二个相关缺点是安全方面的。使用下划线语法的连接名称不会标识侦听应用程序的域。出于这些原因,应优先选择使用域限定名称。

Adobe AIR

要与在 AIR 应用程序安全沙箱中运行的内容(随 AIR 应用程序一起安装的内容)通信,必须将可标识 AIR 应用程序的超级域用作连接名称的前缀。超级域字符串以 app# 开头,然后依次是应用程序 ID、点 (.)字符和发行商 ID(如果已定义)。例如,在 ID为 com.example.air.MyApp 且没有发行商 ID 的应用程序中,connectionName 参数中使用的正确超级域为 "app#com.example.air.MyApp"。因此,如果基础连接名称为“appConnection”,则应在 connectionName 参数中使用的整个字符串为 "app#com.example.air.MyApp:appConnection"。如果应用程序包含发行商 ID,则必须将该 ID 也包含在超级域字符串中,即 "app#com.example.air.MyApp.B146A943FBD637B68C334022D304CEA226D129B4.1"

当您允许其他 AIR 应用程序通过本地连接与您的应用程序通信时,必须调用 LocalConnection 对象的 allowDomain() 来传入本地连接域名。对于 AIR 应用程序,此域名的形式与连接字符串相同,都包含了应用程序 ID 和发行商 ID。例如,如果发送方 AIR 应用程序的应用程序 ID 为 com.example.air.FriendlyApp 且发行商 ID 为 214649436BD677B62C33D02233043EA236D13934.1,则用于允许此应用程序进行连接的域字符串为:app#com.example.air.FriendlyApp.214649436BD677B62C33D02233043EA236D13934.1。(自 AIR 1.5.3 起,并不是所有 AIR 应用程序都包含发行商 ID。)