Bundle Programming Guide (一)

介绍

捆绑是macOS和iOS中用于封装代码和资源的基础技术。软件包通过为所需资源提供已知位置来简化开发人员体验,同时减少创建复合二进制文件的需要。相反,捆绑包使用目录和文件来提供更自然的组织类型,也可以在开发和部署过程中轻松修改。

为了支持bundle,Cocoa和Core Foundation都提供了用于访问bundle的内容的编程接口。由于捆绑包使用有组织的结构,因此所有开发人员都了解捆绑的基本组织原则很重要。本文档为您提供了解软件包的工作原理以及开发过程中如何使用它们来访问资源文件的基础。

本文档的组织

本文档包含以下章节:

关于Bundles介绍了bundle和packages的概念,以及系统如何使用它们。
捆绑结构描述了标准捆绑类型的结构和内容。
访问Bundle的内容显示如何使用Cocoa和Core Foundation界面来获取有关bundle及其内容的信息。
文档包描述了文档包(与捆绑松散相关)以及如何使用它们的概念。

虽然本文档中的信息适用于所有类型的软件包,但如果您使用更专门的软件包(如框架和插件),则还应参考以下文档:

框架编程指南提供了有关创建和使用自定义框架的详细信息。
代码加载编程主题提供有关使用Objective-C语言编写插件的信息。
插件提供了有关使用C语言编写插件的信息。

关于捆绑

捆绑是在MacOS和iOS中提供软件的便捷方式。捆绑包为终端用户提供简化的界面,同时为开发提供支持。本章介绍捆绑包,并讨论他们在macOS和iOS中的作用。

软件包和软件包

虽然捆绑包和包裹有时被称为可互换的,但它们实际上代表着非常不同的概念:

是Finder向用户呈现的任何目录,就像它是单个文件一样。
捆绑包是具有标准化层次结构的目录,其中包含可执行代码和该代码使用的资源。
软件包提供了使MacOS易于使用的基本抽象之一。如果您查看计算机上的应用程序或插件,您实际查看的是一个目录。软件包目录中是使应用程序或插件运行所需的代码和资源文件。然而,当您与包目录进行交互时,Finder将其视为单个文件。此行为可防止临时用户进行可能会对软件包内容产生不利影响的更改。例如,它阻止用户重新排列或删除可能阻止应用程序正常运行的资源或代码模块。

注意:即使软件包默认为不透明文件,用户仍然可以查看和修改其内容。在包目录的上下文菜单中是“显示包内容”命令。选择此命令将显示一个新的Finder窗口,设置为包目录的顶层。用户可以使用此窗口来导航包的目录结构,并进行更改,就像它是常规目录层次结构一样。
而软件包可以改善用户体验,捆绑更适合帮助开发人员打包他们的代码,并帮助操作系统访问该代码。软件包定义用于组织与您的软件相关联的代码和资源的基本结构。这种结构的存在也有助于促进诸如本地化之类的重要特征。 bundle的确切结构取决于您是创建应用程序,框架还是插件。它还取决于其他因素,如目标平台和插件的类型。

捆绑包和包有时被认为是可互换的原因是许多类型的包也是包。例如,应用程序和可加载的软件包是软件包,因为它们通常被系统视为不透明目录。但是并不是所有的bundle都是包,反之亦然。

系统如何识别捆绑包和包

如果满足以下任一条件,则Finder将目录作为包:

该目录有一个已知的文件扩展名:.app,.bundle,.framework,.plugin,.kext等。
该目录具有一些其他应用程序声明代表包类型的扩展名;请参阅文档包。
该目录的包的位设置。
指定包的首选方法是给包目录一个已知的文件扩展名。在大多数情况下,Xcode通过提供适用正确扩展名的模板来为您提供帮助。所有你需要做的是创建一个适合类型的Xcode项目。

大多数捆绑包也是包。例如,应用程序和插件通常由Finder显示为单个文件。但是,对于所有捆绑类型都不是这样。特别地,框架是一种捆绑,它被视为单个单元,用于链接和运行时使用,但框架目录是透明的,以便开发人员可以查看头文件及其包含的其他资源。

关于Bundle显示名称

显示名称给用户一些控制包和包在Finder中的显示,而不会破坏依赖它们的客户端。而用户可以自由重命名文件,重命名应用程序或框架可能导致相关代码模块通过名称引用应用程序或框架中断。因此,当用户更改包的名称时,更改只是表面的。 Finder不是在文件系统中更改包名称,而是将一个单独的字符串(称为显示名称)与捆绑包相关联,并显示该字符串。

