工程管理篇 | 多Targets實(shí)現(xiàn)詳述


前言

很多時(shí)候伙菜,工程管理是一個(gè)很實(shí)際的技能厢洞,我們?cè)趯?shí)際開(kāi)發(fā)中普遍有很多環(huán)境:測(cè)試環(huán)境、開(kāi)發(fā)環(huán)境躺翻、生產(chǎn)環(huán)境等。還有可能遇到需要?jiǎng)?chuàng)建兩個(gè)很多內(nèi)容相同踊淳,部分功能不同的工程陕靠。

如果需要切換環(huán)境發(fā)版本的話,你可以手動(dòng)注冊(cè)修改代碼實(shí)現(xiàn)(如果你喜歡這樣的話剪芥,也就不需要繼續(xù)看本文了),不是說(shuō)這樣很low税肪,而是當(dāng)不同環(huán)境的差異比較多的話,這種手動(dòng)管理工程版本的方法笨拙而且容易出錯(cuò)锻梳。

創(chuàng)建兩個(gè)很多內(nèi)容相同净捅,部分功能不同的工程,你可以選擇拷貝蛔六,修改,保存屁魏,成為兩個(gè)工程捉腥。當(dāng)然還有另一種優(yōu)雅的姿勢(shì)你画。

這個(gè)姿勢(shì)挺累的

這些問(wèn)題都可以通過(guò)設(shè)置多個(gè) Targets 來(lái)解決桃漾。

其它知識(shí)補(bǔ)充

workspace 拟逮、Project、target敦迄、 Scheme 的關(guān)系和簡(jiǎn)介

workspace 是Xcode的一種文件,用來(lái)管理工程和里面的文件苦囱,一個(gè)workspace可以包含若干個(gè)工程
project 里面包含了所有的源文件脾猛,資源文件和構(gòu)建一個(gè)或者多個(gè)product的信息。project利用他們?nèi)ゾ幾g我們所需的product猛拴,也幫我們組織它們之間的關(guān)系。一個(gè)project可以包含一個(gè)或者多個(gè)target职员。
target 每個(gè)target都繼承了project的默認(rèn)設(shè)置跛溉,每個(gè)target可以通過(guò)重新設(shè)置target的編譯選項(xiàng)來(lái)定義自己的特殊編譯選項(xiàng)。一個(gè)target對(duì)應(yīng)于一個(gè)product(產(chǎn)品)倒谷。
scheme 定義了編譯集合中的若干target,編譯時(shí)的一些設(shè)置以及要執(zhí)行的測(cè)試集合牵祟。我們可以定義多個(gè)scheme對(duì)應(yīng)一個(gè)target抖格。

關(guān)于Target

相信很多人都注意到XCode中, 有個(gè)Target的概念.那么這個(gè)Target到底是什么呢?

Apple的人是這樣說(shuō)的:“ Targets that define the products to build. A target organizes the files and instructions needed to build a product into a sequence of build actions that can be taken.”

簡(jiǎn)單的理解的話, 可以認(rèn)為一個(gè)target對(duì)應(yīng)一個(gè)新的product(基于同一份代碼的情況下). 但都一份代碼了, 弄個(gè)新product做什么呢 ?

其實(shí)這不是單純的瞎折騰, 雖然代碼是同一份, 但編譯設(shè)置(比如編譯條件), 以及包含的資源文件卻可以有很大的差別. 于是即使同一份代碼, 產(chǎn)出的product也可能大不相同.

Targets之間, 什么相同, 什么不同!

既然是利用同一份代碼產(chǎn)出不同的product, 那么到底不同Target之間存在著什么樣的差異呢?
要解釋這個(gè)問(wèn)題, 我們就要來(lái)看看一個(gè)Target指定了哪些內(nèi)容.

從XCode左側(cè)的列表中, 我們可以看到一個(gè)Target包含了Copy Bundle Resources, Compile Sources, Link Binary With Libraries. 其中

  • Copy Bundle Resources 是指生成的product的.app內(nèi)將包含哪些資源文件

  • Compile Sources 是指將有哪些源代碼被編譯

  • Link Binary With Libraries 是指編譯過(guò)程中會(huì)引用哪些庫(kù)文件

    Paste_Image.png

通過(guò)Copy Bundle Resources中內(nèi)容的不同設(shè)置, 我們可以讓不同的product包含不同的資源, 包括程序的主圖標(biāo)等, 而不是把XCode的工程中列出的資源一股腦的包含進(jìn)去。

而這還不是一個(gè)target所指定的全部?jī)?nèi)容. 每個(gè)target可以使用一個(gè)獨(dú)立, 不同的Info.plist文件收奔。

我們都知道, 這個(gè)Info.plist文件內(nèi)定義了一個(gè)iPhone項(xiàng)目的很多關(guān)鍵性?xún)?nèi)容, 比如程序名稱(chēng), 最終生成product的全局唯一id等等滓玖。

