共享对象

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

共享对象(有时称为“Flash cookie”)是一个数据文件,您访问的站点可能会在您的计算机上创建该文件。共享对象通常用于增强您的 Web 浏览体验 — 例如,使用这种对象可以个性化经常访问的网站的外观。

关于共享对象

共享对象与浏览器 Cookie 的功能类似。使用 SharedObject 可以将数据存储到用户的本地硬盘上,然后在同一会话期间或以后的会话中调用这些数据。各应用程序仅能访问它们自己的 SharedObject 数据,而且仅当它们在同一域中运行时才能访问。不会将这些数据发送到服务器,并且在其他域中运行的其他应用程序不能访问这些数据,但同一域中的应用程序可以访问这些数据。

共享对象与 Cookie 的比较

Cookie 和共享对象非常相似。由于大多数 Web 程序员都熟悉 Cookie 的工作原理,因此将 Cookie 与本地共享对象进行比较可能非常有用。

遵循 RFC 2109 标准的 Cookie 通常有以下属性:

  • 可以到期,并且默认情况下通常在会话结束时到期。

  • 可以由客户端在特定站点上禁用。

  • Cookie 总数最多为 300 个,每个站点最多只能有 20 个 Cookie。

  • 每个 Cookie 的大小通常限制为 4 KB。

  • 有时被认为是安全威胁,因此有时在客户端上被禁用。

  • 存储在客户端浏览器指定的位置。

  • 通过 HTTP 从客户端传输到服务器。

    相比而言,共享对象有以下属性:

  • 默认情况下不会到期。

  • 默认情况下,每个共享对象的大小限制为 100 KB。

  • 可以存储简单的数据类型(例如字符串、数组和日期等)。

  • 存储在应用程序指定的位置(位于用户的主目录中)。

  • 永远不会在客户端和服务器之间传输。

关于 SharedObject 类

使用 SharedObject 类,可以创建和删除共享对象,并且可以检测正在使用的 SharedObject 对象的当前大小。SharedObject 类由以下方法组成。

方法

说明

clear()

从 SharedObject 对象中清除所有数据,并从磁盘中删除 SharedObject 文件。

flush()

立即将 SharedObject 文件写入客户端上的文件中。

getLocal()

返回对客户端的域特定的本地 SharedObject 对象的引用。如果不存在这样的对象,此方法将在客户端上创建一个新共享对象。

getSize()

获取 SharedObject 文件的大小(以字节为单位)。默认大小限制为 100 KB,但是如果客户端允许,可以更大些。

除了这些方法,SharedObject 对象还有以下属性:

属性

说明

data

只读属性,表示共享对象存储的属性的集合。

onStatus

共享对象的事件处理函数,针对每个警告、错误或信息说明进行调用。

创建共享对象

要创建 SharedObject 对象,请使用 SharedObject.getLocal() 方法,该方法的语法如下:

SharedObject.getLocal("objectName" [, pathname]): SharedObject

以下示例将创建一个名为 mySO 的共享对象:

public var mySO:SharedObject; 
mySO = SharedObject.getLocal("preferences");

这样会在客户端计算机上创建一个名为 preferences.sol 的文件。

术语本地是指共享对象的位置。在本例中,Adobe® Flash® Player 将 SharedObject 文件本地存储到客户端的主目录中。

当您创建共享对象时,Flash Player 会为其沙盒中的应用程序和域创建一个新目录,还会创建一个用于存储 SharedObject 数据的 *.sol 文件。此文件的默认位置为用户主目录的子目录。下表显示了此目录的默认位置:

操作系统

位置

Windows 95/98/ME/2000/XP

c:/Documents and Settings/username/Application Data/Macromedia/Flash Player/#SharedObjects

Windows Vista

c:/Users/username/AppData/Roaming/Macromedia/Flash Player/#SharedObjects

Macintosh OS X

/Users/username/Library/Preferences/Macromedia/Flash Player/#SharedObjects/web_domain/path_to_application/application_name/object_name.sol

Linux/Unix

/home/username/.macromedia/Flash_Player/#SharedObjects/web_domain/path_to_application/application_name/object_name.sol

#SharedObjects 目录下是一个随机命名的目录。随机命名目录下是一个与主机名匹配的目录,再下一级是与应用程序路径匹配的目录,最后一级是 *.sol 文件。

例如,如果您在本地主机上的 /sos 子目录中请求名为 MyApp.swf 的应用程序,则 Flash Player 会将 *.sol 文件存储在 Windows XP 的以下位置:

c:/Documents and Settings/fred/Application Data/Macromedia/Flash Player/#SharedObjects/KROKWXRK/#localhost/sos/MyApp.swf/data.sol
注: 如果未在 SharedObject.getLocal() 方法中提供名称,Flash Player 会将该文件命名为 undefined.sol。

默认情况下,在使用 Flash 时,每个域可在本地保存的持久性 SharedObject 对象的大小不能超过 100 KB。用户可以配置此值。如果应用程序尝试将数据保存到共享对象中,但假如保存成功的话共享对象的大小将超过 100 KB,则 Flash Player 将显示“本地存储区”对话框,用户可在该对话框中允许或拒绝为请求访问的域增加本地存储区。

指定路径

可以使用可选的 pathname 参数指定 SharedObject 文件的位置。此文件必须是该域的 SharedObject 目录的子目录。例如,如果请求本地主机上的应用程序并指定以下内容:

mySO = SharedObject.getLocal("myObjectFile","/");

Flash Player 会将 SharedObject 文件写入 /#localhost 目录(如果应用程序处于脱机状态,则写入 /localhost 目录)。如果希望客户端上的多个应用程序能够访问同一共享对象,这将非常有用。这种情况下,客户端可以运行两个 Flex 应用程序,这两个应用程序都指定了作为域的根目录的共享对象路径;此后,客户端可以从这两个应用程序访问同一共享对象。要在多个非持久性应用程序之间共享数据,可以使用 LocalConnection 对象。

如果指定的目录不存在,Flash Player 将不会创建 SharedObject 文件。

将数据添加到共享对象

可以使用 SharedObject 对象的 data 属性将数据添加至 SharedObject 的 * .sol 文件中。要将新数据添加到共享对象,请使用下面的语法:

sharedObject_name.data.variable = value;

以下示例将 userNameitemNumbersadminPrivileges 属性及其值添加到 SharedObject 中:

public var currentUserName:String = "Reiner"; 
public var itemsArray:Array = new Array(101,346,483); 
public var currentUserIsAdmin:Boolean = true; 
mySO.data.userName = currentUserName; 
mySO.data.itemNumbers = itemsArray; 
mySO.data.adminPrivileges = currentUserIsAdmin;

data 属性赋值后,必须强制 Flash Player 将这些值写入 SharedObject 文件。要强制 Flash Player 将这些值写入 SharedObject 文件,请使用 SharedObject.flush() 方法,如下所示:

mySO.flush();

如果未调用 SharedObject.flush() 方法,Flash Player 会在应用程序退出时将值写入该文件。但是,如果该数据超出默认设置,用户将失去增加 Flash Player 可用空间来存储该数据的机会。因此,较好的做法是调用 SharedObject.flush()

使用 flush() 方法将共享对象写入用户的硬盘驱动器时,应仔细检查用户是否已使用 Flash Player 设置管理器 (www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager07.html) 显式禁用了本地存储,如下面的示例所示:

var so:SharedObject = SharedObject.getLocal("test"); 
trace("Current SharedObject size is " + so.size + " bytes."); 
so.flush();

在共享对象中存储对象

可以将简单对象(如数组或字符串)存储到 SharedObject 的 data 属性中。

在以下示例中,一个 ActionScript 类定义了一些控制与共享对象进行交互的方法。用户可以使用这些方法将对象添加到共享对象中或从共享对象中删除对象。此类将存储一个包含简单对象的 ArrayCollection。

package { 
    import mx.collections.ArrayCollection; 
    import flash.net.SharedObject; 
 
    public class LSOHandler { 
 
        private var mySO:SharedObject; 
        private var ac:ArrayCollection; 
        private var lsoType:String; 
 
        // The parameter is "feeds" or "sites". 
        public function LSOHandler(s:String) { 
            init(s); 
        } 
 
        private function init(s:String):void { 
            ac = new ArrayCollection(); 
            lsoType = s; 
            mySO = SharedObject.getLocal(lsoType); 
            if (getObjects()) { 
                ac = getObjects(); 
            } 
        } 
 
        public function getObjects():ArrayCollection { 
            return mySO.data[lsoType]; 
        } 
 
        public function addObject(o:Object):void { 
            ac.addItem(o); 
            updateSharedObjects(); 
        } 
 
        private function updateSharedObjects():void { 
            mySO.data[lsoType] = ac; 
            mySO.flush(); 
        } 
    } 
 
}

下面的 Flex 应用程序为所需的每个共享对象类型创建一个 ActionScript 类的实例,然后在用户添加或删除博客或站点 URL 时调用该类的方法。

<?xml version="1.0"?> 
<!-- lsos/BlogAggregator.mxml --> 
<mx:Application 
    xmlns:local="*" 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    creationComplete="initApp()" 
    backgroundColor="#ffffff" 