显示名称仅供用户使用。您永远不会使用显示名称来打开或访问代码中的目录,但是在向用户显示目录的名称时,请使用它们。默认情况下,捆绑包的显示名称与捆绑包名称本身相同。但是,在以下情况下,系统可能会更改默认显示名称:

如果捆绑包是应用程序,则Finder在大多数情况下隐藏.app扩展名。
如果软件包支持本地化显示名称(并且用户尚未明确更改软件包名称),则Finder将显示与用户当前语言设置相匹配的名称。
尽管Finder大部分时间都会为应用程序隐藏.app扩展名,但它可能会显示它以防止混淆。例如,如果用户更改应用程序的名称,并且新名称包含另一个文件扩展名,则Finder将显示.app。扩展,以清楚该捆绑是一个应用程序。例如,如果要将.mov扩展名添加到Chess应用程序,Finder将显示Chess.mov.app以防止用户考虑Chess.mov是QuickTime文件。

有关显示名称和指定本地化捆绑包名称的详细信息,请参阅文件系统概述。

捆绑的优点

软件包为开发人员提供以下优势:

因为bundle是文件系统中的目录层次结构,所以bundle只包含文件。因此,您可以使用所有相同的基于文件的界面打开包资源,以便打开其他类型的文件。
捆绑包目录结构可以轻松支持多个本地化。您可以轻松添加新的本地化资源或删除不需要的资源。

软件包可以驻留在许多不同格式的卷上,包括诸如HFS,HFS +和AFP之类的多种叉格式,以及UFS,SMB和NFS等单叉格式。
用户可以通过在Finder中拖动它们来安装,重新定位和删除软件包。
捆绑包也是包,因此被视为不透明文件,不太容易受到意外的用户修改,例如关键资源的删除,修改或重命名。
捆绑可以支持多种芯片架构(PowerPC,Intel)和不同的地址空间要求(32位/ 64位)。它还可以支持包含专门的可执行文件(例如,针对特定向量指令集优化的库)。
大多数(但不是全部)可执行代码可以捆绑。应用程序,框架(共享库)和插件都支持捆绑包模型。静态库,动态库,shell脚本和UNIX命令行工具不使用bundle结构。
捆绑的应用程序可以直接从服务器运行。不需要在本地系统上安装特殊的共享库,扩展和资源。

捆绑类型

虽然所有捆绑包都支持相同的基本功能,但是您可以定义和创建定义其预期用途的捆绑包的方式有所不同:

应用程序 - 应用程序包管理与可启动进程关联的代码和资源。该捆绑的确切结构取决于您定位的平台(iOS或MacOS)。有关应用程序包的结构的信息,请参阅应用程序包。
框架 - 框架包管理动态共享库及其相关资源,如头文件。应用程序可以链接一个或多个框架,以利用它们包含的代码。有关框架包的结构的信息,请参阅框架包的解剖。
插件 - macOS支持许多系统功能的插件。插件是一种应用程序动态加载自定义代码模块的方法。以下列表列出了您可能想要开发的插件的一些关键类型:
自定义插件是为您自己定义的插件;请参阅可卸载捆绑的解剖。
Image Unit插件为Core Image技术添加了自定义的图像处理行为;请参阅图像单元教程。
Interface Builder插件包含要与Interface Builder的库窗口集成的自定义对象。
首选项窗格插件定义要集成到“系统偏好设置”应用程序中的自定义首选项;请参阅“优先窗格编程指南”。
Quartz Composer插件定义了Quartz Composer应用程序的自定义修补程序;请参阅Quartz Composer自定义修补程序编程指南。
Quick Look插件支持使用Quick Look显示自定义文档类型;请参阅快速编程指南。
Spotlight插件支持自定义文档类型的索引,以便用户可以搜索这些文档;请参阅Spotlight导入器编程指南。
WebKit插件扩展了通用Web浏览器支持的内容类型。
窗口小部件将新的基于HTML的应用程序添加到仪表板。
虽然文档格式可以利用捆绑结构来组织其内容,但文档通常不被认为是最纯粹的捆绑包。实现为目录并被视为不透明类型的文档被认为是文档包,而不管其内部格式如何。有关文档包的详细信息,请参阅文档包。

创建捆绑包

在大多数情况下,您不会手动创建软件包或软件包。当您创建新的Xcode项目(或向现有项目添加目标)时,Xcode会在需要时自动创建所需的bundle结构。例如,应用程序,框架和可加载bundle目标都具有关联的bundle结构。当您构建任何这些目标时,Xcode会为您自动创建相应的软件包。

