Xcode使用xcconfig文件配置環(huán)境

歡迎到我的 個(gè)人博客 http://liumh.com 瀏覽此文

與公司 QA 聊天状植,已不止一次被吐槽說(shuō)移動(dòng)端從開發(fā)環(huán)境轉(zhuǎn)到生產(chǎn)環(huán)境時(shí)砌们,還要靠修改代碼來(lái)配置對(duì)應(yīng)的環(huán)境參數(shù)。她認(rèn)為所刀,從 App 轉(zhuǎn)測(cè)試之后撰洗,就不應(yīng)該再修改代碼,可以把所有的環(huán)境配置都整合到配置文件中措拇,這樣打不同環(huán)境下的安裝包時(shí)我纪,會(huì)自動(dòng)選擇對(duì)應(yīng)的環(huán)境參數(shù)。這里說(shuō)到的環(huán)境參數(shù)包括但不僅限于: webservice 地址丐吓,友盟 AppKey浅悉,極光推送 AppKey 和是否是生產(chǎn)環(huán)境標(biāo)志等。

其實(shí)券犁,我也討厭修改環(huán)境參數(shù)啊术健,??

為達(dá)成上述目的,主要是使用 Xcode 的 Configurations Setting File(即后綴為 xcconfig 文件) 來(lái)配置開發(fā)不同階段下的環(huán)境粘衬。本文包含的內(nèi)容如下:

  1. Xcode Target
  2. Xcode Project
  3. Build Setting的繼承關(guān)系
  4. 如何使用xcconfig文件來(lái)配置不同開發(fā)階段的環(huán)境

包含了一些與 build settings 相關(guān)的知識(shí)荞估。

Xcode Target

target, 官方文檔如下解釋:

A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system—the source files and instructions for processing those source files—required to build that product. Projects can contain one or more targets, each of which produces one product.

target 定義了生成的唯一 product, 它將構(gòu)建該 product 所需的文件和處理這些文件所需的指令集整合進(jìn) build system 中。Projects 會(huì)包含一個(gè)或者多個(gè) targets,每一個(gè) target 將會(huì)產(chǎn)出一個(gè) product.

The instructions for building a product take the form of build settings and build phases, which you can examine and edit in the Xcode project editor. A target inherits the project build settings, but you can override any of the project settings by specifying different settings at the target level. There can be only one active target at a time; the Xcode scheme specifies the active target.

這些指令以 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 生效.

A target and the product it creates can be related to another target. If a target requires the output of another target in order to build, the first target is said to depend upon the second. If both targets are in the same workspace, Xcode can discover the dependency, in which case it builds the products in the required order. Such a relationship is referred to as an implicit dependency. You can also specify explicit target dependencies in your build settings, and you can specify that two targets that Xcode might expect to have an implicit dependency are actually not dependent. For example, you might build both a library and an application that links against that library in the same workspace. Xcode can discover this relationship and automatically build the library first. However, if you actually want to link against a version of the library other than the one built in the workspace, you can create an explicit dependency in your build settings, which overrides this implicit dependency.

target 和其生成的 product 可與另一個(gè) target 有關(guān)屯阀,如果一個(gè) target 的 build 依賴于另一個(gè) target 的輸出缅帘,那么我們就說(shuō)前一個(gè) target 依賴于后一個(gè) target .如果這些 target 在同一個(gè) workspace 中轴术,那么 Xcode 能夠發(fā)現(xiàn)這種依賴關(guān)系,從而使其以我們期望的順序生成 products.這種關(guān)系被稱為隱式依賴關(guān)系钦无。同時(shí)逗栽,你可以顯示指定 targets 之間的依賴關(guān)系,并且這種依賴關(guān)系會(huì)覆蓋 Xcode 推測(cè)出的隱式依賴關(guān)系失暂。

指定 targets 之間的依賴關(guān)系的地方在 Project Editor->TRAGETS->Build Phases->Target Dependencies 處設(shè)置彼宠。如下圖所示:

添加targets間的依賴關(guān)系
添加targets間的依賴關(guān)系

Xcode Project

官方文檔的解釋如下:

An Xcode project is a repository for all the files, resources, and information required to build one or more software products. A project contains all the elements used to build your products and maintains the relationships between those elements. It contains one or more targets, which specify how to build products. A project defines default build settings for all the targets in the project (each target can also specify its own build settings, which override the project build settings).

Xcode project 是一個(gè)倉(cāng)庫(kù),該倉(cāng)庫(kù)包含了所有的文件弟塞,資源和用于生成一個(gè)或者多個(gè) software products 的信息兵志。它包含一個(gè)或者多個(gè) targets,其中的每一個(gè) target 指明了如何生成 products宣肚。project 為其擁有的所有 targets 定義了默認(rèn)的 build settings,當(dāng)然悠栓,每一個(gè) target 能夠制定其自己的 build settings霉涨,且 target 的 build settings 會(huì)重寫 project 的 build settings。