而且不同的target還可以定義完整的差異化的編譯設(shè)置, 從簡(jiǎn)單的調(diào)整優(yōu)化選項(xiàng), 到增加條件編譯所使用的編譯條件, 以至于所使用的base SDK都可以差異化指定.

兩種添加Targets的方式

拷貝原有的Target

項(xiàng)目里面創(chuàng)建了多個(gè)target(分別是:生產(chǎn)環(huán)境、測(cè)試環(huán)境翩肌、開(kāi)發(fā)環(huán)境)模暗,每個(gè)target對(duì)應(yīng)一個(gè)環(huán)境念祭,并配置不同的info.plist文件,這樣做的好處是不用開(kāi)發(fā)人員每次都要去手動(dòng)開(kāi)啟/注釋某些代碼去發(fā)布隶糕,而是先配置好,到時(shí)候直接切換target就可以打包上線了切換一下target夷野,運(yùn)行一下测秸,就是一個(gè)新項(xiàng)目灾常。

第一步:

彈出來(lái)的的頁(yè)面是:一般選擇中間那個(gè)選項(xiàng) Duplicate only,如果有pad钞瀑,則選擇最后一個(gè)


第二步:



第三步:(這里不要忘了把你原來(lái)的Info.plist文件也勾選對(duì)了)

第四五六七步:

通過(guò)在不同的Targets 預(yù)定義宏(Build Setting–>Preprocessor Macros)區(qū)分不同的工程環(huán)境

這個(gè)宏是一個(gè)全局宏雕什,在所有/整個(gè)工程的代碼中都是有效的,我們可以在這里添加上環(huán)境與處理的宏(例如:WD_Environment_Mode壹士,這個(gè)是隨便自己取的)

#然后在.pch文件中
/**
WD_Environment_Mode
0:生產(chǎn)環(huán)境
1:測(cè)試環(huán)境
2:開(kāi)發(fā)環(huán)境
*/
#ifdef    WD_Environment_Mode
#if       WD_Environment_Mode == 0
#define    WDAPIServerUrl   @""
#define    JSPatchAppKey     @""

#elif      WD_Environment_Mode == 1
#define    WDAPIServerUrl @""
#define    JSPatchAppKey  @""

#elif    WD_Environment_Mode == 2
#defineWDAPIServerUrl @""
#defineJSPatchAppKey  @""
#else
#warning"未匹配環(huán)境"
#endif

***************************************
更多關(guān)于 預(yù)定義宏的使用

而 Xcode 在產(chǎn)生新的 project 時(shí)偿警,會(huì)自動(dòng)在 Debug scheme 裡面加入 DEBUG=1 這個(gè) Preprocessor Macro.
因此可以使用 DEBUG 這個(gè) preprocessor macro 來(lái)區(qū)分 debug 和 release mode.


  ViewController.m
  ...
  #ifdef DEBUG
      [self.hintLabel setText:@"Debug mode"];
  #else
      [self.hintLabel setText:@"Release mode"];
  #endif
  ...

如果你不喜歡、不習(xí)慣這樣的代碼寫(xiě)法 可以在 PrefixHeader.pch 裡面加入以下的片段:

  PrefixHeader.pch

  #ifdef DEBUG
  #define debug_only YES
  #else
  #define debug_only NO
  #endif

  ViewController.m
   ...
  if(debug_only){
      [self.hintLabel setText:@"Debug mode"];
  } else {
      [self.hintLabel setText:@"Release mode"];
  }
  ...

就可以在所有的 source code 都直接用 if(debug_only){ ... } 來(lái)將 debug 時(shí)才會(huì)用到的程式片段包起來(lái)了盒使。這是你最熟悉的方式是吧.

****************************************

總結(jié)一下七嫌,上面這種復(fù)制 target的方式比較適合不同的環(huán)境需要用到的變量值不同,也就是通過(guò)不同的 Target里面的 全局宏的值來(lái)做判斷依據(jù)的,但是整套工程還是只有一套代碼诵原,相當(dāng)于做了條件編譯挽放。

生成一個(gè)新的target鞋拟,一定會(huì)與原target有區(qū)別,這里可以定義預(yù)編譯宏贺纲,來(lái)區(qū)分兩個(gè)版本的不同代碼褪测,預(yù)編譯宏可以在Build Settings中Preprocessor Macros定義,比如在我們新建的target B中定義預(yù)編譯宏MACRO懈叹,然后在代碼中通過(guò)

  #if defined (MACRO)
       //target  B需要執(zhí)行的代碼
  #else
       //target A需要執(zhí)行的代碼
  #endif