注意:某些Xcode目标(例如shell工具和静态库)不会导致创建捆绑包或包。这是正常的,不需要为这些目标类型专门创建软件包。为这些目标生成的生成的二进制文件旨在按原样使用。
如果您使用make文件(而不是Xcode)来构建项目,那么创建bundle并不奇怪。捆绑包只是文件系统中具有明确定义结构的目录,并将特定文件扩展名添加到捆绑包目录名称的末尾。只要您创建顶级捆绑包目录并适当地构建您的捆绑包的内容,就可以使用编程支持访问这些内容来访问捆绑包。有关如何组织捆绑包目录的更多信息,请参阅捆绑结构。

程序化支持访问捆绑包

引用捆绑包或本身捆绑的程序可以利用Cocoa和Core Foundation中的接口访问捆绑包的内容。使用这些接口,您可以找到捆绑资源,获取有关捆绑包配置的信息,并加载可执行代码。在Objective-C应用程序中,您可以使用NSBundle类来获取和管理包信息。对于基于C的应用程序,可以使用与CFBundleRef opaque类型相关联的函数来管理捆绑包。

注意:与许多其他Core Foundation和Cocoa类型不同,NSBundle和CFBundleRef不是自由的桥接数据类型,不能互换使用。但是,您可以从任一对象中提取捆绑路径信息,并使用它来创建另一个对象。
有关如何使用Cocoa和Core Foundation中的程序化支持访问软件包的信息,请参阅访问软件包的内容。

使用捆绑包的指南

软件包是MacOS和iOS软件的首选组织机制。捆绑结构允许您将可执行代码和资源分组在一个地方并以有组织的方式支持该代码。以下指南提供了有关如何使用软件包的一些额外建议:

始终在您的包中包含信息属性列表(Info.plist)文件。确保包含推荐使用的捆绑类型的密钥。有关可以包含在此文件中的所有密钥的列表,请参阅运行时配置指南。
如果应用程序无法在没有特定资源文件的情况下运行,请将该文件包含在应用程序包中。应用程序应始终包含他们需要操作的所有图像,字符串文件,本地化资源和插件。非关键资源应尽可能类似地存储在应用程序包中,但如果需要,可以将其放在bundle外部。有关应用程序捆绑结构的更多信息,请参阅应用程序包。
如果您计划从捆绑包中加载C ++代码,则可能需要将计划加载的符号标记为extern“C”。 NSBundle和Core Foundation CFBundleRef函数都不知道C ++名称的修改约定,所以以这种方式标记您的符号可以使以后更容易识别它们。
您不能使用NSBundle类来加载代码片段管理器(CFM)代码。如果需要加载基于CFM的代码,则必须使用CFBundleRef或CFPlugInRef不透明类型的函数。您可以使用这种技术从Mach-O可执行文件加载基于CFM的插件。
您应该始终使用NSBundle类(与CFBundleRef opaque类型相关联的函数)来加载包含Java代码的任何包。
在加载包含Objective-C代码的捆绑包时,您可以在macOS v10.5及更高版本中使用NSBundle类或与CFBundleRef opaque类型相关联的函数,但每种类型的行为都有差异。如果您使用Core Foundation函数来加载插件或其他可加载的bundle(而不是框架或动态共享库),那么这些函数将私有加载并立即绑定它的符号;如果您使用NSBundle,则该捆绑包将在全局加载,其符号将被懒惰绑定。另外,使用NSBundle类加载的bundle会导致生成NSBundleDidLoadNotification通知,而使用Core Foundation函数加载的bundle不会生成。

捆绑结构

捆绑结构可以根据捆绑类型和目标平台而有所不同。以下部分描述了macOS和iOS中最常用的捆绑结构。

注意:虽然捆绑是一种打包可执行代码的方法,但它们不是唯一支持的方法。 UNIX shell脚本和命令行工具不使用bundle结构,也不使用静态和动态共享库。

应用程序包

应用程序包是开发人员创建的最常见的捆绑类型之一。应用程序包存储应用程序成功运行所需的所有内容。虽然应用程序包的特定结构取决于您正在开发的平台,但在两个平台上使用捆绑包的方式都相同。本章介绍了iOS和MacOS中应用程序包的结构。

什么文件进入应用程序包?

表2-1总结了您可能在应用程序包中找到的文件类型。这些文件的确切位置因平台而异,一些资源根本不受支持。有关示例和更详细的信息,请参阅本章中特定于平台的软件包部分。