> 
    <mx:Script> 
        <![CDATA[ 
        import mx.collections.ArrayCollection; 
        import mx.utils.ObjectUtil; 
        import flash.net.SharedObject; 
 
        [Bindable] 
        public var welcomeMessage:String; 
        
        [Bindable] 
        public var localFeeds:ArrayCollection = new ArrayCollection(); 
 
        [Bindable] 
        public var localSites:ArrayCollection = new ArrayCollection(); 
 
        public var lsofeeds:LSOHandler; 
        public var lsosites:LSOHandler; 
 
        private function initApp():void { 
            lsofeeds = new LSOHandler("feeds"); 
            lsosites = new LSOHandler("sites"); 
            
            if (lsofeeds.getObjects()) { 
                localFeeds = lsofeeds.getObjects(); 
            } 
            if (lsosites.getObjects()) { 
                localSites = lsosites.getObjects(); 
            } 
        } 
        
        // Adds a new feed to the feeds DataGrid. 
        private function addFeed():void { 
            // Construct an object you want to store in the 
            // LSO. This object can contain any number of fields. 
            var o:Object = {name:ti1.text, url:ti2.text, date:new Date()}; 
            lsofeeds.addObject(o); 
    
            // Because the DataGrid's dataProvider property is 
            // bound to the ArrayCollection, Flex updates the 
            // DataGrid when you call this method. 
            localFeeds = lsofeeds.getObjects(); 
            
            // Clear the text fields. 
            ti1.text = '';        
            ti2.text = ''; 
        } 
        
        // Removes feeds from the feeds DataGrid. 
        private function removeFeed():void { 
            // Use a method of ArrayCollection to remove a feed. 
            // Because the DataGrid's dataProvider property is 
            // bound to the ArrayCollection, Flex updates the 
            // DataGrid when you call this method. You do not need 
            // to update it manually. 
            if (myFeedsGrid.selectedIndex > -1) { 
            
localFeeds.removeItemAt(myFeedsGrid.selectedIndex); 
             } 
        } 
        
        private function addSite():void { 
            var o:Object = {name:ti3.text, date:new Date()}; 
            lsosites.addObject(o); 
            localSites = lsosites.getObjects(); 
            ti3.text = '';                
        } 
        
        private function removeSite():void { 
            if (mySitesGrid.selectedIndex > -1) { 
            
localSites.removeItemAt(mySitesGrid.selectedIndex); 
            }       
        } 
 
        ]]> 
    </mx:Script> 
        
    <mx:Label text="Blog aggregator" fontSize="28"/> 
    
    <mx:Panel title="Blogs"> 
        <mx:Form id="blogForm"> 
            <mx:HBox> 
                <mx:FormItem label="Name:"> 
                    <mx:TextInput id="ti1" width="100"/> 
                </mx:FormItem> 
                <mx:FormItem label="Location:"> 
                    <mx:TextInput id="ti2" width="300"/> 
                </mx:FormItem> 
                <mx:Button id="b1" label="Add Feed" click="addFeed()"/> 
            </mx:HBox> 
 
            <mx:FormItem label="Existing Feeds:"> 
                <mx:DataGrid 
                    id="myFeedsGrid" 
                    dataProvider="{localFeeds}" 
                    width="400" 
                /> 
            </mx:FormItem> 
            <mx:Button id="b2" label="Remove Feed" click="removeFeed()"/> 
        </mx:Form> 
    </mx:Panel> 
    
    <mx:Panel title="Sites"> 
        <mx:Form id="siteForm"> 
            <mx:HBox> 
                <mx:FormItem label="Site:"> 
                    <mx:TextInput id="ti3" width="400"/> 
                </mx:FormItem> 
                <mx:Button id="b3" label="Add Site" click="addSite()"/> 
            </mx:HBox> 
 
            <mx:FormItem label="Existing Sites:"> 
                <mx:DataGrid 
                    id="mySitesGrid" 
                    dataProvider="{localSites}" 
                    width="400" 
                /> 
            </mx:FormItem> 
            <mx:Button id="b4" label="Remove Site" click="removeSite()"/> 
        </mx:Form> 
    </mx:Panel> 
    
</mx:Application>

在共享对象中存储指定了类型的对象

可以在共享对象中存储指定了类型的 ActionScript 实例。通过调用 flash.net.registerClassAlias() 方法来注册类可以实现此目的。如果创建了类的实例并将该实例存储在共享对象的数据成员中,而以后要读出该对象,则将得到指定了类型的实例。默认情况下,SharedObject objectEncoding 属性支持 AMF3 编码,并从 SharedObject 对象中解包存储的实例;存储的实例将保持您调用 registerClassAlias() 方法时指定的同一类型。