Xcode project 文件包含以下信息:

  • 源文件的引用:
    • 源碼惭适,包括頭文件和實(shí)現(xiàn)文件
    • 內(nèi)部和外部的庫(kù)或者框架
    • 資源文件
    • 圖片文件
    • Interface Builder(nib)文件
  • 文件結(jié)構(gòu)導(dǎo)航中用來(lái)組織源文件的組
  • Project-level build configurations.你可以為 project 指定多個(gè) build configuration笙瑟,例如,project 中默認(rèn)包含 debug 和 release 兩種 build settings.
  • Targets, 每一個(gè) target 指定了:
    • project 生成的 product
    • 生成 product 所需的源文件
    • 生成 product 所需的配置文件癞志,包括對(duì)其他 targets 的依賴以及一些其他設(shè)置往枷;當(dāng) targets 的 build configurations 沒(méi)有重寫 project-level 的 build settings 時(shí),會(huì)直接使用 project-level 的 build setting.
  • 可執(zhí)行環(huán)境凄杯,該環(huán)境用于調(diào)試或者測(cè)試程序错洁,每個(gè)可執(zhí)行環(huán)境會(huì)指定:
    • 運(yùn)行或者調(diào)試程序時(shí)加載的可執(zhí)行程序
    • 傳遞給可執(zhí)行程序的命令行參數(shù)
    • 運(yùn)行程序時(shí)需設(shè)置的環(huán)境變量

project 可獨(dú)立存在,也可被包含在 workspace 中戒突。

Build Setting 的繼承關(guān)系

官方文檔內(nèi)容如下:

A build setting is a variable that contains information about how a particular aspect of a product’s build process should be performed. For example, the information in a build setting can specify which options Xcode passes to the compiler.

You can specify build settings at the project or target level. Each project-level build setting applies to all targets in the project unless explicitly overridden by the build settings for a specific target.

build setting 中包含了 product 生成過(guò)程中所需的參數(shù)信息屯碴。你可以在 project-level 和 target-level 層指定 build settings。project-level 的 build settings 適用于 project 中的所有targets膊存,但是當(dāng) target-level 的 build settings 重寫了 project-level 的 build settings导而,以 target-level 中的 build settings 中的值為準(zhǔn)。

Each target organizes the source files needed to build one product. A build configuration specifies a set of build settings used to build a target's product in a particular way. For example, it is common to have separate build configurations for debug and release builds of a product.

一個(gè) build configaration 指定了一套 build settings 用于生成某一 target 的 product隔崎,例如今艺,在 Xcode 創(chuàng)建項(xiàng)目時(shí)默認(rèn)就有兩套獨(dú)立的 build configarations, 分別用于生成 debug 和 release 模式下的 product。

In addition to the default build settings provided by Xcode when you create a new project from a project template, you can create user-defined build settings for your project or for a particular target. You can also specify conditional build settings. The value of a conditional build setting depends on whether one or more prerequisites are met. This mechanism allows you to, for example, specify the SDK to use to build a product based on the targeted architecture.

除了創(chuàng)建工程時(shí)生成的默認(rèn) build settings爵卒,你也可以自定義 project-level 或者 target-level 的 build settings.

關(guān)于繼承關(guān)系虚缎,The Unofficial Guide to xcconfig files 這里也有詳細(xì)的說(shuō)明,強(qiáng)烈建議閱讀技潘。

現(xiàn)在就來(lái)看看如何使用自定義的 build settings 來(lái)達(dá)到本文開始處提到的需求.

如何使用 xcconfig 文件來(lái)配置不同開發(fā)階段的環(huán)境

目前公司中的開發(fā)大致分兩個(gè)階段遥巴,第一階段:開發(fā)階段千康,此時(shí)所打包都是使用 development 的證書,極光和友盟統(tǒng)計(jì)的賬號(hào)都是使用開發(fā)者自己申請(qǐng)的賬號(hào)铲掐,webservice 的地址使用開發(fā)環(huán)境地址拾弃;第二階段:uat 階段,此時(shí)屬于預(yù)發(fā)版階段摆霉,此時(shí)打包使用 ad-hoc 的證書豪椿,極光和友盟統(tǒng)計(jì)的賬號(hào)使用公司申請(qǐng)生成賬號(hào),webservice 使用的特定的預(yù)發(fā)版環(huán)境携栋;另外搭盾,打上傳到 App Store 的生產(chǎn)包,使用 distribution 的證書婉支,webservice 的地址使用生產(chǎn)環(huán)境的地址鸯隅。