表2-1应用程序包中的文件类型
文件
描述
Info.plist文件
(必需)信息属性列表文件是包含应用程序配置信息的结构化文件。系统依赖于此文件的存在来识别有关您的应用程序和任何相关文件的相关信息。
可执行文件
(必需)每个应用程序必须具有可执行文件。该文件包含应用程序的主入口点和静态链接到应用程序目标的任何代码。
资源文件
资源是存在于应用程序的可执行文件之外的数据文件。资源通常由图像,图标,声音,nib文件,字符串文件,配置文件和数据文件(等)组成。大多数资源文件可以针对特定语言或区域进行本地化,也可以由所有本地化共享。
资源文件在捆绑包目录结构中的放置取决于您是开发iOS或Mac应用程序。

其他支持文件

Mac应用程序可以嵌入其他高级资源,如私有框架,插件,文档模板以及其他自定义数据资源,这些资源是应用程序的一部分。尽管您可以在iOS应用程序包中包含自定义数据资源,但不能包括自定义框架或插件。
虽然应用程序包中的大部分资源是可选的,但并不总是如此。例如,iOS应用程序通常需要额外的图像资源来应用程序的图标和默认屏幕。尽管未明确要求,但大多数Mac应用程序都包含一个自定义图标,而不是系统提供的默认图标。

iOS应用程序包的解剖

Xcode提供的项目模板可以为您的iPhone或iPad应用程序设置捆绑包所需的大部分工作。但是,了解捆绑结构可以帮助您确定应该放置自己的自定义文件的位置。 iOS应用程序的捆绑结构更符合移动设备的需求。它使用相对平坦的结构,几乎没有外部目录,以节省磁盘空间并简化对文件的访问。

iOS应用程序捆绑结构

典型的iOS应用程序包包含应用程序可执行文件和应用程序使用的任何资源(例如,应用程序图标,其他映像和本地化内容)在顶级捆绑包目录中。 清单2-1显示了一个名为MyApp的简单iPhone应用程序的结构。 子目录中唯一需要进行本地化的文件; 但是,您可以在自己的应用程序中创建其他子目录来组织资源和其他相关文件。

清单2-1 iOS应用程序的捆绑结构

MyApp.app
   MyApp
   MyAppIcon.png
   MySearchIcon.png
   Info.plist
   Default.png
   MainWindow.nib
   Settings.bundle
   MySettingsIcon.png
   iTunesArtwork
   en.lproj
      MyImage.png
   fr.lproj
      MyImage.png

表2-2所示的应用程序的内容如表2-2所示。 虽然应用程序本身仅用于演示目的,但其中包含的许多文件代表了iOS在扫描应用程序包时查找的特定文件。 您自己的软件包将包含部分或全部这些文件,具体取决于您支持的功能。

表2-2典型的iOS应用程序包的内容

文件
描述
MyApp
(必需)包含应用程序代码的可执行文件。该文件的名称与您的应用程序名称相同。减去.app扩展名。
应用程序图标(MyAppIcon.png,MySearchIcon.png和MySettingsIcon.png)
(必需/推荐)应用程序图标在特定时间用于表示应用程序。例如,不同大小的应用程序图标将显示在主屏幕,搜索结果和设置应用程序中。并不是所有的图标都是必需的,但大多数都是推荐的。有关应用程序图标的信息,请参阅应用程序图标和启动映像。
Info.plist
(必需)此文件包含应用程序的配置信息,例如其包ID,版本号和显示名称。有关详细信息,请参阅信息属性列表文件。
启动图像(Default.png)
(推荐)一个或多个图像,以特定方向显示应用程序的初始界面。系统使用所提供的启动映像之一作为临时背景,直到您的应用程序加载其窗口和用户界面。如果您的应用程序不提供任何启动映像,则应用程序启动时将显示黑色背景。有关应用程序图标的信息,请参阅应用程序图标和启动映像。
MainWindow.nib
(推荐)应用程序的主要nib文件包含在应用程序启动时加载的默认界面对象。通常,此nib文件包含应用程序的主窗口对象和应用程序委托对象的实例。然后,其他接口对象将从其他nib文件加载或由应用程序以编程方式创建。 (可以通过向Info.plist文件中的NSMainNibFile键分配不同的值来更改主nib文件的名称。有关详细信息,请参阅信息属性列表文件。)
Settings.bundle
“设置”包是一种特殊类型的插件,其中包含要添加到“设置”应用程序的任何特定于应用程序的首选项。此软件包包含属性列表和其他资源文件,以配置和显示您的首选项。
自定义资源文件
非本地化资源放置在顶级目录中,本地化资源放置在应用程序包的特定语言的子目录中。资源包括nib文件,图像,声音文件,配置文件,字符串文件以及您的应用程序所需的任何其他自定义数据文件。有关资源的更多信息,请参阅iOS应用程序中的资源。
注意:iOS应用程序包不能包含名为“资源”的自定义文件夹。
iOS应用程序应该国际化,并为其支持的每种语言提供一个language.lproj文件夹。除了提供应用程序的自定义资源的本地化版本之外,还可以通过在特定于语言的项目目录中放置具有相同名称的文件来本地化启动映像。但是,即使您提供本地化版本,应始终在应用程序包的顶层包含这些文件的默认版本。默认版本用于特定本地化不可用的情况。有关本地化资源的更多信息,请参阅捆绑包中的本地化资源。

