iOS多環(huán)境配置之Configurations + xcconfig

前言

一個(gè)APP的開發(fā)涉及到多種環(huán)境在所難免,比如Test環(huán)境宴抚,UAT(User Acceptance Test)用戶驗(yàn)收測(cè)試環(huán)境布轿,Release環(huán)境等等。我的項(xiàng)目需求是朝聋,在不同的環(huán)境下在代碼中使用全局性常量值不同嗡午,比如說(shuō)請(qǐng)求所用的IP。這里只是作一個(gè)簡(jiǎn)單的記錄和分享冀痕。

Configuration配置

配置Configuration的目的是為了增加或刪除編譯環(huán)境荔睹,對(duì)于不同編譯環(huán)境下的參數(shù)需求可以到xcconfig中進(jìn)行設(shè)置。

1言蛇、進(jìn)入工程的info頁(yè)僻他,下面紅框中標(biāo)明的是工程創(chuàng)建時(shí)自帶的兩個(gè)編譯環(huán)境Debug和Release。

1.png

點(diǎn)擊下面的加號(hào)添加新的編譯環(huán)境猜极,根據(jù)需要選擇Duplicate Debug和Duplicate Release中姜,他們的區(qū)別在于消玄,后者會(huì)進(jìn)行各種優(yōu)化跟伏,包括編譯的優(yōu)化,導(dǎo)致不能調(diào)試(不能通過(guò)斷點(diǎn)翩瓜、LLDB查看變量)受扳,另外Release環(huán)境下打的包也會(huì)更輕量一些。這里我將Debug環(huán)境名改為UAT_α兔跌,并增加一個(gè)基于Debug 的UAT_β環(huán)境勘高。


2.png

插曲:如果想要在Relase環(huán)境下去調(diào)試可以前往Bulid Setting總進(jìn)行設(shè)置,將Release下的參數(shù)換成和Debug一樣即可:


3.png

2、配置預(yù)編譯宏坟桅,這就相當(dāng)于在pch文件當(dāng)中去定義宏华望,可以在項(xiàng)目中做不同環(huán)境的區(qū)分,進(jìn)而進(jìn)行操作仅乓。進(jìn)入工程的Build Setting ->Preprocessor Macros:

Snip20170629_10.png

我們看到UAT_α和UAT_β對(duì)應(yīng)的值均為DEBUG = 1赖舟,我們可以理解的是在兩種環(huán)境下同時(shí)定義了#define DEBUG 1,為了表示區(qū)別可以分別設(shè)置為不同的宏名和值夸楣,例如:ConfigDemo_ UAT_α=0,ConfigDemo_ UAT_β=1(等號(hào)兩邊不能留空格宾抓,否則會(huì)編譯出錯(cuò))子漩。GCC提供了一種動(dòng)態(tài)編譯的方法:ConfigDemo_{CONFIGURATION}=1,這兩種設(shè)置方法是等價(jià)的(注意不要?jiǎng)?(inherited)石洗,他表示繼承工程的默認(rèn)設(shè)置)幢泼。

3、進(jìn)行Scheme的配置讲衫,可以理解一個(gè)Scheme對(duì)應(yīng)一個(gè)Target缕棵、一種環(huán)境(當(dāng)然這里只有一個(gè)Target,只是編譯環(huán)境不同)涉兽。 當(dāng)我們切換不同的Scheme運(yùn)行時(shí)就是切換不同的環(huán)境了挥吵。在Xcode的左上角選擇添加新的Scheme,并分別添加ConfigDemo_ UAT_α花椭,ConfigDemo_ UAT_β兩個(gè)Scheme:


Snip20170629_11.png
Snip20170629_13.png

添加完Scheme后對(duì)其進(jìn)行配置忽匈,我們剛才配置環(huán)境后總共有Release、UAT_α矿辽、UAT_β三種環(huán)境丹允,在這里使他們分別對(duì)應(yīng)ConfigDemo、ConfigDemo_ UAT_α袋倔,ConfigDemo_ UAT_β雕蔽,選擇Edit Scheme,這里可以將Run宾娜、Test批狐、Archive改為對(duì)應(yīng)的Scheme,關(guān)于他們的解釋

