每種IDE都有自己特定的工程結(jié)構(gòu),Xcode也不例外, 它的工程描述文件都在.codeproj中, 這是一個目錄, 里邊包含一個主要的文件:project.pbxproj。 大家對這個文件都不會陌生, 每次合并代碼的時候, 最擔(dān)心的噩夢就是這個文件的沖突。要避免或者解決這些沖突的第一步, 就是先了解這個文件的結(jié)構(gòu)。
project.bpxproj
project.pbxproj其實就是一個JSON, 只不過帶上了一些注釋,便于理解而已。為了簡單, 我們忽略掉一些無關(guān)緊要的字段, 我們發(fā)現(xiàn), 這個JSON其實是一個樹形結(jié)構(gòu):

project.pbxproj主要包含兩個子節(jié)點:objects 和 rootObject.
objects是包含所有節(jié)點的字典, rootObject指向objects中的PBXProject節(jié)點。
PBXProject
從上圖可以看到, 這個節(jié)點有四個主要節(jié)點(子樹):
- buildConfigurationList, 對應(yīng)編譯參數(shù)設(shè)置。
- mainGroup, 對應(yīng)工程文件結(jié)構(gòu)。
- projectReferences, 工程之間的引用關(guān)系。
- targets, 每一個target對應(yīng)一個product輸出, target用來管理這個product的編譯參數(shù)以及需要編譯的文件。
PBXGroup
這個就是我們在Xcode窗口左側(cè)看到的樹形結(jié)構(gòu)。主要就是用來組織工程所包含的文件的結(jié)構(gòu)。
PBXGroup可以有多種類型子節(jié)點:
- PBXGroup
- PBXFileReference, 普通文件, 比如圖片資源, 代碼文件, framework, 子工程等。
- PBXReferenceProxy, 指向子工程編譯出來的文件(子工程product目錄下的
.a,.bundle等) - PBXVariantGroup, 指向放在
.lproj中的本地化文件, 比如.strings等。
XCConfigurationList
這個主要就是build settings界面內(nèi)容。 分別可以設(shè)置 project 和 target的編譯選項。
project references
這個配置工程所依賴的其他工程。
每個工程依賴包含兩個部分:
- ProductGroup: 指向所依賴的工程的productRefGroup
- ProjectRef: 指向代表該依賴工程的PBXFileReference
targets
target也是一個重要的子樹。
主要包含以下三部分(子樹):
- buildConfigurationList: 該target的編譯選項配置
- dependencies: 該target依賴的其他 target / 子工程 信息。
- buildPhases: 該target編譯需要的文件信息, 比如源碼, 資源, 庫等。
一些主要/特殊Object
PBXFileReference
每個file reference節(jié)點代表一個文件, 因此如果有多個file reference節(jié)點指向同一個物理文件, 那么這些節(jié)點可以合并成一個。
有些特殊目錄也可以是一個file reference, 比如.xib, .assets, .bundle, .framework等。
PBXVariantGroup
同file reference. 一個目錄下,多個.lproj 子目錄下的同名文件可以視為同一個文件的不同語言版本。 因此一個本地化文件應(yīng)該只存在一個 variant group, 多余的應(yīng)該合并。
PBXReferenceProxy
同file reference. 只不過代表的是本工程引用的另外一個工程。它通過remoteRef屬性指向一個 PBXContainerItemProxy節(jié)點(proxyType=2)。
PBXBuildFile
設(shè)置file reference (包括PBXVariantGroup, PBXReferenceProxy等) 的編譯設(shè)置, 比如-fno-arc等。
同一個file reference, 在不同的target里邊, 分別對應(yīng)多個build file, 可以設(shè)置不同的編譯參數(shù)。 因此, 如果在同一個target里邊,如果有多個build file指向一個file reference, 那么可以認(rèn)為這些build file是重復(fù)的。
PBXContainerItemProxy
目前發(fā)現(xiàn)有兩種proxyType:
- proxyType=1: 用于代理主工程target對子工程target的編譯依賴。顯示在Xcode窗口右側(cè)build phase->Target Dependencies中。
- proxyType=2: 用于代理子工程(或者本工程其他target)編譯結(jié)果文件(
.a,.bundle等)的文件依賴, 也就是會顯示在xcode窗口左側(cè)的文件樹中。
主要屬性:
- containerPortal: 指向代表子工程的PBXFileReference節(jié)點。
- remoteGlobalIDString:
- 當(dāng)proxyType=1時, 指向子工程的target節(jié)點(被依賴的target)
- 當(dāng)proxyType=2時, 指向另一個target(子工程或者本工程)的編譯輸出文件。
因此, 如果有兩個PBXContainerItemProxy節(jié)點, containerPortal和remoteGlobalIDString都相同, 那么可以認(rèn)為這倆節(jié)點是重復(fù)的。
工具
Github 地址: https://github.com/alexlee002/XcodeScripts
功能:
- project.pbxproj 文件解析與修改接口。
- project.pbxproj 優(yōu)化(節(jié)點校驗, 無效節(jié)點清除,重復(fù)節(jié)點清楚等)
開發(fā)中:
- project.pbxproj版本沖突自動解決功能。