來(lái)區(qū)分,并且同時(shí)又可以通過(guò)新Targets 來(lái)實(shí)現(xiàn)APP的 Logo分扎,啟動(dòng)圖,App名稱(chēng)的個(gè)性化定制畏吓!

創(chuàng)建全新的target

有的時(shí)候,我們創(chuàng)建兩個(gè)很多內(nèi)容相同肾砂,部分功能不同的工程宏悦,你可以選擇拷貝,修改饼煞,保存,成為兩個(gè)工程砖瞧。當(dāng)然你也可以利用 多個(gè) Target實(shí)現(xiàn)。

但是有時(shí)候储矩,兩個(gè)版本里面的資源是沖突的褂乍,不能同時(shí)導(dǎo)入到一個(gè)target,上面我們通過(guò)復(fù)制 Target實(shí)現(xiàn)的其實(shí)是條件編譯逃片,并不是真正的新Target只酥。下面的方式就能解決上面提到的沖突的問(wèn)題呀狼。

最贊的是,這種方式即可以解決導(dǎo)入資源沖突的問(wèn)題哥艇,又可以把公用的部分拿出來(lái),供兩個(gè)Target使用十饥,真正做到了:只修改或者創(chuàng)建不同的功能祖乳,公用相同的功能。

Paste_Image.png

會(huì)出現(xiàn)一個(gè)彈框眷昆,向下滾動(dòng),選擇Single View Application-->Next-->Produce Name -->Finish

Paste_Image.png

但是這樣生成出的Target幾乎是空的. Copy Bundle Resources, Compile Sources, Link Binary With Libraries里面都沒(méi)有任何內(nèi)容. 編譯設(shè)置也是完全原始的狀態(tài)作媚。等于是一個(gè)新的小工程伞访。

下面就在一個(gè)復(fù)雜成熟系統(tǒng)中新增target的真實(shí)操作為案例詳述實(shí)際中的操作

需求場(chǎng)景:當(dāng)時(shí)是因?yàn)樾枰煤?档男掳鍿DK做一個(gè)APP弟灼,但是這個(gè)APP的其余部分都跟以前的APP是一樣的冒黑,于是就想到了新增target,通過(guò)共用公共模塊抡爹,不同target 實(shí)現(xiàn)不同的視頻監(jiān)控功能。

基礎(chǔ)知識(shí)補(bǔ)充

  • 【1】Xcode左側(cè)的文件不一定都是實(shí)際目錄下存在的欧穴,有的只是別的目錄位置下的文件的引用。
  • 【2】Xcode左側(cè)的文件不一定屬于看上去的目錄涮帘,沒(méi)有出現(xiàn)的文件也一定不能被該 Target使用笑诅。
  • 【3】修改Xcode左側(cè)的實(shí)際存在的文件/文件夾位置會(huì)直接修改文件的實(shí)際物理位置疮鲫。
  • 【4】如果一個(gè)工程下(即 project的文件夾下)已經(jīng)存在了某一個(gè)文件 .h 或者.m時(shí)弦叶,當(dāng)該文件再次被拖進(jìn)工程中時(shí),就算我們勾選了“Copy items if needed”該文件也看似新增了并出現(xiàn)在了Xcode的左側(cè)導(dǎo)航中伤哺,但是這個(gè)“新增”的文件卻是一個(gè)引用文件,并非重新創(chuàng)建了一份贬循。
  • 【5】工程文件中添加生產(chǎn)新文件的方式只有兩種:
    • A.原工程中沒(méi)有該文件并且在拖進(jìn)工程中時(shí) 勾選了“Copy items if needed”桃序。
    • B. 手動(dòng)復(fù)制并生成在實(shí)際物理位置下烂瘫,再拖入并引用至工程中。

步驟:

一坟比、可以梳理工程中的公用文件到一個(gè)公共文件夾中,注意這個(gè)時(shí)候因?yàn)橐苿?dòng)了文件的實(shí)際物理位置柠衅,我們可以通過(guò)先移除對(duì)文件夾的引用 Remove References,注意不是 Move to Trash


文件夾的實(shí)際位置從A移動(dòng)到了B



當(dāng)我們整理好公用部分的文件后再次拖入工程后菲宴,即便我們?nèi)缦聢D那樣選擇了Add to targets 到所有的 targets后:



公共文件夾中的文件還是沒(méi)有被引用到任何的 target中

二喝峦、給新 Target 的 Compile Sources 呜达、Link Binary With Libraries 谣蠢、Copy Bundle Resources 中添加需要的文件引用查近。

  • Compile Sources中添加需要的所有 .m/.mm 文件,不需要添加進(jìn) .h 文件谈喳,這個(gè)后面會(huì)說(shuō)侥祭。
  • Link Binary With Libraries 中添加的是需要的所有靜態(tài)庫(kù)茄厘、系統(tǒng)類(lèi)庫(kù)谈宛。
  • Copy Bundle Resources 中添加所有需要的圖片或者其他資源文件 包括:xib、 storyBorad吆录。
    基本上上面三個(gè)位置就是一個(gè) Target 的所有能引用到的資源設(shè)置。

