iOS工程持续集成(解析xcodeproj),对工程进行代码,资源,库动态添加

javascript/jquery

浏览数:38

2020-6-12

AD:资源代下载服务

  下面介绍一下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];

完成后, 效果如下:

示例已说完,还有更多的理解点,这里就不提了。 对这方面有兴趣的话,欢迎一起讨论。

作者:肖XX