创建多个共享对象

可以为同一 Flex 应用程序创建多个共享对象。为此,需要为每个共享对象指定不同的实例名,如以下示例所示:

public var mySO:SharedObject = SharedObject.getLocal("preferences"); 
public var mySO2:SharedObject = SharedObject.getLocal("history");

这样可以在 Flex 应用程序的本地目录中创建一个 preferences.sol 文件和一个 history.sol 文件。

创建安全 SharedObject

当使用 getLocal()getRemote() 创建本地或远程 SharedObject 时,有一个名为 secure 的可选参数,该参数确定对此共享对象的访问是否限于通过 HTTPS 连接传递的 SWF 文件。如果此参数设置为 true 且 SWF 文件是通过 HTTPS 传递的,Flash Player 将新建一个安全共享对象,或者获取对现有安全共享对象的引用。只可由通过 HTTPS 传递的 SWF 文件对此安全共享对象进行读取或写入,而该 HTTPS 调用 SharedObject.getLocal() 并将 secure 参数设置为 true。如果此参数设置为 false 且 SWF 文件是通过 HTTPS 传递的,Flash Player 将新建一个共享对象,或者获取对现有共享对象的引用。

仅可由通过非 HTTPS 连接传递的 SWF 文件对此共享对象进行读取或写入。如果 SWF 文件是通过非 HTTPS 连接传递的,并且您尝试将此参数设置为 true,将无法创建新的共享对象(或访问以前创建的安全共享对象),并会引发错误,并且共享对象设置为 null。如果尝试通过非 HTTPS 连接运行以下代码片断,SharedObject.getLocal() 方法将引发错误:

try 
{ 
    var so:SharedObject = SharedObject.getLocal("contactManager", null, true); 
} 
catch (error:Error) 
{ 
    trace("Unable to create SharedObject."); 
}

无论此参数为何值,创建的共享对象的数量都接近域所允许的磁盘空间的总量。

显示共享对象的内容

值存储在共享对象中的 data 属性中。可以使用 for..in 循环来循环访问共享对象中的每个值,如下面的示例所示:

var so:SharedObject = SharedObject.getLocal("test"); 
so.data.hello = "world"; 
so.data.foo = "bar"; 
so.data.timezone = new Date().timezoneOffset; 
for (var i:String in so.data) 
{ 
    trace(i + ":\t" + so.data[i]); 
}

销毁共享对象

若要破坏客户端上的 SharedObject,请使用 SharedObject.clear() 方法。这样做不会销毁应用程序共享对象的默认路径中的目录。

以下示例将从客户端中删除 SharedObject 文件:

public function destroySharedObject():void { 
    mySO.clear(); 
}

SharedObject 示例

以下示例显示了可在 SharedObject 对象中存储简单对象(如 Date 对象),而不必对这些对象手动进行序列化和反序列化。

以下示例从欢迎您第一次访问开始。在您单击“注销”后,应用程序会将当前日期存储在共享对象中。下次您启动此应用程序或者刷新该页时,应用程序将欢迎您回来,并显示一则提醒,指出您上次注销的时间。

要查看应用程序的运行情况,请启动该应用程序,单击“注销”,然后刷新该页。应用程序将显示您上次访问时单击“注销”按钮的日期和时间。您随时都可以通过单击“删除 LSO”按钮来删除存储的信息。

<?xml version="1.0"?> 
<!-- lsos/WelcomeMessage.mxml --> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="initApp()"> 
  <mx:Script><![CDATA[ 
  public var mySO:SharedObject; 
  [Bindable] 
  public var welcomeMessage:String; 
 
  public function initApp():void { 
     mySO = SharedObject.getLocal("mydata"); 
     if (mySO.data.visitDate==null) { 
        welcomeMessage = "Hello first-timer!" 
     } else { 
        welcomeMessage = "Welcome back. You last visited on " + 
           getVisitDate(); 
     } 
  } 
 
  private function getVisitDate():Date { 
     return mySO.data.visitDate; 
  } 
 
  private function storeDate():void { 
     mySO.data.visitDate = new Date(); 
     mySO.flush(); 
  } 
  
  private function deleteLSO():void { 
     // Deletes the SharedObject from the client machine. 
     // Next time they log in, they will be a 'first-timer'. 
     mySO.clear(); 
  } 
  
  ]]></mx:Script> 
  <mx:Label id="label1" text="{welcomeMessage}"/> 
  <mx:Button label="Log Out" click="storeDate()"/> 
  <mx:Button label="Delete LSO" click="deleteLSO()"/> 
</mx:Application>