簡介
本文主要介紹這樣的一種項目結(jié)構(gòu):整個工程以一個Workspace來管理忘巧,這個Workspace中包含一到多個Project门坷,一個Project中包含一到多個Target续搀,每個Target可以輸出一個靜態(tài)庫(Framework)或者App嵌洼。
這樣做的好處是:多Project的模式可以更方便的解耦和組件化自己的項目,將一些可以復(fù)用到其他項目中的模塊作為一個單獨的Framework(如網(wǎng)絡(luò)層、數(shù)據(jù)庫層寂汇、分享模塊等等),方便的提供給多個項目使用捣染,也更方便在App項目中進行調(diào)試骄瓣;多Target的模式可以快速創(chuàng)建相似度較高的馬甲App(或者iPhone版和iPad版),或者Framework項目中耍攘,對于不同的使用者有不同的定制化需求時榕栏,可以方便的定制化和管理。
創(chuàng)建Workspace
首先創(chuàng)建項目文件夾蕾各,這里命名為MultiTargetSample
在Xcode中點擊File -> New -> Workspace扒磁,或者使用快捷鍵Ctrl+Cmd+N創(chuàng)建Workspace,這里命名為MTSample
Workspace創(chuàng)建完成之后式曲,Xcode會自動打開這個空的Workspace
向Workspace中添加Project
使用快捷鍵Shift+Cmd+N創(chuàng)建Project妨托,選擇Single View App,點擊Next
此處將項目名命名為MTProject
按照下圖中進行配置检访,創(chuàng)建的Project需要位于剛才創(chuàng)建的MultiTargetSample文件夾下始鱼,同時需要添加到剛才創(chuàng)建的Workspace中
向Workspace中添加Framework
我們開發(fā)時經(jīng)常會遇到有一部分代碼在其他項目中也會用到,總是復(fù)制粘貼也很不方便脆贵,而且如果有修改也需要維護多份代碼医清,這時候我們可以通過將其抽離出來做成靜態(tài)庫(.framework或.a),但是這同樣有不方便的地方卖氨,比如每次更新都需要重新編譯(且模擬器編譯的只能在模擬器上運行会烙,真機同理,還需要通過終端命令來合并筒捺,下文會有詳細描述)且重新導(dǎo)入項目柏腻,而且很不方便調(diào)試(靜態(tài)庫的.m文件是不公開的)。
這時候如果有一種辦法能夠既方便其他項目集成系吭,又能方便調(diào)試塔拳,那就太好了,下面就介紹怎樣在一個Workspace中添加Framework項目朽缎。
當然舅锄,并不只是這一種方法,我們還可以將代碼抽離出來做成動態(tài)庫则吟,提交到SVN或Git服務(wù)器上槐臀,然后通過Cocoapods引入,就像我們引入AFNetworking一樣氓仲!不過這種方法在本文中不做介紹水慨,后續(xù)會有一篇單獨的文章說明得糜。而且,它也會使用本文中所介紹的項目結(jié)構(gòu)
- 同樣使用快捷鍵Shift+Cmd+N晰洒,此時選擇Cocoa Touch Framework朝抖,然后點擊Next。如下圖所示:
此處將Framework命名為MTFramework
按照與Project一樣的配置欢顷,將Framework添加到Workspace中
- 修改Mach-O Type槽棍。在Build Setting中搜索Mach,然后修改為Static Library
在Build Phases -> Headers -> Public中管理需要暴露的頭文件抬驴,未被暴露的頭文件將不能被別的項目引用
在MTProject中添加依賴MTFramework:首先需要切換到MTProject的Target下炼七,然后點擊Linked Frameworks and Libraries下的加號,在彈出的窗口中選擇MTFramework布持,點擊Add
- 此時MTProject在編譯的時候?qū)瑫r編譯MTFramework豌拙,并且可以使用MTFramework中暴露出的頭文件。而MTFramework本身也是一個獨立的工程题暖,可以隨時將該工程集成到別的Workspace中按傅,也可以在Xcode的Scheme中選擇MTFramework并編譯,將編譯后生成的MTFramework.framework提供給別的工程使用
- 合并模擬器編譯的Framework和真機編譯的Framework胧卤。(注意:此條僅在需要將編譯后的Framework提供給別的項目使用時才需要唯绍,在當前文章內(nèi)的項目結(jié)構(gòu)中不需要如此,因為在編譯或運行MTProject的時候會自動編譯其依賴的MTFramework)
單獨編譯MTFramework項目時枝誊,需要在模擬器和真機環(huán)境下各編譯一次(真機環(huán)境編譯的只能在真機環(huán)境運行况芒,模擬器同理),然后在Products下的MTFramework.framework上右鍵叶撒,選擇show in finder绝骚,可以看到模擬器和真機編譯生成的framework。
合并模擬器和真機的編譯文件需要使用終端命令祠够,且合并的并不是MTFramework.framework本身压汪,而是其內(nèi)部的MTFramework二進制文件。命令如下:
lipo -create 第一個framework下二進制文件的絕對路徑 第二個framework下二進制文件的絕對路徑 -output 最終的二進制文件路徑
此處輸出的二進制文件路徑設(shè)置的與真機環(huán)境編譯的二進制文件路徑一致古瓤,會自動替換掉原來的文件止剖,如上圖所示,如果命令執(zhí)行完成之后沒有任何信息落君,說明執(zhí)行成功穿香,此時的MTFramework.framework將可以同時在真機和模擬器環(huán)境使用。
向Workspace中的Project和Framework添加Cocoapods
- 首先在MTSample.xcworkspace的同級目錄下創(chuàng)建podfile文件(podfile沒有后綴名)叽奥,下面是示例的podfile文件內(nèi)容
platform :ios, '8.0'
# 如果項目中使用了Swift語言,則此句必須添加
use_frameworks!
# 設(shè)置pods的工作目錄為Workspace
workspace 'MTSample.xcworkspace'
# 此處使用宏定義了公用的一些第三方庫痛侍,方便在多個target中使用
def common_pods
pod 'Masonry'
end
target 'MTProject' do
# 配置MTProject target工作的相對路徑
project 'MTProject/MTProject.xcodeproj'
# 此處使用了上面定義的宏
common_pods
end
target 'MTFramework' do
# 配置MTFramework target工作的相對路徑
project 'MTFramework/MTFramework.xcodeproj'
common_pods
end
- 打開終端 -> cd到MultiTargetSample目錄下 -> pod install朝氓,pod安裝完成后魔市,需要重新打開MTSample.xcworkspace。pods安裝完成后的MultiTargetSample目錄結(jié)構(gòu)如下:
向Project中添加多個target
開發(fā)時有時會遇到兩個或多個項目相似度很高赵哲,代碼幾乎完全一致的情況待德,比如iPhone版和iPad版,可能只是幾個特定頁面的UI不同枫夺;或者有需求要做幾個相似度很高的App将宪,俗稱馬甲包。
如果我們用多個項目來開發(fā)橡庞,維護的時候?qū)浅2环奖憬咸常@時我們可以通過在一個Project中建立多個Target的方式來解決這個問題,每個Target只維護其與其他不同的地方扒最,比如UI丑勤、圖片資源、獨有的特定功能等吧趣,相同的地方可以通過采用上文中提到的Framework的形式或者只是將這部分代碼抽離出來放在Project的公共部分法竞,以供所有的Target使用。
本文只介紹Single View App類型的Target强挫,其他諸如Widget之類的不在此處介紹岔霸。
添加Target有兩種方式,一種是通過復(fù)制現(xiàn)有的Target俯渤,然后修改配置實現(xiàn)呆细;另一種是完全新建一個Target。下面以復(fù)制Target的方式為例介紹稠诲。
Framework項目也可以添加多個Target侦鹏,用處體現(xiàn)在比如不同的項目在接入這個Framework時有不同的需求,此時可以使用多個Target來管理臀叙,多個Target之間共用一套核心代碼略水,各個Target僅維護與其他Target不同之處。
復(fù)制現(xiàn)有Target
在現(xiàn)有的MTProject的Target上右鍵劝萤,選擇Duplicate(或者直接快捷鍵cmd+D)
在彈出的窗口中選擇Duplicate Only或者Duplicate and Transition to iPad(根據(jù)實際情況渊涝,如果是做iPad版則可以選擇后者,本文此處選擇了Duplicate Only)床嫌,之后會出現(xiàn)一個MTProject copy的Target跨释。復(fù)制出來的Target與之前的除名字外完全一致,所以需要手動修改一些配置
首先修改一下bundleID和證書厌处,這里不做詳細介紹鳖谈。
-
MTProject copy的名字看起來一點也不明確,我們先改一下名稱阔涉。此處將其命名為MTProjectLite缆娃。
1). 點擊MTProject copy的名稱即可改名捷绒;
2). 修改Xcode中的Scheme名(在停止調(diào)試按鈕的右邊),選擇Manager Schemes贯要,在彈出的窗口中將MTProject copy改為MTProjectLite暖侨。如下圖:
3). 然后需要在MTProject項目的目錄下建立MTProjectLite文件夾并拖到Xcode中,以便于管理兩個Target下不同的資源崇渗、類等字逗。
4). 復(fù)制Target時會自動創(chuàng)建MTProject copy-Info.plist,此時修改為MTProjectLite.plist宅广,然后移動到MTProjectLite文件夾下葫掉。
5). 因為增加了Target,所以podfile中也需要同步增加一個Target乘碑,否則MTProjectLite則不能使用pod中導(dǎo)入的第三方庫挖息。在podfile中增加如下代碼:
```
target 'MTProjectLite' do
# 這里與MTProject是一致的,因為是在同一個Project下
project 'MTProject/MTProject.xcodeproj'
common_pods
end
```
然后再次pod install
-
到這一步兽肤,兩個Target除了名字和bundleID之外套腹,其他完全一致。
想要區(qū)別不同的Target资铡,需要在Build Phases中管理:
1). Compile Sources(當前Target編譯的代碼文件)电禀;
2). Link Binary With Libraries(當前Target編譯所依賴的庫);
3). Copy Bundle Resources(當前Target編譯需要的資源)笤休。
不同的Target可根據(jù)需要增減這三項里面的內(nèi)容
- 在同一份代碼中區(qū)別不同的Target尖飞,可以通過設(shè)置預(yù)編譯宏實現(xiàn),在Build Setting中搜索
Preprocessor Macros
店雅,然后添加一條定義政基,此處命名為MTProjectLite。
在代碼中可以通過如下方法來區(qū)別不同的Target:
#ifdef MTProjectLite
NSLog(@"This is MTProjtectLite!!");
#else
NSLog(@"This is MTProjtect!!");
#endif