由此,可新建一種 build configuration, 由 Xcode 自動(dòng)生成的 Release 復(fù)制而來(lái)向挖,如下所示:

新建Configurations

并命名為 PreRelease蝌以。

官方文檔Adding a Build Configuration 中如下提到:

A configuration file is a plain text file with a list of build setting definitions, one per line. You can base a build configuration only on a configuration file that is in your project, not on an external file.

When you base a target or project’s build configuration on a configuration file, that build configuration automatically inherits the build setting definitions in that configuration file (and any configuration files it includes). If you then modify the value of any of those build settings in the target or project, the new value is used instead of the value in the configuration file.

Build settings defined at the target level override any values assigned to those build settings at the project level. Therefore, target-level configurations take precedence over any project-level configurations.

這里需要注意的是:當(dāng)你的 target-level 或者 project-levle 的 build configurations 基于配置文件時(shí),build configuration 會(huì)自動(dòng)繼承配置文件(以及配置文件中引入的配置文件)中定義的 build settings何之,但是如果你又在之后 target 或者 project 中修改了配置文件中定義的 build settings 值跟畅,那么最終配置文件中的值會(huì)失效,實(shí)際使用的是 target 或者 project 中設(shè)置的值溶推。

這里鑒于公司的情況徊件,新建了 Debug.xcconfig/PreRelease.xcconfig/Release.xcconfig 配置對(duì)應(yīng)于開發(fā)階段、預(yù)發(fā)版階段蒜危、上傳 AppStore 三種情況下的打包虱痕。

新建一個(gè) xcconfig 目錄,在該目錄下新建配置文件:

創(chuàng)建配置文件

根據(jù)項(xiàng)目情況舰褪,每個(gè)配置文件中都包含同樣的 key 值皆疹,內(nèi)容大致如下:

//網(wǎng)絡(luò)請(qǐng)求baseurl
WEBSERVICE_URL = @"http:\/\/127.0.0.1"

//友盟配置
UMENG_APPKEY = @"xxxvvv555999=="

//極光推送配置
JPUSH_DEVELOPMENT_APPKEY = @"nnncccvvvwww"
IS_PRODUCATION = NO

#include "Generator.xcconfig"

你可在配置文件中包含其他配置文件,其中 Generator.xcconfig 文件的內(nèi)容是:

GCC_PREPROCESSOR_DEFINITIONS = $(inherited) WEBSERVICE_URL='$(WEBSERVICE_URL)' MESSAGE_SYSTEM_URL='$(MESSAGE_SYSTEM_URL)' UMENG_APPKEY='$(UMENG_APPKEY)'  IS_PRODUCATION='$(IS_PRODUCATION)'

其作用是將配置文件中定義的常量定義成預(yù)編譯宏占拍,以便于在代碼中獲取略就。

其中 GCC_PREPROCESSOR_DEFINITIONS, 文檔如下:

Space-separated list of option specifications. Specifies preprocessor macros in the form foo (for a simple #define) or foo=1 (for a value definition). This list is passed to the compiler through the gcc -D option when compiling precompiled headers and implementation files.

GCC_PREPROCESSOR_DEFINITIONS 是 GCC 預(yù)編譯頭參數(shù),通常我們可以在 Project 文件下的 Build Settings 對(duì)預(yù)編譯宏定義進(jìn)行默認(rèn)賦值晃酒。在 Xcode7 下的路徑為 Build Settings->Apple LLVM 7.x Preprocessing->Preprocessor Macros表牢,

GCC_PREPROCESSOR_DEFINITIONS

想必大家看這個(gè)宏的名字已經(jīng)知道它的作用了, 使用上和在 pch 頭文件中添加宏定義沒(méi)有太大的區(qū)別, 但有以下好處:

  1. Xcode 的 Project 的 Build Settings 是由一個(gè) plist 文件進(jìn)行描述的, plist 本質(zhì)上是一個(gè) XML 配置文件, 通過(guò)外部的腳本比較容易去修改。
  2. Preprocessor Macros 可以按照 Configuration 選項(xiàng)進(jìn)行默認(rèn)配置, 也就是說(shuō)可以根據(jù)不同的環(huán)境預(yù)先制定不同定義的宏贝次,或者為不同環(huán)境下的相同變量定義不同的值

xcconfig 支持可以根據(jù)不同的 Configuration 選項(xiàng)配置不同的文件崔兴。不同的 xcconfig 可以指定不同的 Build Settings 里的屬性值, 這樣子我們就可以通過(guò)項(xiàng)目 xcconfig 去修改 GCC_PREPROCESSOR_DEFINITIONS 的值了(最終目的就達(dá)到了)。

配置文件中變量定義好之后,怎么讓 Xcode 自動(dòng)加載呢敲茄?如下圖設(shè)置所示位谋,是將 project-level 的 build settings 基于配置文件,三種情況的 configurations 分別選擇與之對(duì)應(yīng)的配置文件堰燎。

將配置文件與項(xiàng)目關(guān)聯(lián)

當(dāng)我們想把 project-level 或者 target-level 中的 Build Settings 的設(shè)置挪動(dòng)到 xcconfig 配置文件來(lái)設(shè)置時(shí)掏父,是否需要一個(gè)個(gè)手動(dòng)輸入呢?當(dāng)然不是秆剪,直接在 Build Settings 中選中你想要在 xcconfig 中配置的鍵值對(duì)所在行(當(dāng)然也可以選多行)赊淑,command + c復(fù)制,然后到對(duì)應(yīng)的 xcconfig 中去粘貼就好了仅讽,記得在 Build Settings 中改為你想要的值后再?gòu)?fù)制陶缺,如果為默認(rèn)值的話則只可復(fù)制其鍵。如果需要改回去的話洁灵,還是選中這行饱岸,command + delete 就恢復(fù)默認(rèn)值了。