信息属性列表文件

每个iOS应用程序必须具有包含应用程序配置信息的信息属性列表(Info.plist)文件。当您创建一个新的iOS应用程序项目时,Xcode会自动创建此文件,并为您设置某些关键属性的值。表2-3列出了您应该明确设置的其他一些键。 (Xcode在默认情况下遮盖实际的键名称,所以Xcode显示的字符串也列在括号中,可以通过在编辑器中单击信息属性列表键并选择显示来查看所有键的真实密钥名称来自上下文菜单中的原始键/值。)

表2-3 Info.plist文件所需的密钥



CFBundleDisplayName(Bundle显示名称)
捆绑显示名称是显示在应用程序图标下面的名称。对于所有支持的语言,此值应本地化。
CFBundleIdentifier(Bundle标识符)
捆绑标识符字符串将您的应用程序标识到系统。此字符串必须是仅包含字母数字(A-Z,a-z,0-9),连字符( - )和句点(。)字符的统一类型标识符(UTI)。字符串也应该是反向DNS格式。例如,如果您的公司的域名是Ajax.com,并且您创建一个名为Hello的应用程序,则可以将com.Ajax.Hello字符串分配为应用程序的包标识符。
捆绑标识符用于验证应用签名。
CFBundleVersion(Bundle版)
bundle版本字符串指定包的版本号。该值是单调增加的字符串,由一个或多个周期分隔的整数组成。此值无法本地化。
CFBundleIconFiles
包含用于应用程序各种图标的图像的文件名的字符串数组。虽然在技术上不需要,但强烈建议您使用它。
iOS 3.2及更高版本支持此键。
LSRequiresIPhoneOS(应用程序需要iOS环境)
一个布尔值,指示捆绑只能在iOS上运行。 Xcode自动添加此键并将其值设置为true。您不应该更改此键的值。
UIRequiredDeviceCapabilities
告诉iTunes和App Store的一个关键知道应用程序需要运行哪些设备相关功能。 iTunes和移动App Store使用此列表来阻止客户在不支持列出的功能的设备上安装应用程序。
该键的值是数组或字典。如果使用阵列,则给定键的存在表示需要相应的功能。如果您使用字典,则必须为每个键指定布尔值,以指示该功能是否必需。在这两种情况下,不包括键表示不需要该功能。
有关要包含在字典中的键的列表,请参阅信息属性列表键参考。 iOS 3.0及更高版本支持此键。
除了上表中的键之外,表2-4列出了iOS应用程序通常使用的一些键。虽然这些键不是必需的,但大多数提供了一种在启动时调整应用程序配置的方法。提供这些密钥可以帮助确保系统适当地呈现您的应用程序。

表2-4 Info.plist文件中通常包含的键

帕拉
帕拉
NSMainNibFile(主要nib文件名)
标识应用程序主nib文件名称的字符串。如果要使用除为项目创建的默认文件之外的nib文件,请将该nib文件的名称与此键相关联。 nib文件的名称不应包含.nib文件扩展名。
UIStatusBarStyle
一个字符串,用于标识应用程序启动时状态栏的样式。该值基于在UIApplication.h头文件中声明的UIStatusBarStyle常量。默认样式为UIStatusBarStyleDefault。应用程序可以在完成启动时更改此初始状态栏样式。
如果不指定此键,则iOS会显示默认状态栏。
UIStatusBarHidden
一个布尔值,用于确定应用程序启动时状态栏是否最初被隐藏。将其设置为true以隐藏状态栏。默认值为false。
UIInterfaceOrientation
标识应用程序用户界面初始方向的字符串。该值基于在UIApplication.h头文件中声明的UIInterfaceOrientation常量。默认样式为UIInterfaceOrientationPortrait。
UIPrerenderedIcon
一个布尔值,指示应用程序图标是否已经包含光泽和斜角效果。默认值为false。如果您不希望系统将这些效果添加到您的作品中,请将其设置为true。
UIRequiresPersistentWiFi
一个布尔值,通知系统应用程序使用Wi-Fi网络进行通信。在任何时候使用Wi-Fi的应用程序都必须将此键设置为true;否则,30分钟后,设备将关闭Wi-Fi连接以节省电量。设置此标志还允许系统知道当Wi-Fi可用但当前未被使用时,它应显示网络选择对话框。默认值为false。
即使此属性的值为true,当该设备空闲(即屏幕锁定)时,此密钥也不起作用。在此期间,应用程序被视为无效,尽管它可能在某种程度上起作用,但没有Wi-Fi连接。
UILaunchImageFile
包含应用程序启动映像使用的基本文件的字符串。如果不指定此键,则基本名称被假定为字符串Default。
应用程序图标和启动映像

