束(bundle)是在文件系统中存放可执行代码及与该代码有关软件资源的一种目录。(束有可能只包含可执行代码或只包含软件资源,但此类情况并不常见)。本质上,束目录将一组资源“捆绑”在一个离散包中。资源包括诸如图像、声音以及某些软件使用的本地化字符串。由于在文件系统中代码和相关资源位于同一位置,这样使得进行安装、卸载以及其它形式的软件管理变得更为方便。
束(bundle)的类型分为三种,分别是应用程序(application)、框架(framework)以及可加载束(loadable bundle),可加载束中也包括了插件(plug-in)。这些束类型的内在结构是(或可以是)十分相似的。应用程序、框架以及可加载束的主要区别在于它们所包含的可执行代码的特性和用途不同。每一个类型都有它自己所需的扩展名:.app,.framework或.bundle(或者是应用程序为可加载束定义的任何扩展名)。
在程序中,束(bundle)等同于一些特定的编程实体,如一个类的实例或一个(在过程语言中)隐含类型的对象。这些实体的一些例程可使需要束资源的程序代码能够访问到这些资源,而其它的一些例程则使您能将可执行代码加载以及链接入一个运行中的应用程序。无论什么时候需要可加载束中的代码,应用程序都可以将它们载入。框架可自动地(并动态地)加载和链接共享库代码。
束(bundle)可包含多个资源组,每一组按语言、地区以及平台对资源进行分组整合。通过将这些资源组和可执行代码集合成一个单一的包,您就能创建一个可在任何被支持的平台上正常运行的应用程序、框架或插件的版本。通过使用此模型,您能根据用户的语言预置参数自动地本地化应用程序的人机界面。
一般地,Finder将束目录以文件形式显示给用户,以避免束的内容被随意地篡改。但是一些束的目录结构并不是隐含的,例如框架(framework)。Finder以文件还是以文件夹形式显示束取决于若干因素,其中包括在束目录中的束位(一种Finder属性)是否被设置。另外,Finder也隐藏了所有应用程序束的扩展名。
注意: 在Mac OS X的当前版本中,框架是“版本化”的束,因为它们不同的内在结构反映了它们为版本化动态共享库进行的配置。该结构缺乏新类型束的许多特征。关于这些类型束的更多信息,请参见“框架”一章。
与Mac OS 9软件传统的打包方案相比,束提供了诸多重要的优点:
- 单个可执行束可在Mac OS 9和Mac OS X上运行。
- 单个束可支持多种芯片体系结构(PowerPC,x86)、库体系结构(CFM,Mach-O)以及其它特殊的可执行文件(例如,Velocity Engine的优化库)。
- 通过一个国际化体系结构,单个的束可支持多种语言。您可方便地增加新的本地化资源或移除不需要的。
- 束可驻留在许多不同格式的卷上,包括象HFS、HFS+和AFP的多分支格式,以及象UFS,SMB和NFS的单分支格式。
- 通过Sherlock,您可索引以及访问帮助文件和其它有关束的信息资源。
- 通过拖曳,您可方便地安装、移动以及删除束。
在下一节“束的剖析”中描述的版本化束不具备上面所列的前两个特征,即支持多芯片体系结构以及可在各种Mac OS系统上运行的可执行文件。
束可以包含可执行代码,和以下各种资源:
- 图像
- 声音
- 本地化字符串
- 资源管理器-格式资源文件
- 库和框架
- 插件和其它可加载束
- 归档的用户界面定义
Mac OS X支持两种不同的束目录布局结构,即“新格式”和“版本化”的目录布局结构。版本化束的目录布局继承自Mac OS X之前的操作系统。以下例子描述了此目录布局结构:
MyBundle.bundle/
MyBundle(可执行代码)
Resources /
Pretty.tiff(非本地化资源)
English.lproj/(本地化资源)
Stop.eps
MyBundle.nib
MyBundle.st
French.lproj/(本地化资源)
stop.eps
MyBundle.nib
MyBundle.strings尽管Mac OS X的最新开发工具只创建新格式束(框架除外),但系统束例程仍能读取并操作两种格式的束。
在本节的以下部分,将通过说明可执行代码和资源在束中的位置,来描述新格式束的布局结构。在磁盘上,束以一个多层次的目录结构存在。最简单的束应具有列表5-1所示的结构:
列表5-1 一个最小的束
- MyBundle/ Contents/ Info.plist换言之,一个束应具有Contents目录和存放于此目录的Info.plist 文件。这些文件对于Finder以及操作系统的其它部分如何处理束来说是重要的。它们描述了束的各种属性。
注意: 不赞成使用PkgInfo 文件,对于束而言这已不再是必需的。虽然仍可将此文件包括在束中,但类型以及创建者信息也应被存放在束的Info.plist 文件内。
信息属性列表Info.plist中包含以XML格式存储的键值对。这些键值对指定了诸如束的名称、束中可执行文件的名称、版本信息、类型和创建者代码、应用程序和文件图标以及其它元数据等属性。系统例程允许束可执行文件在运行时读取这些属性。除了缺省的束属性外,子系统还可将它们自己的属性信息放置在Info.plist文件内,以便于运行时存取。您也可将任何应用程序定义的数据自由地存放在信息属性列表中。关于信息属性列表的更多内容,包括给出的一个例子,请参见“软件结构”一章的“信息属性列表”。
Info.plist 文件附带了一个名为InfoPlist.strings 的特殊的本地化资源文件。它包含需要被本地化的信息属性列表的关键字,例如CFBundleName关键字。关于束名称本地化的更多信息,请参见“束名称本地化”
由最简单的束布局结构发展而来,一个束目录可以扩展成为与复杂应用程序相适应的结构丰满的束。列表5-2 显示了这种束可能具有的结构。
列表5-2 一个复杂应用程序束的布局结构.
- MyBundle/
MyApp /*Contents/MacOSClassic/MyApp的替身*/
Contents/
MacOSClassic/
MyApp
Helper Tool
MacOS/
MyApp
Helper Tool
Info.plist
Resources/
MyBundle.icns
Hand.tiff
Horse.jpg
WaterSounds/
en_US.lproj/
MyApp.nib
bird.tiff
Bye.txt
house.jpg
house-macos.jpg
house-macosclassic.jpg
InfoPlist.strings
Localizable.strings
CitySounds/
en_GB.lproj
MyApp.nib
bird.tiff
Bye.txt
house.jpg
house-macos.jpg
house-macosclassic.jpg
InfoPlist.strings
Localizable.strings
CitySounds/
Japanese.lproj/
MyApp.nib
bird.tiff
Bye.txt
house.jpg
house-macos.jpg
house-macosclassic.jpg
InfoPlist.strings
Localizable.strings
CitySounds/
Frameworks/
PlugIns/
SharedSupport/尽管有各种类型的束,但它们都共有着某些特征。在束的顶层总是有一个Contents目录。而Resources、 Frameworks、 SharedSupport以及PlugIns目录是可选择的,仅在需要时出现。
注意
由于束的内部结构是可变的,所以在程序中应避免硬编码(hard-coding)束中各项目的目录路径,而应使用由苹果提供的合适的束API。
正如它们的名称所表示的那样,一些目录包含有针对特定平台的可执行代码。当一个束的代码被请求时,系统将搜索那些适合底层操作系统格式的代码。“平台特定”的可执行文件目录的名称为MacOSClassic以及MacOS。一般情况下,这些目录内的可执行文件的名称与束的名称相同(无扩展名)。
资源可被本地化或非本地化,即适合所有本地化版本。束中的每一组本地化资源各自存放在它自己的目录中。资源目录中包含有资源文件,这些文件是根据一种语言或根据一个地区来进行分组的。这些目录具有.lproj(“l”代表“语言”)的扩展名。每一个这样的目录内包含了针对一种特定语言以及该语言所适用地区的所有本地化资源。非本地化资源被存放在.lproj的上一层目录内,这是由于这里只需要这些文件的一个版本。其中的一种非本地化资源是束的图标文件(如果是应用程序束,则它是应用程序图标)。习惯上,此文件采用束的名称以及.icns的扩展名; 图像格式可以是任何被支持的类型,但若没有指定扩展名,系统将假定为.icns。关于束资源的更多内容,请参见“本地化资源”。
束通常将每个资源逐个存放在它们自己的文件中,而不需利用资源管理器来将它们聚集到单个文件中。但是,所有本地化字符串被一起存放在一个“字符串”文件中(这样称呼它是因为它的扩展名为.strings)。将可本地化的字符串存放在一个文件中的原因是,其内容可被方便地缓存,以获得更高的性能。 关于包括本地化字符串束资源的更多信息,请参见“国际化”一章。
注意
苹果建议您不要将资源打包在束中可执行文件的资源分支内。
Frameworks目录中包含了与应用程序紧密绑定的各种框架。这些框架的动态共享库是版本锁定的,它不会被在操作系统中可能出现的任何其它(甚至更新)的版本所取代。
Frameworks,PlugIns以及SharedSupport目录主要出现在应用程序束中。关于这些目录的更多信息,请参见“应用程序打包”一章。
当您创建一个束时,生成系统可在束文件夹中设置一个称之为“束位”的Finder属性。当Mac OS X Finder在它的一个窗口中显示该束之前,它将读取此属性。如果束位被设置成“开”,该束将以文件包的形式出现。文件包就是一个文件夹,但Finder将它以类似单个文件的形式呈现给用户(参见图5-1)。换言之,Finder对用户隐藏了文件夹的内容。这种不透明性可以防止用户无意中(或故意地)改变束的内容。
图5-1 Finder的束位
(左图为束位“开”,右图为束位“关”)
一些束可能没有设置束位,苹果所提供的束即是如此,然而Finder仍能适当地处理它们。如同在下一节(“束的类型”)所说明的那样,束文件夹应该具有表示其类型的扩展名-.app,.framework,.bundle等。当Finder遇到其中之一的文件夹扩展名并确定文件夹确实是束时,它将做以下几件事:
- 除框架之外,束以文件包形式显示。
框架则被以文件夹形式显示,以便可浏览它们中的头文件。
- 如果束是一个应用程序(或是一个应用程序包),Finder将隐藏.app扩展名。
- 从束中提取或计算Finder所需要的运行时信息(例如类型代码和创建者代码)并用这些信息来更新Finder的数据库。
关于Finder以及它是如何处理束和文件的更多信息,请参见“Finder”一章。
Mac OS X至少认可三种不同类型的束:
- 应用程序。对于Mac OS X的应用程序来说,应用程序包是一个包含了那些对于启动应用程序所必需的资源(包括应用程序可执行文件)的束。
- 框架。框架是一个包含了动态共享库和与该库相关的所有资源(例如:头文件、图像以及文档)的束。
- 可加载束。象应用程序一样,可加载束通常包含可执行代码以及相关的资源。与应用程序和框架不同的是,可加载束必须被明确地载入一个运行中的应用程序。有一些特殊类型的可加载束,其中的两种类型特别值得关注:
o 调色板(Palette) 调色板是专门用于Interface Builder的一种可加载束。它包含可自定义的用户界面对象以及被载入Interface Builder调色板的已编译代码。
o 插件(Plug-in) 插件是一种特殊类型的可加载束,它需要一种特定的体系结构和实现机制,用以超越常规束编程接口中的代码加载和函数定位。
另外,内核扩展(KEXTs)是一种被低层系统例程认可并载入内核环境的可加载束。尽管它们与其它可加载束很相似,但它们不能被应用程序或其它非内核软件加载。KEXT束具有.kext的扩展名。关于KEXTs的更多信息,请参见“Inside Mac OS X: Kernel Programming(内核编程)”
尽管束可具有任意的扩展名,但还是存在一些命名约定。例如,应用程序一般使用.app扩展名。您同样可为应用程序起其它的扩展名,只要应用程序的Info.plist文件中有一个值为“APPL”的CFBundlePackageType关键字即可。框架的常规扩展名为.framework。插件和其它可加载束也可具有任意的扩展名,但所使用的扩展名应被知道如何加载该束的应用程序所接受。通常可加载束的扩展名为.bundle。
应用程序的主束(Main Bundle)
除大多数命令行工具以外,每个应用程序至少有一个束,即主束,这是放置其资源和可执行文件的文件夹。应用程序束应该有一个.app扩展名(针对已发布应用程序)、.debug扩展名(针对含有调试符号的应用程序)或.profile扩展名(针对含有profiling数据的应用程序)。Finder对用户隐藏.app扩展名。
框架束
框架是将动态共享库、接口定义文件、图像以及其它支持可执行代码的资源与描述相关编程接口的头文件和文档打包在一起的束。一旦应用程序动态地链接了框架,在此以后就很少有需要再进行其他明确的操作;在一个正在运行的应用程序中,框架代码是在需要时被自动加载和链接的。框架的扩展名为.framework。
可加载束和动态链接
除了主束和所链接框架的束之外,应用程序还能装载许多其它的束。尽管这些可加载束通常驻留在应用程序文件包内,然而它们也可被存放在文件系统中的任何地方(但一般被存放在文件系统域的/Library/Extensions目录中)。应用程序可在需要时动态地加载代码和束中的资源。例如,用于管理PostScript打印机的应用程序具有包含可被下载至打印机的PostScript代码的束。
可加载束中的可执行代码可被动态地链接入一个运行中的应用程序。通过使用各种代码加载编程接口,可按名称查寻和通过函数指针来调用可加载束中的函数。然后,此新链接的代码可使用一个束标识符为它的束获得一个实例。通过这个束的实例,代码可定位并加载打包在束中的其他资源。
可加载束应该有一个扩展名,它的常规扩展名是.bundle, Interface Builder调色板束的常规扩展名为.palette。尽管扩展名可以是任意的,但所使用的扩展名应被一个或多个能够加载该束的应用程序所接受。这样,这些束就可以(通过Finder)与应用程序相关联,当用户双击它们时,所关联的应用程序即可启动(如果尚未开始运行)并加载它们。
如果一个束被用于世界上的多个地域时,可能需要针对不同语言、国家或文化区域来定制或本地化它的资源。例如,应用程序可能需要日语、英语、法语和瑞典语,等不同版本的菜单命令标签字符串。应用程序也可能需要提供区域性语言的变种,例如:英国英语和美国英语。
束通过将资源聚合入按区域和语言命名的具有.lproj扩展名的目录来解决这个问题。当进行"区域特定"的资源目录命名时,应从ISO3166标准获取国家代码,从ISO639标准获取语言代码(参见http://www.iso.ch)。您可将针对法国本地的法语方言资源存放在名为fr_FR.lproj的目录中,而将针对加拿大法语的资源存放在名为fr_CA.lproj的目录中。那些不需要指定特定地区的资源应该被存放在只按语言命名的目录中,例如English.lproj或Japanese.lproj。然后,这些本地化的资源目录被存放在束Contents目录的Resources目录中。非本地化(全局)资源被存放在Resources目录的顶级。关于复杂的束文件系统配置实例,请参见“束的剖析”一节。
实际上,束在运行时究竟使用哪一组本地化资源是由用户决定的。与束相关的系统例程依赖于用户在预置程序中设定的语言预置参数。预置程序让用户创建了一张包含了各有效区域的顺序列表,最优先的区域排在第一,第二优先的区域排在其次,依此类推。当束被请求一个资源文件时,它返回与用户区域预置参数最为匹配的资源的文件系统位置。关于Mac OS X进行束资源定位的具体过程,请参见“搜索算法”一节。关于束名称本地化的信息,请参见“文件系统名称的本地化”一节。另外,关于.lproj目录命名的更详尽信息,请参见“国际化”一章。
最常见的资源类型是字符串文件(习惯上,它的扩展名为.strings)。字符串文件被用于存放必须被本地化的字符串。它们实质上是将开发语言中的字符串映射至本地化版本字符串的字典中。虽然关键字不需要作为字符串的开发语言版本,但通常采用这种惯例。
系统例程会首先定位和加载字符串文件(象任何其它资源一样),然后一起查寻您需要的所有字符串。另外,它们也提供了缓冲机制,这样在对同一张表进行多次重复查寻时就不需要重新定位和加载字符串文件了。
因为字符串文件的使用非常频繁, Mac OS X开发环境提供了一套用来访问它们的特殊宏指令和工具。详细内容请参见“字符串的本地化”
.
当您使用“束特定”的编程接口来定位一个给定资源时,它将执行一次搜索以确保返回给您的是资源的正确版本。因为资源可以是全局、本地化或是“平台特定”的,因此搜索可能会很复杂。各种资源查找API将屏蔽不同束打包方案中的潜在变化,以帮助您处理许多棘手的搜索问题。您应该始终使用这些API,而不是由您自己在束的内部搜寻。
图 5-2 详述了系统例程在进行资源定位时采取的步骤。
图5-2 束中资源的定位
请注意全局资源要优先于本地化资源。事实上,一个给定的资源不应该会具有全局和本地化两个版本。如果一个给定资源有一全局版本,那么就不会出现该相同资源的本地化版本。优先的原因是为了获得更高的效率。如果本地化资源首先被搜索的话,那么在找到全局资源前,束例程也许会在若干本地化资源文件夹中进行许多不必要的搜索。另外请注意,为了找到“平台特定”的资源,“平台通用”的版本必须存在。其原因也是为了获得更高的效率。您通常应该首先制作一个资源的通用平台版本,然后再为其它平台提供“平台特定”的版本。
当资源定位例程找到资源时,它将检查是否存在一个“平台特定”的版本。“平台特定”资源用标准标识符命名。当制作“平台特定”资源时,可使用的名称有macosclassic(在Mac OS 9上)及macos(在Mac OS X上)。“平台特定”资源的名称是将“平台通用”的名称与平台标识符字符串组合而成的。例如,如果资源名称为Fish.jpg,那么当特定于Mac OS 9时,它的名称将是Fish-macosclassic.jpg。当在Mac OS 9上运行的应用程序需要资源Fish.jpg时,束例程也将检查Fish-macosclassic.jpg是否存在于与该资源相同的文件夹内。若是,例程将返回“平台特定”资源的路径;若不是,它将返回Fish.jpg的路径。如同先前所提及的,如果Fish-macosclassic.jpg 被找到的话,那么一个名为Fish.jpg的文件必定存在于相同的文件夹内(包括“语言特定”的资源目录)。
束可包含一些数量的特殊资源文件,在他们的数据分支中保存有“资源管理器风格”的资源,这些资源文件习惯上所使用的扩展名为.rsrc,正象在Resources目录下任何其它类型的文件那样,他们也被视为束资源。可使用核心基础束服务(Core Foundation Bundle Services)为这样的文件获得CFURL类型,并将其转换至FSRef类型,然后使用资源管理器来打开它。然而,束服务(Bundle Services)管理着两个特殊的资源文件(如果您提供了它们)。一个文件是针对非本地化资源,它被命名为executable name.rsrc,此处executable name是主可执行文件的名称。该文件与其它非本地化资源一起被存放在Resources目录中。另一个文件是针对本地化资源,它被称为Localized.rsrc。该文件被存放在合适的.lproj目录中,对于每一语言或地区都有一个版本。请确定资源被存放在文件的数据分支而不是资源分支内。
当应用程序被启动时,束服务(Bundle Services)会自动尝试打开这些文件,这样应用程序的资源将总是可用的。而对于其它束(框架和可加载束),您必须使用特别为此目的而提供的束服务功能来亲自完成这项工作。
如果由于某种原因,不能将Carbon应用程序转换为“束”,可将信息属性列表(Info.plist)(作为一个类型为“plst”、标识符为“0”的资源)打包进您的单个文件的应用程序中。更多信息请参见“CFM可执行文件”。
[ 返回 ]