現(xiàn)在我們將設(shè)置挪動(dòng)到了配置文件中徽千,所有的配置文件都是鍵值對(duì)類型的文本文件伶贰,但是當(dāng)同一個(gè)鍵同時(shí)存在于 target-level、project-level 和配置文件中時(shí)罐栈,到底是哪一個(gè)鍵值對(duì)起作用了呢?現(xiàn)在看看下圖泥畅。

多個(gè)配置項(xiàng)列

注意: Xcode以從左至右的順序設(shè)置解析的優(yōu)先級(jí)荠诬,從左至右優(yōu)先級(jí)降低,最左邊的具有最高優(yōu)先級(jí)位仁,即 target-level > project-level > 自定義配置文件 > iOS 默認(rèn)配置柑贞;且最左列 Resolved 列顯示的是最終使用的值。那么如何使 Xcode 使用配置文件中的配置項(xiàng)呢聂抢?這需要選中要使用配置文件的行钧嘶,點(diǎn)擊 Delete 按鍵,你會(huì)發(fā)現(xiàn)項(xiàng)目的默認(rèn)設(shè)置已經(jīng)被刪除琳疏,且 xcconfig 的配置文件列被標(biāo)記為綠色有决。標(biāo)記為綠色代表該列的值生效,其值應(yīng)該與 Resolved 列的值相同空盼。

最后书幕,你可以像如下示例使用 xcconfig 中定義的宏:

NSLog(@"webservice url: %@, umeng appkey: %@", WEBSERVICE_URL, UMENG_APPKEY);

通過(guò)以上步驟,就達(dá)到了使用 xcconfig 文件來(lái)配置開發(fā)不同階段時(shí)的環(huán)境變量的目的了揽趾。

文中內(nèi)容為自己學(xué)習(xí)總結(jié)台汇,如有錯(cuò)誤之處請(qǐng)指正。


參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市苟呐,隨后出現(xiàn)的幾起案子痒芝,更是在濱河造成了極大的恐慌,老刑警劉巖牵素,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件严衬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡两波,警方通過(guò)查閱死者的電腦和手機(jī)瞳步,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)腰奋,“玉大人单起,你說(shuō)我怎么就攤上這事×臃唬” “怎么了嘀倒?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)局冰。 經(jīng)常有香客問(wèn)我测蘑,道長(zhǎng),這世上最難降的妖魔是什么康二? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任碳胳,我火速辦了婚禮,結(jié)果婚禮上沫勿,老公的妹妹穿的比我還像新娘挨约。我一直安慰自己,他們只是感情好产雹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布诫惭。 她就那樣靜靜地躺著,像睡著了一般蔓挖。 火紅的嫁衣襯著肌膚如雪夕土。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天瘟判,我揣著相機(jī)與錄音怨绣,去河邊找鬼。 笑死拷获,一個(gè)胖子當(dāng)著我的面吹牛梨熙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刀诬,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼咽扇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼邪财!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起质欲,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤树埠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后嘶伟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怎憋,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年九昧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绊袋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铸鹰,死狀恐怖癌别,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布葬荷,位于F島的核電站,受9級(jí)特大地震影響剂习,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望擂达。 院中可真熱鬧,春花似錦胶滋、人聲如沸谍婉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至镀迂,卻和暖如春丁溅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背探遵。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工窟赏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箱季。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓涯穷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親藏雏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拷况,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

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