应用程序图标和启动映像是必须存在于每个应用程序中的标准图形。每个应用程序必须指定要在设备的主屏幕和App Store中显示的图标。并且应用程序可以指定用于不同情况的几个不同的图标。例如,应用程序可以提供在显示搜索结果时使用的应用程序图标的小版本。启动图像向用户提供应用程序启动的视觉反馈。

用于表示图标和启动图像的图像文件必须都位于捆绑包的根级别中。如何将这些映像标识到系统可能会有所不同,但是建议的方法来指定应用程序图标是使用CFBundleIconFiles键。有关如何在应用程序中指定图标和启动图像的详细信息,请参阅iOS应用程序编程指南中的高级应用技巧中的这些项目的讨论。

注意:除了捆绑软件顶层的图标和启动映像之外,还可以在应用程序的语言特定项目子目录中包含启动映像的本地化版本。有关在应用程序中包含本地化资源的更多信息,请参阅捆绑包中的本地化资源。

iOS应用程序中的资源

在iOS应用程序中,非本地化资源位于捆绑包目录的顶层,以及应用程序的可执行文件和Info.plist文件。大多数iOS应用程序在此级别至少有几个文件,包括应用程序的图标,启动映像和一个或多个nib文件。尽管您应该将大多数非本地化资源放在此顶级目录中,但您也可以创建子目录来组织资源文件。本地化资源必须放置在一个或多个特定于语言的子目录中,这些子目录在捆绑软件的本地化资源中有更详细的讨论。

清单2-2显示了一个包含本地化和非本地化资源的虚构应用程序。非本地化资源包括Hand.png,MainWindow.nib,MyAppViewController.nib以及WaterSounds目录的内容。本地化资源包括en.lproj和jp.lproj目录中的所有内容。

清单2-2具有本地化和非本地化资源的iOS应用程序

MyApp.app/
   Info.plist
   MyApp
   Default.png
   Icon.png
   Hand.png
   MainWindow.nib
   MyAppViewController.nib
   WaterSounds/
      Water1.aiff
      Water2.aiff
   en.lproj/
      CustomView.nib
      bird.png
      Bye.txt
      Localizable.strings
   jp.lproj/
      CustomView.nib
      bird.png
      Bye.txt
      Localizable.strings

有关在应用程序包中查找资源文件的信息,请参阅访问软件包的内容。有关如何加载资源文件并在程序中使用它们的信息,请参阅资源编程指南。

macOS应用程序包解剖

Xcode提供的项目模板可以在开发过程中设置Mac应用程序包所需的大部分工作。但是,了解捆绑结构可以帮助您确定应该放置自己的自定义文件的位置。 macOS软件包使用高度有组织的结构,使捆绑加载代码更容易查找软件包中的资源和其他重要文件。层次性还有助于系统将代码捆绑包(例如应用程序与其他应用程序使用的目录包)区分开来实现文档类型。

macOS应用程序包的结构

Mac应用程序包的基本结构非常简单。在bundle的顶层是一个名为Contents的目录。此目录包含应用程序所需的所有资源,包括资源,可执行代码,私有框架,私有插件和支持文件。虽然Contents目录可能看起来很多,但它将该捆绑包标识为现代风格的捆绑包,并将其与早期版本的Mac OS中发现的文档和旧版捆绑类型分离。

清单2-3显示了典型应用程序包的高级结构,包括您最可能在Contents目录中找到的立即文件和目录。这个结构代表每个Mac应用程序的核心。

清单2-3 Mac应用程序的基本结构

MyApp.app/
   Contents/
      Info.plist
      MacOS/
      Resources/

表2-5列出了您可能在Contents目录中找到的一些目录,以及每个目录的目的。该列表并不详尽,但仅代表常用的目录。

