理解 Xcode 中的各种文件
上一篇文章我们介绍了 Xcode 中的各种概念,本文我们来看看这些概念在
Xcode 中的具体表示。其中,有一个最常见的文件
project.pbxproj
,其描述了描述了整个 Xcode Project
的相关信息,包括:文件、Target、Product 等。另外,Xcode Workspace 则使用
contents.xcworkspacedata
进行描述,主要描述了其所包含的
Project 的位置。Xcode Scheme 则使用 .xcscheme
后缀的文件进行描述。
下面,我们来对这几个文件分别进行介绍。
project.pbxproj
Xcode Project 使用 project.pbxproj
来描述一个 Xcode
工程所包含的所有内容,包括文件、配置、库等,其存储在 Xcode 工程文件
*.xcodeproj
中。
文件格式
project.pbxproj
是一种旧风格的 Property List 文件(简称
plist
)。Property List 与 JSON
最主要的区别在于数组和字典的表示:
- 数组:使用小括号表示,数组元素使用逗号进行分隔
- 字典:使用大括号表示,键和值之间使用等号链接
1 | # plist 数组 |
对象关系
本质上,project.pbxproj
是一个对象关系图,所有的对象都与
Xcode 中的某个文件、配置、操作相对应,每一个对象都使用一个 96
bit(24 位的十六进制)的UUID 进行唯一标识,如下所示。
1 | 00004989A1D96C5B52A8E09B8A3BC4B5 /* DoraemonFPSPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B3712CE0D0A78D8379015D4C5647631 /* DoraemonFPSPlugin.h */; settings = {ATTRIBUTES = (Project, ); }; }; |
project.pbxproj
整体构成了一个树状的对象关系图,其类图大体如下所示。Xcode
中的各种概念大多数在类图中能够找到对应的类,比如:
- Project 对应 PBXProject
- Build Configuration 对应 XCBuildConfiguration
- Target 对应 PBXTarget
Root Element
project.pbxproj
Root Element
作为整个对象树的根节点。通过 rootObejct
为键引用一个
PBXProject
对象。objects
则定义了整个 project
中的所有相关文件。
PBXProject
PBXProject
定义了一个编译配置列表对象
buildConfigurationList
,该对象中定义了一组
XCBuildConfiguration
,其中每一个
XCBuildConfiguration
定义了一系列的 build settings。
关于文件的组织和维护,PBXProject
以
mainGroup
为键引用了一个 PBXGroup
对象。PBXGroup
对应 Xcode 中的 Group 的概念,类似于
Folder,但有所区别,主要用于 Xcode
中组织管理源文件。mainGroup
定义了文件组织结构的根节点,通过层层递进,可以索引到工程中的所有文件。
当然,PBXProject
还定义了一系列的
PBXTarget
。这里的 PBXTarget
对应上述的 Xcode
Target。
PBXTarget
类图中定义的 PBXTarget
是一个抽象类,其主要有以下几种具体类型:
PBXNativeTarget
:一次构建一个 target。Xcode 项目中最常用的 target。PBXLegacyTarget
:通过命令行进行构建。如果一个 project 的依赖项需要通过make
来构建,那么应该使用这种 target。PBXAggregateTarget
:同时构建多个 target,也可以用于执行不输出 product 的场景。
这些具体类型的 target,比如
PBXNativeTarget
,引用了一系列的
PBXBuildRule
、PBXBuildPhase
,还定义了输出的
product 的相关信息。
当然,这些 target 还引用了一组
XCBuildConfiugration
,XCBuildConfiguration
中通过 baseConfigurationReference
引用了 project 级别的
XCBuildConfiguration
,从而进行继承或覆盖。
PBXTarget
还定义了一组
PBXTargetDependency
,即上述提到的如果 target A 依赖了
target B,那么 target B 就是 target A 的一个依赖项。
PBXBuildPhase
PBXBuildPhase
也是一个抽象类,其主要包含 7
种具体类型,正好与 Xcode 中的 7 种 build phase 相对应:
PBXHeadersBuildPhase
:对应 Headers PhasePBXSourcesBuildPhase
:对应 Compile Sources PhasePBXFrameworksBuildPhase
:对应 Link Binary With Libraries PhasePBXCopyFilesBuildPhase
:对应 Copy Files PhasePBXShellScriptBuildPhase
:对应 Run Script PhasePBXResourcesBuildPhase
:对应 Copy Bundle Resources PhasePBXRezBuildPhase
:对应 Build Carbon Resources Phase
PBXBuildFile
project.pbxproj
使用 PBXBuildFile
表示构建文件,其定义了以下五种类型的文件引用。
PBXFileReference
PBXGroup
PBXReferenceProxy
PBXVariantGroup
XCVersionGroup
这里提到了 group 的概念,group 和 folder 是存在区别的,主要有以下两方面:
- Group 只在工程一般是文件夹的形式,但是在本地的目录还是以散乱的形式放在一起,除非是从外部以 group 的形式引用进来,这种情况下的 group 同时是一个文件夹实体。
- Folder 只能作为资源,folder 下的所有内容都会引入项目,不会被编译。也就是说,以 folder 形式引用进来的文件,不能被放在 compile sources 列表中。
contents.xcworkspacedata
Xcode Workspace 使用 contents.xcworkspacedata
来描述
workspace 中 project 的组成。如下所示,一个 workspace 包含两个
project,分别是:Demo.xcodeproj
和
Pods/Pods.xcodeproj
。
1 | <?xml version="1.0" encoding="UTF-8"?> |
.xcscheme
Xcode Scheme 使用 .xcscheme
后缀的 XML
文件进行描述,其存储在 xcshareddata
目录下。Xcode Scheme
默认定义了 6 种操作,如下图所示。
对应在 .xcscheme
文件中,同样定义了这 6 个默认
action,如下所示。每个操作中具体定义相关的 build
configuration、arguments、options 等信息。
1 | <?xml version="1.0" encoding="UTF-8"?> |
BuildableReference
.xcscheme
每一个 action 的依赖被定义在
BuildableReference
中。如果有一个 action 中包含了
BuildableReference
,那么就意味着 Build Action 被作为当前
action 的依赖,首先被执行。在 .xcscheme
中,同一个
BuildableReference
可能会被包含多次,从而引用同一个
target。这里使用 UUID 来引用一个 target,由
BlueprintIdentifier
指定。这里的 UUID 对应的 target 定义在
project.pbxproj
文件中。如下所示,是一个
BuildableReference
的示例。
1 | <BuildableReference |
Actions
Xcode Scheme 中的 action 中只有 Build Action 可以引用多个
target。因此,它在 BuildActionEntries
中包含了一个
BuildableReferences
列表,这些列表项引用了 target
所指定的显式依赖项。这些依赖项来源于 Target Dependencies 或 Link Binary
With Library。对于其他的 action,它们会将
BuildableReference
嵌套在其内部,如果需要的话。
此外,每一个 action 都有这不同的配置选项,如下所示。所有的 action
都有 pre-actions
和 post-actions
,它们可以在主
action 执行之前执行。相对来说,Analyze 和 Archive 的选项最少,Launch
的选项最多。
Options
所有的 action 都有相关的选项,它们会以属性的形式存储在 Action 中,如下所示。
1 | <LaunchAction |
Pre-Actions & Post-Actions
Pre-Actions 和 Post-Action 主要有两种类型:
- 发送邮件
- 运行脚本
对于 Send Email Action,它会打开 Mail.app 并发送邮件,如下所示。
1 | <ExecutionAction |
对于 Script Action,它可以运行任何脚本。类似于
PBXShellScriptBuildPhase
,脚本会被包含在
.xcscheme
文件中。默认,脚本会在构建目录下运行。因此,如果我们想修改 workspace
的内容,则可以运行 cd ${SRCROOT}
,如下所示。
1 | cd ${SRCROOT} |
1 | <ExecutionAction |
总结
本文我们简单地介绍了一下 Xcode
中的三个文件:project.pbxproj
、contents.xcworkspacedata
、.xcscheme
。后两个文件分别描述了
workspace 和 scheme 的具体信息。project.pbxproj
则包含了除此之外的所有信息,包括:target、product、files、build
configuration 等等。
了解了 Xcode 中的概念和文件之后,我们可以针对特定场景对这些文件进行修改、适配,从而解决特定问题。