Snip20170629_15.png

于是在代碼中就可以進(jìn)行如下操作:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
#ifdef ConfigDemo_UAT_α
    
#define TestString @"ConfigDemo_UAT_α"
    
#elif ConfigDemo_UAT_β
    
#define TestString @"ConfigDemo_UAT_β"
    
#else //Release
    
#define TestString @"Release"
    
#endif
    
    NSLog(@"TestString:%@",TestString);
    
    // 打印結(jié)果分別為Release前塔、ConfigDemo_UAT_α嚣艇、ConfigDemo_UAT_β
}

根據(jù)不同的Scheme配置不同的displayName、APPICON等可以參見文章最后的鏈接;

配置xcconfig

關(guān)于項(xiàng)目的參數(shù)需要做一下說(shuō)明:

xcconfig文件的修改實(shí)際上是修改build setting中的參數(shù)华弓。Projects 會(huì)包含一個(gè)或者多個(gè) targets,這里可以理解每一種編譯環(huán)境對(duì)應(yīng)一個(gè)target食零,每一個(gè) target 將會(huì)產(chǎn)出一個(gè) product.這些指令以 build setting 和 build phases 的形式存在,你可在 Xcode 的項(xiàng)目編輯器(TARGETS->Build Setting, TARGETS->Build Phases)中進(jìn)行查看和編輯寂屏。target 中的 build setting 參數(shù)繼承自 project 的 build settings, 但是你可以在 target 中修改任意 settings 來(lái)重寫 project settings贰谣,這樣,最終生效的 settings 參數(shù)以在 target 中設(shè)置的為準(zhǔn). Project 可包含多個(gè) target, 但是在同一時(shí)刻迁霎,只會(huì)有一個(gè) target 生效吱抚,可用 Xcode 的 scheme 來(lái)指定是哪一個(gè) target 生效,雖然這里并沒有配置多個(gè)Target,但是這里還是可以理解一個(gè)Scheme對(duì)應(yīng)一個(gè)Target考廉。
另外要說(shuō)明一點(diǎn)秘豹,對(duì)于項(xiàng)目中其他地方的配置,可以直接在操作板中復(fù)制粘貼到文件中來(lái)進(jìn)行修改芝此,最終xcconfig的設(shè)置會(huì)覆蓋原來(lái)的設(shè)置憋肖。

對(duì)于需要單獨(dú)配置參數(shù)的環(huán)境則生成一個(gè)xcconfig文件因痛,沒有單獨(dú)配置xcconfig的則使用默認(rèn)的設(shè)置,另外在這里需要生成一個(gè)公用的xcconfig文件岸更。公共文件用于定義好統(tǒng)一的變量(宏)鸵膏,每一個(gè)環(huán)境去設(shè)置具體的值,形成多環(huán)境配置怎炊。
Snip20170629_8.png
Snip20170629_9.png
每個(gè)文件代碼的寫法:
  1. Common. xcconfig的寫法
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) VariableA='$(VariableA)' VariableB='$(VariableB)'