表2-5目录目录的子目录
目录
描述
MacOS
(必需)包含应用程序的独立可执行代码。通常,此目录仅包含一个二进制文件,其中包含应用程序的主入口点和静态链接代码。但是,您也可以将其他独立的可执行文件(如命令行工具)放在此目录中。
资源
包含所有应用程序的资源文件。此目录的内容进一步组织起来以区分本地化和非本地化资源。有关此目录的结构的更多信息,请参阅资源目录
构架
包含可执行文件使用的任何私有共享库和框架。该目录中的框架是针对应用程序进行修订锁定的,不能被操作系统可用的任何其他甚至更新的版本所取代。换句话说,包含在该目录中的框架优先于在操作系统的其他部分中发现的任何其他类似命名的框架。
有关如何向应用程序包添加私有框架的信息,请参阅框架编程指南。
插件
包含可扩展的应用程序的基本功能的可加载捆绑包。您可以使用此目录来包含必须加载到应用程序进程空间中以便使用的代码模块。您不会使用此目录来存储独立的可执行文件。
SharedSupport
包含不影响应用程序运行能力的其他非关键资源。您可以使用此目录来包括应用程序期望存在的文档模板,剪贴画和教程,但不影响应用程序运行的能力。
多年来应用程序包已经发展很大,但总体目标是一样的。捆绑组织使应用程序更容易找到其资源,同时使用户更难干扰这些资源。由于Finder将大多数捆绑包视为不透明实体,因此临时用户很难移动或删除应用程序可能需要的资源。

信息属性列表文件

要使Finder能够识别应用程序包,您需要包含一个信息属性列表(Info.plist)文件。该文件包含XML属性列表数据,用于标识捆绑包的配置。对于最小的包,该文件将包含很少的信息,很可能只是包的名称和标识符。对于更复杂的软件包,Info.plist文件包含更多信息。

重要提示:使用区分大小写的搜索来定位捆绑资源。因此,您的信息属性列表文件的名称必须以资本“I”开头。
表2-6列出了您应该始终包含在Info.plist文件中的键。 Xcode在创建新项目时自动提供所有这些键。 (Xcode在默认情况下遮盖了实际的键名称,所以Xcode显示的字符串也列在括号中,您可以通过在编辑器中单击信息属性列表键并选择显示原始密钥/值来查看所有密钥的真实密钥名称从出现的上下文菜单。)

表2-6 Info.plist文件中的预期密钥

描述
CFBundleName(Bundle name)
捆绑的短名称。该键的值通常是应用程序的名称。创建新项目时,Xcode默认设置此键的值。
CFBundleDisplayName(Bundle显示名称)
应用程序名称的本地化版本。您通常在InfoPlist.strings每个语言特定资源目录中的文件中包含此密钥的本地化值。
CFBundleIdentifier(Bundle标识符)
将应用程序标识到系统的字符串。此字符串必须是仅包含字母数字(A-Z,a-z,0-9),连字符( - )和句点(。)字符的统一类型标识符(UTI)。字符串也应该是反向DNS格式。例如,如果您的公司的域名是Ajax.com,并且您创建一个名为Hello的应用程序,则可以将com.Ajax.Hello字符串分配为应用程序的包标识符。
捆绑标识符用于验证应用签名。
CFBundleVersion(Bundle版)
指定包的版本号的字符串。该值是单调增加的字符串,由一个或多个周期分隔的整数组成。该值可以对应于应用程序的已发布版本或未发行版本。此值无法本地化。
CFBundlePackageType(Bundle OS类型代码)
这是捆绑的类型。对于应用程序,此键的值始终为四个字符的字符串APPL。
CFBundleSignature(Bundle创建者操作系统类型代码)
捆绑的创建者代码。这是一个特定于包的四个字符的字符串。例如,TextEdit应用程序的签名是ttxt。
CFBundleExecutable(可执行文件)
主要可执行文件的名称。这是用户启动应用程序时执行的代码。 Xcode通常在构建时自动设置此键的值。
表2-7列出了您在Info.plist文件中应该考虑的键。

表2-7 Info.plist文件的推荐键

描述
CFBundleDocumentTypes(文档类型)
应用程序支持的文档类型。这种类型由一系列字典组成,每个字典提供有关特定文档类型的信息。
CFBundleShortVersionString(Bundle version string,short)
发布版本的应用程序。该键的值是由三个周期分隔的整数组成的字符串。
LSMinimumSystemVersion(最小系统版本)
运行该应用程序所需的最小版本的macOS。该键的值为n.n.n形式的字符串,其中每个n是表示所需的macOS的主版本号或次版本号的数字。例如,值10.1.5将代表macOS v10.1.5。
NSHumanReadableCopyright(版权(可读))
申请的版权声明。这是一个可读的字符串,可以通过将密钥包含在特定于语言的项目目录中的InfoPlist.strings文件中进行本地化。
NSMainNibFile(主要nib文件名)
启动应用程序时加载的nib文件(不带.nib文件扩展名)。主要的nib文件是一个Interface Builder存档,包含启动时所需的对象(主窗口,应用程序委托等)。
NSPrincipalClass(Principal类)
动态加载的Objective-C代码的入口点。对于应用程序包,这几乎总是NSApplication类或自定义子类。
您放入Info.plist文件的确切信息取决于您的软件包的需求,并可根据需要进行本地化。有关此文件的更多信息,请参阅运行时配置指南。

