iOS持續整合:命令列建立工程
在開發iOS應用的時候,大部分都是直接採用Xcode進行開發,但有時候需要用命令列來建立工程,比如最近在做ci的持續整合,就只能通過命令列的方式,這時候就需要瞭解一下工程檔案的構成。我們知道工程檔案的相關資訊儲存在project.pbxproj,因此可以通過指令碼建立出pbxproj檔案,完成基礎工程的建立。
pbxproj
下面介紹一下pbxproj檔案,可以拖動.xcodeproj檔案到文字編輯器,如sublime,查看pbxproj檔案的組成方式,主要包括:
* PBXBuildFile PBXFileReference
這兩個section儲存中工程檔案相關的資訊:包含檔案的類型,路徑,名稱等
/* 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 = ; };/* End PBXFileReference section */
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 = ; };/* 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以及對應的配置資訊就行了。
命令列產生pbxproj
上面大概瞭解了一個pbxproj檔案的整體構造,要想產生一個這樣的檔案,可以自己按照對應的格式書寫,或者藉助一些指令碼工具,這裡推薦cocoapods的Xcodeproj,項目的地址:Xcodeproj ,該工具是用ruby語言實現的,可以用它來修改和建立pbxproj檔案,下面是自己用ruby產生project檔案的一部分範例程式碼:
#建立 Example.xcodeproj工程檔案,並儲存 Xcodeproj::Project.new(./Example.xcodeproj).save #開啟建立的Example.xcodeproj檔案 proj=Xcodeproj::Project.open(./Example.xcodeproj) #建立一個分組,名稱為Example,對應的路徑為./Example exampleGroup=proj.main_group.new_group(Example,./Example) #給Example分組添加檔案引用 exampleGroup.new_reference(AppDelegate.h) ref1=exampleGroup.new_reference(AppDelegate.m) ref2=exampleGroup.new_reference(Images.xcassets) exampleGroup.new_reference(Base.lproj/LaunchScreen.xib) #在Example分組下建立一個名字為Supporting Files的子分組,並給該子分組添加main和info.plist檔案引用 supportingGroup=exampleGroup.new_group(Supporting Files) ref3=supportingGroup.new_reference(main.m) supportingGroup.new_reference(Info.plist) #建立target,主要的參數 type: application :dynamic_library framework :static_library 意思大家都懂的 #name:target名稱 #platform:平台 :ios或者:osx target = proj.new_target(:application,Example,:ios) #添加target配置資訊 target.build_configuration_list.set_setting('INFOPLIST_FILE', $(SRCROOT)/Example/Info.plist) #target添加相關的檔案引用,這樣編譯的時候才能引用到 target.add_file_references([ref1,ref2,ref3]) testGroup=proj.main_group.new_group(ExampleTests,./ExampleTests) ref4=testGroup.new_reference(ExampleTests.m) supportingGroup=testGroup.new_group(Supporting Files) supportingGroup.new_reference(Info.plist) #建立test target testTarget = proj.new_target(:unit_test_bundle,ExampleTests,:ios,nil,proj.products_group) testRefrence = testTarget.product_reference testRefrence.set_explicit_file_type('wrapper.cfbundle') testRefrence.name = ExampleTests.xctest testTarget.add_file_references([ref4]) #儲存 proj.save