解析如下:
其作用是將配置文件中定義的常量定義成預(yù)編譯宏谭企,以便于在代碼中獲取。
GCC_PREPROCESSOR_DEFINITIONS 是 GCC 預(yù)編譯頭參數(shù)评肆,對(duì)應(yīng)的設(shè)置在 Xcode8下的路徑為 Build Settings->Apple LLVM 7.x Preprocessing->Preprocessor Macros债查,就是我上面提到的設(shè)置預(yù)編譯宏,這里權(quán)且可以理解上面這一串代碼是在Build Setting中設(shè)置預(yù)編譯宏的代碼化瓜挽,而這里的設(shè)置并不會(huì)覆蓋之前在Build Setting中的設(shè)置盹廷,只會(huì)將這些新增的設(shè)置添加到最后面。 上面代碼的意思是久橙,定義兩個(gè)預(yù)編譯的宏名字分別為VariableA俄占、VariableB,他們具體的值就可以在不同的xcconfig中去設(shè)置淆衷,不同的xcconfig需要導(dǎo)入這一個(gè)Common. xcconfig的文件缸榄,這就實(shí)現(xiàn)了不同環(huán)境下動(dòng)態(tài)的配置,不同環(huán)境下的預(yù)編譯宏名一樣只是值會(huì)不一樣祝拯,而且這些xcconfig文件可以在不同的項(xiàng)目中使用甚带。
這樣就可以簡(jiǎn)單的理解為Common. xcconfig實(shí)現(xiàn)了一個(gè)Build Setting里面的一個(gè)方法,而其他的xcconfig文件調(diào)用這個(gè)方法進(jìn)行具體設(shè)置佳头。
上面在Preprocessor Macros中配置的用于在代碼中區(qū)分不同環(huán)境的預(yù)編譯宏鹰贵,也可以直接在Common. xcconfig中設(shè)置,只是在代碼中進(jìn)行區(qū)分就要區(qū)分不同宏的值了畜晰。

2.其他xcconfig代碼:

#include "Common.xcconfig"

VariableA = @"UAT_α.xcconfig_VariableA"
VariableB = @"UAT_α.xcconfig_VariableB"

3砾莱、將xcconfig與環(huán)境進(jìn)行關(guān)聯(lián):
我們來(lái)到工程下的info->Configuration瑞筐,


Snip20170630_19.png

我們發(fā)現(xiàn)凄鼻,每一種環(huán)境下都有兩個(gè)這樣的設(shè)置,一個(gè)設(shè)置是工程的xcconfig文件配置聚假,另一個(gè)則是target的xcconfig文件配置块蚌,在這里配置xcconfig意味著APP在運(yùn)行的時(shí)候會(huì)去加載相應(yīng)xcconfig中的設(shè)置。上面我們說(shuō)到了配置的繼承關(guān)系膘格,那么這里只設(shè)置target的xcconfig就夠了峭范,而且你設(shè)置了工程的xcconfig就相當(dāng)于在編譯的時(shí)候?qū)⑦@些xcconfig的配置加載設(shè)置了兩遍!其實(shí)你也會(huì)發(fā)現(xiàn)此時(shí)再設(shè)置工程的xcconfig也沒有關(guān)系瘪贱。這里我暫且只設(shè)置UAT_α和UAT_β環(huán)境下的xcconfig纱控,Release環(huán)境留著調(diào)式pod辆毡。

2019-6-7更新:
經(jīng)過(guò)上面的設(shè)置,在某些Xcode上會(huì)出現(xiàn)“use undecalred indentifire”的錯(cuò)誤甜害,經(jīng)過(guò)不斷嘗試后發(fā)現(xiàn)舶掖,將工程的xcconfig文件對(duì)應(yīng)為Commn就可以了,猜測(cè)與Xcode自身有關(guān)尔店,配置文件的加載順序會(huì)影響到代碼的編譯眨攘。

Snip20170630_20.png

接下來(lái)你就可以直接在代碼中使用VariableA、VariableB宏了:

// 這里并不能在Release環(huán)境下使用這些宏嚣州,否則會(huì)報(bào)錯(cuò)鲫售。
   NSLog(@"%@ - %@",VariableA, VariableB);
    // ConfigDemo_UAT_α、ConfigDemo_UAT_β環(huán)境打印結(jié)果分別為
    // UAT_α.xcconfig_VariableA - UAT_α.xcconfig_VariableB
    // UAT_β.xcconfig_VariableA - UAT_β.xcconfig_VariableB

Pod調(diào)試该肴,Pod安裝SDWebImage

在刪除上面的log代碼之后情竹,你會(huì)發(fā)現(xiàn)只有在Release環(huán)境下能夠運(yùn)行!首先我們來(lái)看看報(bào)錯(cuò):