并設(shè)置好特殊類(lèi)的編譯設(shè)置:


三哀卫、設(shè)置新 Target 的 info.plist 文件和 .pch文件路徑撬槽,注意.pch文件路徑 就是該文件在工程目錄中的相對(duì)實(shí)際物理路徑


比如上面的這張圖中:.pch的文件路徑就是 Modular/GlobalConfig/xxxxx.pch

四、注意事項(xiàng)

1侄柔、 兩個(gè)不同 Target中可以存在相同名稱(chēng)的 .h 和 .m 文件,不會(huì)出現(xiàn)重名的沖突移剪。
2薪者、關(guān)于.h文件,有一個(gè)很有意思的事情就是言津,我們?cè)谝迷O(shè)置的時(shí)候不用管任何 .h 文件,一般第三方中會(huì)有大量的 .h文件贝椿,我們都不需要管,在新的 Target 中如果沒(méi)有對(duì)應(yīng)名稱(chēng)的 .h 文件烙博,編譯器就會(huì)從整個(gè)工程目錄中搜索烟逊,如果在其他的Target 中找到對(duì)應(yīng)的 .h文件就會(huì)直接引用,如果在當(dāng)前 Target中搜索到對(duì)應(yīng)名稱(chēng)的 .h文件就會(huì)引用當(dāng)前Target內(nèi)的 .h文件宪躯,即便別的Target中也有相同名稱(chēng)的 .h 文件也不會(huì)被引用。
3详瑞、當(dāng)然你也可以不整理出公用的公共部分文件,這樣就直接 new一個(gè) Target 坝橡,完成 Bouild Phases的資源引用設(shè)置后,設(shè)置好 info.plist 文件和 .pch文件路徑就完成了多 Target 的工程設(shè)置了计寇。


本文參考文章
手把手教你給一個(gè)iOS app配置多個(gè)環(huán)境變量
使用 Preprocessor Macros 區(qū)分 release 和 debug 版本
如何在iOS項(xiàng)目中創(chuàng)建多個(gè)target
iOS新建target番宁,使兩個(gè)不同項(xiàng)目共用某一模塊

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蝶押,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌棋电,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異招刨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)沉眶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)杉适,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人猿推,你說(shuō)我怎么就攤上這事∨河剑” “怎么了秽五?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)坦喘。 經(jīng)常有香客問(wèn)我西设,道長(zhǎng)答朋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任擒滑,我火速辦了婚禮叉弦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘淹冰。我一直安慰自己,他們只是感情好樱拴,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布晶乔。 她就那樣靜靜地躺著珍坊,像睡著了一般正罢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翻具,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天裆泳,我揣著相機(jī)與錄音,去河邊找鬼工禾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛闻葵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洪灯,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼签钩!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起憎夷,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昧旨,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后兔沃,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乒疏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年额衙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怕吴。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡窍侧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出转绷,到底是詐尸還是另有隱情伟件,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布议经,位于F島的核電站锋爪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏爸业。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一亏镰、第九天 我趴在偏房一處隱蔽的房頂上張望扯旷。 院中可真熱鬧,春花似錦钧忽、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至篮幢,卻和暖如春大刊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背三椿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工缺菌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留葫辐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓伴郁,卻偏偏與公主長(zhǎng)得像耿战,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子焊傅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 前言 談到多環(huán)境剂陡,相信現(xiàn)在大多公司都至少有2-3個(gè)app環(huán)境了,比如Test環(huán)境狐胎,UAT(User Accepta...
    一縷殤流化隱半邊冰霜閱讀 75,935評(píng)論 222 776
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,754評(píng)論 25 707
  • 歡迎到我的 個(gè)人博客 http://liumh.com 瀏覽此文 與公司 QA 聊天鸭栖,已不止一次被吐槽說(shuō)移動(dòng)端從開(kāi)...
    CaryaLiu閱讀 4,576評(píng)論 0 16
  • 關(guān)于對(duì)象很兇這件事,我一直很惆悵,我一直都說(shuō)他誰(shuí)給你慣出來(lái)的臭毛病,脾氣不好還呢么兇,他整個(gè)人都很?chē)?yán)肅,偶爾還給我...
    6706447be911閱讀 342評(píng)論 1 0
  • 昨天帶學(xué)生春游,雖累卻很盡興顽爹。今天正好三八節(jié)纤泵,下午放假半天,還不錯(cuò)镜粤。早上聽(tīng)了一節(jié)校內(nèi)老師的公開(kāi)課后捏题,加上自己上了三...
    清湯寡水bh閱讀 219評(píng)論 0 0