概述
偶然看到一個(gè)很有趣的問(wèn)題:如何在ios環(huán)境下實(shí)現(xiàn)多個(gè)環(huán)境同時(shí)打包。
談到多環(huán)境,我想大多公司都至少有2-3個(gè)環(huán)境,比如Test環(huán)境,UAT(User Acceptance Test)用戶驗(yàn)收測(cè)試環(huán)境勒庄,Release環(huán)境等等串前。當(dāng)需要開(kāi)發(fā)打多個(gè)包的時(shí)候,一般常見(jiàn)做法就是直接代碼里面修改環(huán)境變量实蔽,改完之后Archive一下就打包了荡碾。或者在App中內(nèi)置一個(gè)切換的按鈕局装,實(shí)現(xiàn)環(huán)境的切換坛吁。
或者,你們公司已經(jīng)搭建了Jenkins環(huán)境铐尚,利用Jenkins環(huán)境就可以給app來(lái)配置一下多個(gè)環(huán)境變量拨脉,之后Jenkins分別再不同環(huán)境下自動(dòng)集成即可。
那么如何實(shí)現(xiàn)ios的多環(huán)境打包呢宣增?參照網(wǎng)上的一些方案這里做一個(gè)簡(jiǎn)單的總結(jié)玫膀。要實(shí)現(xiàn)多環(huán)境打包,現(xiàn)在主流的方案有三種(各有優(yōu)劣)爹脾。
1.利用Build Configuration來(lái)配置多環(huán)境
2.利用xcconfig文件來(lái)配置多環(huán)境
3.利用Targets來(lái)配置多環(huán)境
一帖旨、Build Configuration方式
做過(guò)ios開(kāi)發(fā)的人都知道Build Configuration,系統(tǒng)默認(rèn)提供2個(gè)環(huán)境灵妨,一個(gè)Debug解阅,一個(gè)Release。這里泌霍,我們利用的就是Build Configuration給我們提供的配置功能來(lái)實(shí)現(xiàn)多環(huán)境打包瓮钥。具體步驟如下:
1,新建Build Configuration
點(diǎn)擊Project里面找到Configuration烹吵,然后選擇添加一個(gè)Configuration碉熄,系統(tǒng)默認(rèn)是2個(gè),一個(gè)Debug肋拔,一個(gè)Release锈津。這里我們需要選擇是復(fù)制一個(gè)Debug還是Release。Release是不能調(diào)試程序凉蜂,因?yàn)槟J(rèn)是屏蔽了可調(diào)試的一些參數(shù)琼梆。
這里我們新增一套環(huán)境:Configuration。在這一套包含了一些編譯參數(shù)的配置集合窿吩。如果此時(shí)項(xiàng)目里面有cocopods的話茎杂,打開(kāi)Configuration Set就會(huì)發(fā)現(xiàn)是如下的樣子。
然后打開(kāi)項(xiàng)目的pod文件纫雁,打開(kāi)配置是會(huì)看到如下信息:
說(shuō)明:pod安裝完成之后會(huì)自動(dòng)生成xcconfig文件煌往,如果你手動(dòng)新建這個(gè)xcconfig,然后把原來(lái)的debug和release對(duì)應(yīng)的pod xcconfig文件內(nèi)容復(fù)制進(jìn)來(lái)轧邪,這樣做是無(wú)效的刽脖,需要pod自己去生成xcconfig文件才能被識(shí)別到羞海。
新建完Build Configuration,這個(gè)時(shí)候需要新建pod里面對(duì)應(yīng)的Build Configuration曲管,要不然一會(huì)編譯會(huì)報(bào)錯(cuò)却邓。如果沒(méi)用pod,可以忽略一下這一段院水。
2腊徙,新建Scheme
新建完成之后,我們就可以編輯剛剛新建的Scheme檬某,我們可以把Run模式和Archive都改成新建Scheme撬腾。
注意:如果是使用了Git這些協(xié)同工具的同學(xué)這里還需要把剛剛新建的Scheme共享出去,否則其他人看不到這個(gè)Scheme橙喘。
3,新建User-defined Build Settings
回到Project的Build Settings里面來(lái)胶逢,Add User-Defined Setting厅瞎。
CustomAppBundleld是為了之后打包可以分開(kāi)打成多個(gè)包,這里需要3個(gè)不同的Id初坠,建議是直接在原來(lái)的Bundleld加上Scheme的名字即可和簸。CustomProductName為app顯示在手機(jī)上的名字,建議直接按環(huán)境給予描述碟刺,例如:測(cè)試(debug)锁保,線上(relase),UAT等半沽。
需要注意的是:Pods的Build_DIR這些目錄其實(shí)是Pods自己生成好的爽柒,之前執(zhí)行過(guò)Pod install 之后,這里默認(rèn)都是配置好的者填,不需要再改動(dòng)了浩村。
4,修改info.plist文件 和 Images.xcassets
打開(kāi)info.plist文件占哟。由于我們新添加了2個(gè)CustomAppBundleld 和 CustomProductName心墅,這里我們需要把info.plist里面的Bundle display name修改成我們自定義的這個(gè)字典。編譯過(guò)程中榨乎,編譯器會(huì)根據(jù)我們?cè)O(shè)置好的Scheme去自己選擇Debug怎燥,Release,TestRelease分別對(duì)應(yīng)的ProductName蜜暑。
為了方便區(qū)分不同的環(huán)境铐姚,你還可以對(duì)不同環(huán)境下App Icon,名字等做一個(gè)修改肛捍。
既然我們已經(jīng)新建了這幾個(gè)scheme谦屑,那接下來(lái)怎么把他們都打包成app呢驳糯?
這里分享下實(shí)際打包過(guò)程中的一些經(jīng)驗(yàn)。
每個(gè)環(huán)境都要設(shè)置好Debug 和 ReleaseG獬取T褪唷!
千萬(wàn)別認(rèn)為線上的版本只設(shè)置Release就好悍手,哪天需要調(diào)試線上版本帘睦,沒(méi)有設(shè)置Debug就無(wú)從下手了。也千萬(wàn)別認(rèn)為測(cè)試環(huán)境的版本只要設(shè)置Debug就好坦康,萬(wàn)一哪天要發(fā)布一個(gè)測(cè)試環(huán)境需要發(fā)Release包竣付,那又無(wú)從下手了。我的建議就是每個(gè)環(huán)境都配置Debug 和 Release滞欠。
在打包的時(shí)候古胆,一定要注意將Scheme的名字和編譯方式區(qū)分開(kāi)。選擇一個(gè)Scheme筛璧,只是相當(dāng)于選擇了一個(gè)環(huán)境逸绎,并不是代表這Debug還是Release。
配置好上述之后夭谤,就可以選擇不同環(huán)境運(yùn)行app了棺牧。可以在手機(jī)上生成不同的環(huán)境的app朗儒,可以同時(shí)安裝颊乘。
接下來(lái)說(shuō)幾種動(dòng)態(tài)配置環(huán)境變量的方法。
動(dòng)態(tài)配置環(huán)境變量
使用GCC預(yù)編譯頭參數(shù)GCC_PREPROCESSOR_DEFINITIONS
進(jìn)入到Build Settings里面醉锄,可以找到Apple LLVM Preprocessing乏悄,找到Preprocessor Macros,在這里我們是可以加一些環(huán)境變量的宏定義來(lái)標(biāo)識(shí)符恳不。Preprocessor Macros可以根據(jù)不同的環(huán)境預(yù)先制定不同定義的宏纲爸。
使用plist文件動(dòng)態(tài)配置環(huán)境變量
首先,新建3個(gè)名字一樣的plist作為3個(gè)環(huán)境的配置文件(新建三個(gè)配置文件妆够,分別放在3個(gè)不同文件夾下面即可)识啦。
接下來(lái)我們要做的是在編譯的時(shí)候(運(yùn)行app前),動(dòng)態(tài)的copy Configuration.plist到app里面神妹,這里需要設(shè)置一個(gè)copy腳本颓哮。
進(jìn)入到我們的Target里面,找到Build Phases鸵荠,我們新建一個(gè)New Copy Files Phase冕茅,并且重命名為Copy Configuration Files。其中,腳本能保證我們的Configuration.plist 文件可以在編譯的時(shí)候姨伤,選擇其中一個(gè)打包進(jìn)入app哨坪。再通過(guò)讀取這個(gè)plist里面的信息就可以做到動(dòng)態(tài)化。
使用單例來(lái)處理環(huán)境切換
當(dāng)然使用一個(gè)單例也可以做到環(huán)境切換乍楚。新建一個(gè)單例当编,然后可以在設(shè)置菜單里面加入一個(gè)列表,里面列出所有的環(huán)境徒溪,然后用戶選擇以后忿偷,單例就初始化用戶所選的環(huán)境。
二臊泌、利用xcconfig文件配置多環(huán)境
提到xcconfig鲤桥,就要先說(shuō)說(shuō)幾個(gè)概念。Xcode Workspace渠概、Xcode Scheme茶凳、Xcode Project、Xcode Target播揪、Build Settings 贮喧。
Xcode Project
project就是一個(gè)個(gè)的倉(cāng)庫(kù),里面會(huì)包含屬于這個(gè)項(xiàng)目的所有文件剪芍,資源塞淹,以及生成一個(gè)或者多個(gè)軟件產(chǎn)品的信息窟蓝。每一個(gè)project會(huì)包含一個(gè)或者多個(gè) targets罪裹,而每一個(gè) target 告訴我們?nèi)绾紊a(chǎn) products。project 會(huì)為所有 targets 定義了默認(rèn)的 build settings运挫,每一個(gè) target 也能自定義自己的 build settings状共,且 target 的 build settings 會(huì)重寫 project 的 build settings。
Xcode Project 文件會(huì)包含以下信息谁帕,對(duì)資源文件的引用(源碼.h和.m文件峡继,frame,資源文件plist匈挖,bundle文件等碾牌,圖片文件image.xcassets還有Interface Builder(nib),storyboard文件)儡循、文件結(jié)構(gòu)導(dǎo)航中用來(lái)組織源文件的組舶吗、Project-level build configurations(Debug\Release)、Targets择膝、可執(zhí)行環(huán)境誓琼,該環(huán)境用于調(diào)試或者測(cè)試程序。
Xcode Target
target 會(huì)有且唯一生成一個(gè) product, 它將構(gòu)建該 product 所需的文件和處理這些文件所需的指令集整合進(jìn) build system 中。Projects 會(huì)包含一個(gè)或者多個(gè) targets,每一個(gè) target 將會(huì)產(chǎn)出一個(gè) product腹侣。需要注意的是叔收, Project 可以包含多個(gè) target, 但是在同一時(shí)刻,只會(huì)有一個(gè) target 生效傲隶,可用 Xcode 的 scheme 來(lái)指定是哪一個(gè) target 生效饺律。
Build Settings
build setting 中包含了 product 生成過(guò)程中所需的參數(shù)信息。project的build settings會(huì)對(duì)于整個(gè)project 中的所有targets生效伦籍,而target的build settings是重寫了Project的build settings蓝晒,重寫的配置以target為準(zhǔn)。
一個(gè) build configaration 指定了一套 build settings 用于生成某一 target 的 product帖鸦,例如Debug和Release就屬于build configaration芝薇。
Xcode Scheme
一個(gè)Scheme就包含了一套targets(這些targets之間可能有依賴關(guān)系),一個(gè)configuration作儿,一套待執(zhí)行的tests洛二。
xcconfig使用
1,新建一個(gè)xcconfig文件,然后在project設(shè)置一下攻锰。
接下來(lái)晾嘶,把配置文件換成我們剛剛新建的文件。細(xì)心的讀者可能發(fā)現(xiàn)娶吞,其實(shí)我們一直使用的cocopods就是用這個(gè)文件來(lái)配置編譯參數(shù)的垒迂。
GCC_PREPROCESSOR_DEFINITIONS 是 GCC 預(yù)編譯頭參數(shù),通常我們可以在 Project 文件下的 Build Settings 對(duì)預(yù)編譯宏定義進(jìn)行默認(rèn)賦值妒蛇。
在Build Settings里面的 Apple LLVM 7.X - Preprocessing - Preprocessor Macros 机断。
Preprocessor Macros 其實(shí)是按照 Configuration 選項(xiàng)進(jìn)行默認(rèn)配置的, 它是可以根據(jù)不同的環(huán)境預(yù)先制定不同定義的宏,或者為不同環(huán)境下的相同變量定義不同的值绣夺。
在xcconfig 我們可以寫入不同的 Configuration 選項(xiàng)配置不同的文件吏奸。每一個(gè) xcconfig 可以配置 Build Settings 里的屬性值, 其實(shí)實(shí)質(zhì)就是通過(guò) xcconfig 去修改 GCC_PREPROCESSOR_DEFINITIONS 的值,這樣我們就可以做到動(dòng)態(tài)配置環(huán)境的需求了陶耍。
現(xiàn)在本地有這么多配置奋蔚,到底哪一個(gè)最終生效呢?打開(kāi)Build 里面的level烈钞,優(yōu)先級(jí)是從左往右泊碑,依次降低的。Resolved = target-level > project-level > 自定義配置文件 > iOS 默認(rèn)配置毯欣。
除了上面的功能以為馒过,還能利用xcconfig動(dòng)態(tài)配置Build Settings里面的很多參數(shù)。這其實(shí)類似于cocopods的做法仪媒。詳情資料請(qǐng)大家自行搜索沉桌。
三谢鹊、利用Targets配置多環(huán)境
其實(shí)使用Scheme和xcconfig就可以實(shí)現(xiàn)多環(huán)境的功能,使用Targets反而顯得更加麻煩留凭。利用Targets可以瞬間大批量產(chǎn)生大量的app佃扼。相關(guān)使用可以查看:使用多Target來(lái)構(gòu)建大量相似App
僅僅只用一套代碼,就可以生產(chǎn)出7個(gè)app蔼夜。7個(gè)app的證書都是不同的兼耀,配置也都不同,但是代碼只需要維護(hù)一套代碼求冷,就可以完成維護(hù)7個(gè)app的目標(biāo)瘤运。
下面來(lái)看一下如何使用Targets來(lái)生成不同的app。
一種方法是完全新建一個(gè)Targets匠题,另外一種方法是復(fù)制原有的Targets拯坟。
其實(shí)第一種方法建立出Targets,之后看你需求是怎么樣的韭山。如果也想是做OEM這種郁季,可以把新建出來(lái)的project刪掉,本地還是維護(hù)一套代碼钱磅,然后在新建的Targets 的Build Phases里面去把本地現(xiàn)有代碼加上梦裂,參數(shù)自己可以隨意配置。這樣也是一套代碼維護(hù)多個(gè)app盖淡。
第二種方法就是復(fù)制一個(gè)原有的Targets年柠,這種做法只用自己去改參數(shù)就可以了。
再來(lái)說(shuō)說(shuō)Targets的參數(shù)褪迟。
由于我們新建了Targets冗恨,相當(dāng)于新建了一個(gè)app了。所以里面的所有的文件全部都可以更改牵咙。包括info.plist派近,源碼引用攀唯,Build Settings……所有參數(shù)都可以改洁桌,這樣就不僅僅局限于修改Scheme和xcconfig,所以之前說(shuō)僅僅配置一個(gè)多環(huán)境用Targets有點(diǎn)興師動(dòng)眾侯嘀,但是它確實(shí)能完成目的另凌。根據(jù)第二章里面我們也提到了,Targets相當(dāng)于流水線戒幔,僅次于Project的地位吠谢,可以想象,有了Targets诗茎,我們沒(méi)有什么不能修改的工坊。
注意點(diǎn)
在開(kāi)發(fā)過(guò)程中遇到比較坑爹的問(wèn)題:證書不使用xcode的Automatically manage signing
的時(shí)候献汗,(環(huán)境不同bundle ID
不同的時(shí)候)每個(gè)版本選擇不同的描述文件,需要注意的地方 bundle ID
依Build Settings
中Package
分欄下的Product Bundle Identifier
的為準(zhǔn)王污,要不然選擇描述文件的時(shí)候有問(wèn)題罢吃,就會(huì)提示
The provisioning profile specified in your build settings ("xxx") has an AppID of "com.xxx" which does not match your bundle identifier "com.xxx"
http://blog.csdn.net/l2i2j2/article/details/51661443