Snip20170630_22.png

是的匀哄,工程找不到相關(guān)文件了鲤妥,其實(shí)這個(gè)你在終端的提示中就可以發(fā)現(xiàn)端倪:

Snip20170630_21.png

大概意思是你需要你配置的xcconfig文件中導(dǎo)入pod配置文件的路徑。

在完成一次pod install之后拱雏,Pods工程會(huì)為每一個(gè)環(huán)境生成一個(gè)xcconfig文件棉安,包括默認(rèn)的debug環(huán)境,如果我們的目標(biāo)工程ConfigDemo對(duì)應(yīng)的環(huán)境沒有配置xcconfig文件铸抑,那么就會(huì)在ConfigDemo工程下拷貝一份對(duì)應(yīng)的xcconfig文件并自動(dòng)在環(huán)境中完成配置贡耽,這種配置讓工程能夠使用pod。大家可以看到這里在ConfigDemo工程下只有Release. xcconfig文件的拷貝鹊汛,而此時(shí)Release環(huán)境下的Configuration配置已經(jīng)發(fā)生了改變蒲赂。

Snip20170630_24.png
Snip20170630_25.png

我們只需要在其他xcconfig文件中導(dǎo)入相關(guān)的pod下的xcconfig就好了,記得使用相對(duì)路徑刁憋,否則在其他電腦上就不能運(yùn)行了:

#include "Pods/Target Support Files/Pods-ConfigDemo/Pods-ConfigDemo.release.xcconfig"

這個(gè)時(shí)候你就可以刪除在ConfigDemo工程下的.release.xcconfig文件滥嘴,并去Configuration中配置你自己的xcconfig文件了,記得重新pod install一下至耻。

Demo:https://github.com/Randy1993/ConfigDemo

宏DEBUG丟失的問(wèn)題

上述的配置結(jié)束之后若皱,會(huì)導(dǎo)致Pod工程下UAT_α等缺少DEBUG宏,導(dǎo)致某些三方庫(kù)無(wú)法正常使用尘颓,比如說(shuō)MLeaksFinder無(wú)效走触。在Podfile中添加如下代碼即可:

pod 'MLeaksFinder'
    
    post_install do |installer_representation|
        installer_representation.pods_project.targets.each do |target|
            if target.name == 'MLeaksFinder'
                target.build_configurations.each do |config|
                    if config.name == 'UAT_α'
                        config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)','DEBUG=1']
                    end
                end
            end
        end
    end

參考文章:

http://www.reibang.com/p/83b6e781eb51
http://liumh.com/2016/05/22/use-xcconfig-config-specific-variable/#xcconfig-environment 關(guān)于xcconfig文件的說(shuō)明。
http://www.reibang.com/p/51a2bbe877aa Configuration配置

Stay hungry疤苹,Stay foolish互广!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惫皱,更是在濱河造成了極大的恐慌像樊,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旅敷,死亡現(xiàn)場(chǎng)離奇詭異凶硅,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)扫皱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門足绅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人韩脑,你說(shuō)我怎么就攤上這事氢妈。” “怎么了段多?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵首量,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我进苍,道長(zhǎng)加缘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任觉啊,我火速辦了婚禮拣宏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杠人。我一直安慰自己勋乾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布嗡善。 她就那樣靜靜地躺著辑莫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪罩引。 梳的紋絲不亂的頭發(fā)上各吨,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音袁铐,去河邊找鬼揭蜒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛昭躺,可吹牛的內(nèi)容都是我干的忌锯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼领炫,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了张咳?” 一聲冷哼從身側(cè)響起帝洪,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤似舵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后葱峡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砚哗,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年砰奕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛛芥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡军援,死狀恐怖仅淑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胸哥,我是刑警寧澤涯竟,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站空厌,受9級(jí)特大地震影響庐船,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘲更,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一筐钟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赋朦,春花似錦盗棵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至琳拨,卻和暖如春瞭恰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狱庇。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工惊畏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人密任。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓颜启,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親浪讳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缰盏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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