资源目录

资源目录是您放置所有图像,声音,nib文件,字符串资源,图标文件,数据文件和配置文件的位置。此目录的内容进一步细分为您可以存储本地化和非本地化资源文件的区域。非本地化资源驻留在Resources目录本身的顶层或您定义的自定义子目录中。本地化资源驻留在称为特定于语言的项目目录的单独子目录中,这些目录被命名为与特定本地化一致。

查看资源目录的最佳方式是查看一个例子。清单2-4显示了一个包含本地化和非本地化资源的虚构应用程序。非本地化资源包括Hand.tiff,MyApp.icns和WaterSounds目录的内容。本地化资源包括en.lproj和jp.lproj目录或其子目录中的所有内容。

清单2-4具有本地化和非本地化资源的Mac应用程序

MyApp.app/
   Contents/
      Info.plist
      MacOS/
         MyApp
      Resources/
         Hand.tiff
         MyApp.icns
         WaterSounds/
            Water1.aiff
            Water2.aiff
         en.lproj/
            MyApp.nib
            bird.tiff
            Bye.txt
            InfoPlist.strings
            Localizable.strings
            CitySounds/
               city1.aiff
               city2.aiff
         jp.lproj/
            MyApp.nib
            bird.tiff
            Bye.txt
            InfoPlist.strings
            Localizable.strings
            CitySounds/
               city1.aiff
               city2.aiff

您的每个语言特定的项目目录都应包含相同资源文件集的副本,并且所有本地化文件的任何单个资源文件的名称必须相同。换句话说,只有给定文件的内容才能从一个本地化到另一个本地化。当您在代码中请求资源文件时,只能指定所需文件的名称。捆绑加载代码使用用户的当前语言偏好来确定要搜索所请求的文件的目录。

有关在应用程序包中查找资源文件的信息,请参阅访问软件包的内容。有关如何加载资源文件并在程序中使用它们的信息,请参阅资源编程指南。

应用程序图标文件

您的顶级Resources目录中的一个特殊资源是您的应用程序图标文件。按照惯例,此文件采用包的名称和.icns的扩展名;图像格式可以是任何支持的类型,但如果没有指定扩展名,则系统假定为.icns。

本地化信息属性列表

因为应用程序的Info.plist文件中的某些键包含用户可见的字符串,所以macOS提供了一种用于指定这些字符串的本地化版本的机制。在每个特定于语言的项目目录中,您可以包括一个指定适当本地化的InfoPlist.strings文件。该文件是一个字符串文件(不是属性列表),其条目由要本地化的Info.plist键和适当的翻译组成。例如,在TextEdit应用程序中,该文件的德语本地化包含以下字符串:

CFBundleDisplayName = "TextEdit";
NSHumanReadableCopyright = "Copyright © 1995-2009 Apple Inc.\nAlle Rechte vorbehalten.";

创建应用程序包

创建应用程序包的最简单的方法是使用Xcode。所有新的应用程序项目都包括一个适当配置的应用程序目标,它定义了构建应用程序包所需的规则,包括要编译哪些源文件,哪些资源文件要复制到该包中,等等。新项目还包括预配置的Info.plist文件,通常还有几个其他文件可以帮助您快速入门。您可以使用项目窗口根据需要添加任何自定义文件,并使用Info或Inspector窗口配置这些文件。例如,您可以使用“信息”窗口为您的包中的资源文件指定自定义位置。

有关如何在Xcode中配置目标的信息,请参阅Xcode Build System Guide。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 框架捆绑 框架是封装动态共享库和支持该库所需的资源文件的分层目录。框架比典型的动态共享库提供了一些优势,因为它们为...
    nicedayCoco阅读 1,530评论 0 2
  • 关于首选项和设置 首选项是您持久存储的信息,并用于配置您的应用程序。应用程序通常会向用户公开偏好设置,以便他们自定...
    nicedayCoco阅读 899评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 关于资源 适用于计算机程序的资源是与程序可执行代码相关的数据文件。资源可以通过将代码之外的复杂数据集或图形内容创建...
    nicedayCoco阅读 574评论 0 0
  • 关于iOS应用程序架构 应用程序需要与iOS一起工作,以确保他们提供出色的用户体验。 除了为您的应用程序的设计和用...
    nicedayCoco阅读 1,147评论 0 1