下面介绍一下pbxproj文件,可以拖动.xcodeproj文件到文本编辑器,如xcode 打开,查看pbxproj文件的组成方式,这次主要介绍几个 PBXFileReference PBXBuildFile PBXGroup:
首先,我得说的是每一个节点,前面都配上一个UUID的,然后必须会有一个叫isa的属性来标识这个节点属于什么类型,这个值可以是任意英文或者数字,不过必须是24位。
PBXFileReference
其实这个就是资源文件的引用,任何资源都可以,其节点包含文件的类型,路径,名称等
/* Begin PBXFileReference section */ F60CC2A014D4EA0500A005E4 /* SocketOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocketOperation.m; sourceTree = "<group>"; };/* End PBXFileReference section */
其中的重点节点属性我解析一下:
name:这个是代表在xcode 工程里的显示名称
path:这个是xcode 工程可以找到该文件的路径,这路径还需要配合上sourceTree这个属性的, 一般默认值为
"<group>",这个值代指会在当前目录下(这个目录指的是放到PBXGroup所指定的path路径哦),如果是"SOURCE_ROOT",则代指是从工程的目录下去寻找。
sourceTree:这个我上面都讲清楚, 一般默认值为:"<group>":
fileEncoding:这个值,一般是针对文本文件的,一般为4, 代表utf-8 ,如果是代码文件,就不能赋值了。
lastKnownFileType:这个值是重点,它根据不同类型的文件,分成以下几个值:
text.json,text.xml: 这个我觉得不用说了吧, 是文本还是json文件就使用这个值
image.bmp,image.png, image.jpeg : 图片的取值
text.plist.strings,text.plist.strings: ios 的特定文件, strings plist的取值
wrapper.plug-in: 这个是后缀名为.bundle 的取值
sourcecode.c.h: 这个是h文件的取值
sourcecode.c.objc: 这个是代码文件的取值,
wrapper.framework: 这个是后缀名为.framework 的取值
archive.ar: 这个是静态编译库, 后缀名为.a的取值, 这个可是记要点哦。 如果加载静态库不设置这个值,工程只会把它当作是普通文件来使用。
file:如果你不知道这个类型, 就设置这个值吧。
PBXBuildFile
这个section主要就是针对工程需要编译的文件了,当你通过PBXFileReference 引用后,不代表代码就会编译了, 必须要在这里添加相应的节点才行
/* Begin PBXBuildFile section */ F60CC2A114D4EA0500A005E4 /* SocketOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F60CC2A014D4EA0500A005E4 /* SocketOperation.m */; };/* End PBXBuildFile section *//* Begin PBXFileReference section * F60CC2A014D4EA0500A005E4 /* SocketOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SocketOperation.m; sourceTree = "<group>"; };/* End PBXFileReference section */
其中的重点节点属性我解析一下:
fileRef:这个值是PBXFileReference 所对应的uuid。
PBXGroup
这个section保存着工程文件的分组信息:分组的名称,以及该组内含有的文件,比如下面的例子,一个TestChat分组里面还有一个Supporting Files子分组,同时该组包含AppDelegate的.h和.m两个文件,该分组对应的路径为TestChat:
* Begin PBXGroup section */ F62417EA14D52F3C003CE997 /* TestChat */ = { isa = PBXGroup; children = ( F62417EB14D52F3C003CE997 /* Supporting Files */, F62417F314D52F3C003CE997 /* AppDelegate.h */, F62417F414D52F3C003CE997 /* AppDelegate.m */, ); path = TestChat; sourceTree = "<group>"; };/* End PBXGroup section */
PBXNativeTarget
该section保存工程创建的target信息:包含target的对应的配置信息、创建规则、依赖、名称和类型等信息
/* Begin PBXNativeTarget section */CAC8612E08B161103B6C9DC7 /* UIModuleExample */ = { isa = PBXNativeTarget; buildConfigurationList = 56006E5E8040DE2B3965BE91 /* Build configuration list for PBXNativeTarget "UIModuleExample" */; buildPhases = ( 58D3152C3900AA8B62A79D47 /* Sources */, A5BF724742232AA0E86F3339 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = UIModuleExample; productName = UIModuleExample; productReference = 377070E96E22438316AB8879 /* UIModuleExample.app */; productType = "com.apple.product-type.application"; };/* End PBXNativeTarget section */
XCBuildConfiguration XCConfigurationList
这两个section保存着工程相关的配置信息:下面对应的是debug模式下的配置信息,可以看到里面包含CODE_SIGN_IDENTITY,sdk,framework的搜索路径等信息。
/* Begin XCBuildConfiguration section */ F62417FD14D52F3C003CE997 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\"$(DEVELOPER_FRAMEWORKS_DIR)\"", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "TestChat/TestChat-Prefix.pch"; INFOPLIST_FILE = "TestChat/TestChat-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; name = Debug; };/* End XCBuildConfiguration section */
通过上面分析一个pbxproj文件的过程可以看出,要创建一个工程,首先需要添加相关的文件,然后设置需要生成的target以及对应的配置信息就行了。
费话不多了。 其实这个工程看起来好像挺复杂,但原理还是很容易能摸透的。首先,它很像json ,但很肯定它不是。不过我们依然可以用序列化成对象的方式去实现。我自己上传了一个解析pbxproj 的工程类:http://git.oschina.net/xiaochang/XcodeprojParser
里面有代码,也有对应好的示例:
下载后, 打开demo目录下的Demo.xcodeproj,如下图:
//工程解析器 XCodeProjParser* parser=[[XCodeProjParser alloc] init]; NSError* error=nil; //解析成一个XCodeProjectModel的对象 XCodeProjectModel* model=[parser load:[NSString stringWithContentsOfFile:@"/Users/fanty/Desktop/BSLBundleModifyProject/demo/Demo.xcodeproj/project.pbxproj" encoding:NSUTF8StringEncoding error:nil] error:&error]; //对这个模型进行文件添加 XCodeProjEditer* editer=[[XCodeProjEditer alloc] initWithProject:model]; //清空工程这个组的所有内容 [editer removeItemAtDirectory:@"Demo/NewGroup"]; //添加头文件 [editer appendHeaderFile:@"Demo/NewGroup/Hello.h"]; //添加代码文件 [editer appendSourceFile:@"Demo/NewGroup/Hello.m"]; //添加静态文件 [editer appendLibraryFile:@"Demo/NewGroup/libPushSDK-1.8.8.a"]; //添加plist文件 [editer appendResourceFile:@"Demo/NewGroup/PushConfig.plist"]; //保存 [[model parserToJSON] writeToFile:@"/Users/fanty/Desktop/BSLBundleModifyProject/demo/Demo.xcodeproj/project.pbxproj" atomically:YES encoding:NSUTF8StringEncoding error:nil];
完成后, 效果如下:
示例已说完,还有更多的理解点,这里就不提了。 对这方面有兴趣的话,欢迎一起讨论。