Mac OS X为您提供了大量配置软件的方法。它可以使用各种不同的机制来稳固存储所有的配置数据。这些机制允许动态地对这些数据进行更新,以及在程序运行时进行这些操作。
Mac OS X有三种基本的配置选项:
- 属性列表:一种用XML作为构造方法来显示数据的格式文本。属性列表中的元素描述了一些特定类型的数据,例如:数组,字典和字符串。系统例程允许程序把属性列表读入内存中并将所描述的数据转换成“真实”的数据。
- 信息属性列表:一种带有预定义关键字的特殊形式的属性列表,用来说明基本的束属性和关于Finder和其他应用程序的重要信息。信息属性列表被存储在束中,它描述了一些信息,诸如所支持的文档格式,URL方案及版权和版本信息。信息属性列表也允许说明用户自定义关键字。
- 预置系统:允许您创建和读写每个用户,每个应用程序和每个主机的预置信息。
Mac OS X的属性列表用扩展标记语言(Extensible Markup Language,XML)作为构造方法以文本的形式来表示数据。这种构造的灵活性给程序设计带来了巨大的便利。(关于XML的概述,参见http://www.w3.org/XML/1999/XML-in-10-points)XML中的元素与某些编程实体相符合,诸如:数组,字典和字符串。
您可以用属性列表编辑器程序来创建属性列表,如果没有,也可以使用其他任何文本编辑器。然后将这个文件加入到您的工程中,属性列表将被存储为束资源(通常为非本地化的)。一旦您的程序被创建和运行,它便能轻松使用特定例程来访问属性列表中的信息,这些例程读取属性列表并将其中所表示的数据转换成适当的类型。所支持的属性列表类型有:字典,数组(向量),字符串,数据,日期,数字和布尔值。
用户属性列表有时用于说明某些初始化数据类型,诸如关键字绑定。名为CustomInfo.plist的文件通常用于此目的。
信息属性列表就是系统属性列表(参见“Property Lists”一章),其包含了束的基本配置信息。此信息在系统和程序代码运行时可用。如同在“束”一章中“束的类型”一节里描述的,束是一种打包方案和一种通用的程序类型,诸如:应用程序,框架和插件。因此信息属性列表是配置几乎所有类型软件的一种广泛而又重要的方式。他们向Finder(以及可能的其他应用程序)提供了所需的信息,也使得应用程序能够处理HFS和HFS+文件。
通常,信息属性列表文件名为Info.plist。他们也可以包含“平台特定”的信息,在这种情况下,平台的标识被放入文件名中,标准“平台特定”的名称如下:
Info-macos.plist
Info-macosclassic.plist如果所有平台的配置信息都是通用的(理想的来说),那么文件名都是Info.plist。当束的代码被执行时,其先寻找“平台特定”的信息属性列表文件,如果在束中不存这个文件,就读取“平台通用”的信息属性列表文件。由于搜索规则查找的是一个文件而不是一个特定的关键字,所以如果既存在“平台特定”的文件又存在“平台通用”的文件时,就需要确定每个文件中都包含了一组相互对应的键值对(Key-value pair)。信息属性列表存放在束的Contents目录中。
束的Info.plist文件中包含了各种信息。在属性列表的顶层,信息被描述成键值对(是一个“字典”)。Mac OS X定义了一组基本配置信息的标准关键字,诸如可执行文件名和束的版本。Finder也为诸如文档,图标及向用户显示的信息定义了关键字。您还可以自由定义和使用自己的关键字。集成开发环境(IDE)提供了一个人性化界面,用以向Info.plist文件输入键值对方式的(标准,Finder和用户的)配置数据。关于标准及Finder特定的信息属性列表关键字,请参见:“附件A”。
一个名为InfoPlist.strings的特殊本地化资源文件伴随Info.plist文件出现。InfoPlist.strings文件包含信息属性列表中需要被本地化的关键字。这些关键字是Info.plist文件中相关联的关键字的值。通常本地化关键字有CFBundleName,CFBundleShortVersionString,CFBundleGetInfoString,CFBundleGetInfoHTML以及CFBundleTypeName 和 CFBundleURLName类型的值。关于本地化束更多信息请,特别是它们在束中该存放在哪里及如何定位,请参见“束”一章。
用来创建或“解读”文档的应用程序信息属性列表允许定义抽象类型及角色。这些定义被应用于剪贴板(粘贴板)数据以及文档。
抽象类型定义了一类文档的一般特性。每种抽象类型都有相应的具体类型,例如一个文件扩展名或一个4字节的标识符。具体类型是抽象类型在不同文件系统或固定格式中编码的方式。抽象类型的概念通过消除“粘贴板类型系统“和”文件扩展名类型系统”之间的不统一,来提高一般应用程序协同工作的能力。抽象类型的名称需要拥有“版权”以保证其唯一性。
角色定义了一个应用程序与特定文档类型间的关系,这里存在5种角色:
- Editor(编辑器):应用程序可以读,修改和储存该类型的数据。
- Bowser(浏览器):应用程序可以读以及显示该类型的数据。
- Printer(打印器):应用程序只能打印该类型的数据。
- Shell(外壳):应用程序为其他进程提供运行时服务--例如 Java applet浏览器。文档的名称就是被运行进程的名称(替代了应用程序名称),对于每个打开的文档,都会创建一个新的进程。
- None(无):应用程序无法解读该类型的数据,但能够说明有关于该类型的信息(举个例子,Finder说明了字体的图标)。
列表11-1包含了一个Info.plist文件的例子。这个信息属性列表是基于Sketch演示程序的,展示了在默认Sketch 应用程序中无法找到的额外关键字。
列表11-1 Sketch演示程序的Info.plist文件
<?xml version="1.0" encoding="UTF-8"?><plist version="1.0"><dict><key>CFAppleHelpAnchor</key><string>sktch001</string><key>CFBundleDevelopmentRegion</key><string>English</string><key>CFBundleName</key><string>Sketch</string><key>CFBundleDisplayName</key><string>Sketch</string><key>CFBundleDocumentTypes</key><array><dict><key>CFBundleTypeExtensions</key><array><string>sketch</string><string>draw2</string></array><key>CFBundleTypeIconFile</key><string>Draw2File</string><key>CFBundleTypeName</key><string>Apple Sketch Graphic Format</string><key>CFBundleTypeOSTypes</key><array><string>sktc</string></array><key>CFBundleTypeRole</key><string>Editor</string><key>NSDocumentClass</key><string>SKTDrawDocument</string><key>NSExportableAs</key><array><string>NSPDFPboardType</string><string>NSTIFFPboardType</string></array></dict><dict><key>CFBundleTypeExtensions</key><array><string>pdf</string></array><key>CFBundleTypeName</key><string>NSPDFPboardType</string><key>CFBundleTypeOSTypes</key><array><string>pdf </string></array><key>CFBundleTypeRole</key><string>None</string></dict><dict><key>CFBundleTypeExtensions</key><array><string>tiff</string></array><key>CFBundleTypeName</key><string>NSTIFFPboardType</string><key>CFBundleTypeOSTypes</key><array><string>tiff</string></array><key>CFBundleTypeRole</key><string>None</string></dict></array><key>CFBundleExecutable</key><string>Sketch</string><key>CFBundleIconFile</key><string>Draw2App</string><key>CFBundleIdentifier</key><string>com.apple.CocoaExamples.Sketch</string><key>CFBundleInfoDictionaryVersion</key><string>6.0</string><key>CFBundlePackageType</key><string>APPL</string><key>CFBundleSignature</key><string>sktc</string><key>CFBundleVersion</key><string>1.2.0</string><key>NSAppleHelpFile</key><string>osxa444.htm</string><key>NSAppleScriptEnabled</key><string>YES</string><key>NSJavaNeeded</key><string>YES</string><key>NSJavaPath</key><array><string>Sketch.jar</string></array><key>NSJavaRoot</key><string>Contents/Resources/Java</string><key>NSMainNibFile</key><string>Draw2Java.nib</string><key>NSPrincipalClass</key> <string>NSApplication</string></dict> </plist>
这个Sketch应用程序还包含了InfoPlist.strings文件中几个关键字的本地化版本。 列表11-2显示了这个文件的英语版本。列表11-2 Sketch演示程序的nfoPlist.strings文件
// InfoPlist.strings// Sketch Exampmle { CFBundleName = "Sketch"; CFBundleGetInfoString = "Apple Sketch Application Example 1.2.0. Copyright \U00A9 1998-2001, Apple Computer, Inc."; NSHumanReadableCopyright = "Copyright \U00A9 1998-2001, Apple Computer, Inc."; // Document type human-readable names. "Apple Sketch Graphic Format" = "Apple Sketch Graphic Format"; "NSPDFPboardType" = "Portable Document Format (PDF)"; "NSTIFFPboardType" = "Tagged Image File Format (TIFF)"; }
预置是一个应用程序或系统的可选项,通过它允许用户定制他们自己的工作环境。大多数应用程序会读入某些形式的用户预置。举个例子,一个基于文档的应用程序可能存储了有关默认字体,自动保存选项及页面设置信息的预置信息。预置也不仅限于应用程序。您可以从任何您所定义的框架和库中读写预置信息,包括用户预置。
Mac OS X的预置系统提供了内建支持,用于在不同会话中保存和恢复用户设置。Carbon 和Cocoa应用程序都能使用核心基础(Core Foundation)的预置服务(Preference Services)来读写预置信息。Cocoa应用程序还能用NSUserDefaults类来读取用户预置。
注意:
预置系统并不是具决定性的,如果他们被丢失了,应用程序也应该能够重建预置的默认设置。您不必存储应用程序初始化配置数据作为预置。初始化配置数据并不具决定性,它应被存储在应用程序包内部的信息属性列表,或是一些其他的属性列表中。
预置系统存储的每一个值都分别与一项关键字相联系,之后当您需要它时,便能使用这项关键字来查找这个预置值,“键值对(Key-value pair)”用一组用户名,应用程序ID和主机(计算机)名来指定一个作用域。这种机制允许您为不同类型用户创建预置。例如,您可以将保存的预置值应用于:
- 当前主机上您的应用程序的当前用户
- 连接到本地网络的特定主机上您的应用程序的所有用户
- 连接到本地网络的任何主机上您的应用程序的当前用户(用户预置通常的类型)
- 连接到本地网络的任何主机上任何应用程序的任何一个用户
应用程序应只存储那些从用户那里得到的信息的预置。对于管理您的应用程序的预置来说,为每个用户分别储存相同的默认预置信息并不是一种高效的方法。预置被存在属性列表文件中,它要被解析来读入预置信息。一种管理预置更有效的方法是先在内部存储一组默认预置,然后将任何用户自定的预置应用到默认设置的开头部分。
预置系统将预置数据存储在适当的文件系统域下Library/Preferences目录中的文件里。举个例子,如果预置用于个人用户,文件将被存入用户home目录的Library/Preferences文件夹中。如果预置应用于某个网络的所有用户,它将被写入Network/Library/Preferences。
存放在Library/Preferences文件夹中的每个文件都有一个单独的名称来唯一标识一个应用程序。每个名称都是来自应用程序的束标识符。您需要在您的应有程序项目中指定束标识符(用关键字CFBundleIdentifier)作为信息属性列表的一部分(详情请参见“标准束关键字”)有关预置的系统例程会使用束标识符来为当前的程序找寻预置。
为了保证没有命名冲突,苹果公司强烈建议束的标识符可与Java包的命名方法相同--既在您公司的域名后跟随应用程序或库的名称。举些例子如com.apple.finder, com.apple.Sherlock, 和 com.foo.ImageImport。使用这个方案可使产生命名冲突的可能性最小化,使您有责任在您的公司域名下管理标识符命名空间。
核心基础(Core Foundation's)的束服务(Bundle Services)和NSBundle类(对Cocoa应用程序而言)提供了特定例程来访问应用程序的束标识符,您应该始终使用这些例程,而决不要硬编码应用程序标识符。
Library/Preferences中的预置文件有一个.plist的扩展名。这个扩展名说明其包含了属性列表。如果您需要编辑预置文件,请使用属性列表编辑器应用程序。如果您愿意,您也可以直接修改XML格式的属性列表来增加或改变应用程序预置。然而,这样做您有可能会把编辑错误引入XML数据中,如果这种情况发生的话,应用程序有可能会无法装载文件而导致丢失所有的预置信息。
如果应用程序试图在其他的位置写入预置信息(不是在适当的文件系统域中Library/Preferences文件夹中)的话,就可能会出现问题。原因之一是,预置服务API并没有对此差别进行过设计。但更重要的是,存储在未知区域的预置数据被排除在预置搜索列表之外,因此它们可能不能被其他应用程序,框架或系统服务所察觉。
当您创建一个新的预置或是搜索一个已存在的预置时,预置系统会使用预置域概念来描述预置的作用域及位置。一个预置域包含了三种信息:应用程序标识符,主机名和用户名。表11-1展示了所有的预置域,它们按照预置系统试图查找一个预置值时搜索的顺序列出。
表11-1 按搜索顺序排列的预置域
1 当前用户 当前应用程序 当前主机 2 当前用户 当前应用程序 任何主机 3 当前用户 任何应用程序 当前主机 4 当前用户 任何应用程序 任何主机 5 任何用户 当前应用程序 当前主机 6 任何用户 当前应用程序 任何主机 7 任何用户 任何应用程序 当前主机 8 任何用户 任何应用程序 任何主机 搜索例程按照以上的顺序在各种预置域中进行查找,直到找到您所指定的关键字。如果一个预置在一个“不太特定”的域中被设置--“任何应用程序”,举个例子--如果不能找到一个“十分特定”的版本,通过这一调用它的值会被恢复。这就意味着“十分特定”的域中的值会覆盖“不太特定”的域中相同关键字的值。
Mac OS X的预置系统包含一个名为defaults的命令行实用程序,用来从应用程序或其他域中读,写及删除预置(或用户defaults)。defaults实用程序作为调试应用程序的辅肋程序是非常有价值的。多数预置是通过应用程序置对话框来存取的(或是类似的程序),但有些不是,例如窗口的位置。您可以通过defaults实用程序来对其进行信息存取。
要运行该实用程序,应先启动终端(Terminal)程序,在BSD shell命令行中,输入defaults并加上适当的命令行参数。如需简单地了解其语法和参数的描述,可直接运行defaults命令。更详细的描述,请阅读defaults的man命令帮助页或在运行此命令时加上usage参数。
$ defaults usage
由于应用程序在运行时可访问预置系统,所以您不应该使用defaults来修改运行着的应用程序的预置信息。如果您修改了一个域中的某个确省值,而它又隶属于一个运行着的应用程序,那么这个应用程序很可能不会察觉到这里的修改,进而可能会覆盖您的预置。
[ 返回 ]