這篇文章由Eugene Trapeznikov貢獻劫灶。想象一下霞丧,你已經(jīng)完成了應(yīng)用程序的開發(fā)和測試劲妙,現(xiàn)在準(zhǔn)備提交正式版本湃鹊。問題是,一些web服務(wù)的url指向了測試服務(wù)器镣奋,同時API密鑰被配置用于測試環(huán)境币呵。在提交app給蘋果審核前,你需要修改所有這些API密鑰和URL以適應(yīng)生產(chǎn)版本侨颈。這聽起來還好余赢,對吧?但是相較于在開發(fā)環(huán)境和生產(chǎn)環(huán)境之間來回修改相關(guān)數(shù)值肛搬,有沒有更好的方法來處理開發(fā)和生產(chǎn)版本的構(gòu)建没佑?這正是接下來Eugene要和你討論的毕贼。
進入Eugene的教程
對于初學(xué)者來說温赔,有些人可能會奇怪,在App開發(fā)過程中鬼癣,為什么需要使用兩個單獨的數(shù)據(jù)庫和環(huán)境陶贼。原因是當(dāng)你繼續(xù)構(gòu)建新的功能特性或繼續(xù)開發(fā)你的應(yīng)用,你希望區(qū)分開現(xiàn)有的公開版本和生產(chǎn)版本待秃。
標(biāo)準(zhǔn)的軟件開發(fā)實踐是在不同的開發(fā)環(huán)境下開發(fā)不同版本的軟件拜秧,像我們案例中講到的開發(fā)iphone應(yīng)用。應(yīng)用程序的開發(fā)版本通常使用一個不同于生產(chǎn)環(huán)境的數(shù)據(jù)庫(或如分析的其他系統(tǒng))章郁。這就是為什么我們應(yīng)該為不同的環(huán)境中使用單獨的服務(wù)器和數(shù)據(jù)庫枉氮。開發(fā)人員在測試期間通常都使用虛擬圖像或虛擬數(shù)據(jù)。在測試環(huán)境中暖庄,使用諸如 “test comment”, “argharghargh” 和 “one more test comment”之類的測試數(shù)據(jù)并不少見聊替。顯然,你不希望你的真實用戶看到這樣的消息培廓。如果你的應(yīng)用程序使用了一個分析系統(tǒng)的情況下惹悄,你甚至?xí)跍y試階段發(fā)送成千上萬的事件。同樣的,你不會把測試數(shù)據(jù)和生產(chǎn)數(shù)據(jù)放在同一個數(shù)據(jù)庫中肩钠。這就是為什么總是推薦區(qū)分開發(fā)和生產(chǎn)環(huán)境泣港。
在使用兩個獨立的環(huán)境時暂殖,你的應(yīng)用程序需要有一個辦法找出它應(yīng)該連接到的環(huán)境。一種常用的方法是在你的主應(yīng)用代理里定義一個全局變量当纱,它會將您的應(yīng)用程序初始化為開發(fā)或生產(chǎn)模式呛每。
enumenvironmentType?{
casedevelopment,?production
}
let?environment:environmentType?=?.production
switchenvironment?{
case.development:
//?set?web?service?URL?to?development
//?set?API?keys?to?development
print("It's?for?development")
case.production:
//?set?web?service?URL?to?production
//?set?API?keys?to?production
print("It's?for?production")
}
這種方法需要你每次切換環(huán)境時改變?nèi)肿兞俊km然這種方法也許快捷坡氯,方便莉给,但是它有一些重要的限制。首先廉沮,因為我們在開發(fā)和生產(chǎn)兩個環(huán)境中使用一個Bundle ID颓遏,你不能在一臺設(shè)備上安裝應(yīng)用的兩個版本。當(dāng)你需要要測試開發(fā)版本的應(yīng)用程序時滞时,同時仍在該設(shè)備上使用生產(chǎn)版本的應(yīng)用叁幢,這就變的不方便了。此外坪稽,這種方法很有可能將應(yīng)用的開發(fā)版本上傳到應(yīng)用商店曼玩。如果你忘記了改變這個全局變量,你將會上傳錯誤的應(yīng)用給你的用戶窒百。我記得有一次在提交應(yīng)用程序到應(yīng)用商店之前我忘記改變?nèi)肿兞渴蚺校脩粝螺d的是應(yīng)用的開發(fā)版本,這是可怕的篙梢。
在這篇文章中顷帖,我將展示一個更好的方法來區(qū)分開發(fā)和生產(chǎn)構(gòu)建。具體而言渤滞,我們將在Xcode中創(chuàng)建一個開發(fā)的target贬墩。這種方法法適用于新的和現(xiàn)有的大型項目,所以你可以用一個現(xiàn)有的應(yīng)用程序?qū)φ毡窘坛獭?/p>
通過應(yīng)用這種方法妄呕,應(yīng)用的開發(fā)和生產(chǎn)版本將使用相同的基礎(chǔ)代碼陶舞,但可以有不同的圖標(biāo),bundle ID 和指向不同的數(shù)據(jù)庫绪励。發(fā)布和提交過程將會非常簡單肿孵。最重要的是,你的測試人員和經(jīng)理可以在同一設(shè)備上安裝兩個版本的應(yīng)用程序,所以他們完全知道他們在體驗?zāi)膫€版本。
如何創(chuàng)建一個新的Target
所以你如何在Xcode中創(chuàng)建一個開發(fā)的target?我使用示例項目“todo”引導(dǎo)您一步一步完成整個過程疏魏。停做。您也可以使用自己的項目并按照步驟:
1. 在項目的導(dǎo)航面板進入項目設(shè)置。在Targets區(qū)域下蠢护,右鍵單擊現(xiàn)有目標(biāo)并選擇 `Duplicate` 復(fù)制現(xiàn)有的目標(biāo)雅宾。
2.Xcode會詢問你新的target是否是為iPad開發(fā)。對于本教程,我們只是選擇“Duplicate Only”。
提示:如果您的項目支持通用設(shè)備眉抬,Xcode不會提示上述消息贯吓。
3.現(xiàn)在我們有一個名為`todo copy`的新的target和build scheme。重命名并使之更容易理解蜀变。
在Targets列表中選擇新的target悄谐。按Enter鍵編輯文本,添加一個更合適的名字库北。我更傾向于“todo Dev”爬舰。你可以自由選擇任何你喜歡的名字。
接下來寒瓦,找到“Manage Schemes…”情屹,選擇您在步驟1中創(chuàng)建的shceme,并按“輸入”,使scheme的名稱和新的target的名稱相同(這是你為新的target所選擇的名字)
4. 步驟4是可選的杂腰,但強烈推薦垃你。如果你想簡單地區(qū)分開發(fā)和生產(chǎn)版本構(gòu)建,你應(yīng)該為每個版本使用單獨的icon和啟動頁喂很。這將使測試人員更清晰地知道正在使用哪個app,防止上傳開發(fā)版本惜颇。
跳到 `Assets.xcassets` 添加一個新的圖標(biāo)。右擊圖標(biāo) >?App Icons & Launch Images?>?New iOS App Icon. 新圖標(biāo)重命名為“AppIcon-Dev”同時添加自己的圖片少辣。
5.現(xiàn)在回到項目設(shè)置,選擇您的開發(fā)target凌摄,并改變Bundle Identifier。你可以簡單地將“Dev”追加到原來的ID上漓帅。如果執(zhí)行了步驟4锨亏,請確保更改應(yīng)用app icon,設(shè)置為在上一步中創(chuàng)建的煎殷。
6. Xcode會自動為你的target添加plist文件(如todo copy-Info.plist)屯伞。你可以在項目的根文件夾找到它。將它從“copy”重命名為“Dev”,并將它放在原始的plist文件下豪直。這里你將更容易管理文件。
7. 現(xiàn)在打開你開發(fā)target的“Build Settings”珠移,滾動到“Packaging”弓乙,并將值改為開發(fā)的plist文件(todo Dev.plist)。
8. 最后钧惧,我們會為生產(chǎn)和開發(fā)target配置預(yù)處理宏/編譯器標(biāo)識暇韧。之后我們就可以使用該標(biāo)識在我們的代碼來檢測應(yīng)用程序正在運行的版本。
對于Objective-C的項目浓瞪,去到`Build Settings`下`Apple LLVM 7.0 - Preprocessing`懈玻。拓展`Preprocessor Macros`在Rebug和Release區(qū)域添加一個變量。對于開發(fā)target(即todo Dev)乾颁,將該值設(shè)置為`DEVELOPMENT = 1`涂乌。另一個艺栈,將值設(shè)為`DEVELOPMENT=0`來表示生產(chǎn)版本。
對于swift的項目湾盒,編譯器不再支持預(yù)處理指令湿右。作為替代,它使用編譯時的屬性和build配置罚勾。選中開發(fā)target毅人,添加一個標(biāo)識表示開發(fā)版本。找到`Build Setting`往下滾動到`Swift Compiler - Custom Flags`部分尖殃。將值設(shè)為`-DDEVELOPMENT`表示這個target作為開發(fā)版本丈莺。
現(xiàn)在,您已經(jīng)創(chuàng)建并配置了開發(fā)target送丰,下一步呢场刑?
使用Target和宏
根據(jù)已配置的宏DEV_VERSION,我們可以在代碼中利用它動態(tài)地編譯項目蚪战。下面是一個簡單的例子:
Objective-C:
#ifDEVELOPMENT
#define?SERVER_URL?@"http://dev.server.com/api/"
#define?API_TOKEN?@"DI2023409jf90ew"
#else
#define?SERVER_URL?@"http://prod.server.com/api/"
#define?API_TOKEN?@"71a629j0f090232"
#endif
Objective-C中你可以使用`#if`檢查`DEVELOPMENT`的環(huán)境牵现,并相應(yīng)的設(shè)置URLs/ API密鑰。
Swift:
#ifDEVELOPMENT
let?SERVER_URL?="http://dev.server.com/api/"
let?API_TOKEN?="DI2023409jf90ew"
#else
let?SERVER_URL?="http://prod.server.com/api/"
let?API_TOKEN?="71a629j0f090232"
#endif
Swift中你仍然可以使用`#if`判定build的參數(shù)動態(tài)編譯邀桑。然而瞎疼,除了使用`#define`定義基本常量,在swift中我們也可以用`let`定義一個全局常量壁畸。
提示:通常贼急,你會把上面的代碼放在app delegate中。但這最終是取決于你在哪里初始化應(yīng)用程序設(shè)置捏萍。
現(xiàn)在太抓,當(dāng)您選擇“todo Dev”scheme運行項目,你創(chuàng)建開發(fā)版本會自動將服務(wù)器的配置設(shè)置為開發(fā)環(huán)境×铊荆現(xiàn)在走敌,您可以上傳開發(fā)版本到TestFlight 或 HockeyApp供測試人員和管理人員來測試。
接著如果你需要創(chuàng)建一個生產(chǎn)版本逗噩,您可以簡單地選擇"todo"scheme掉丽。不需要更改代碼。
管理多個target的一些注意事項
1.當(dāng)你添加新的文件到項目中异雁,不要忘記選擇兩個target捶障,以保持你的代碼同步在兩個版本。
2.如果你使用的CocoaPods纲刀,不要忘了添加新的target到你的podfile中项炼。您可以使用`link_with`指定多個target。您可以進一步細(xì)節(jié)請查閱的CocoaPods文檔。你的podfile看起來是這樣的:
source'https://github.com/CocoaPods/Specs.git'
platform?:ios,'7.0'
workspace'todo'
link_with'todo','todo?Dev'
pod'Mixpanel'
pod'AFNetworking'
3.如果你使用持續(xù)集成系統(tǒng)锭部,如Travis CI或Jenkins暂论,別忘了配置兩個target的build和deliver。
你對這個教程有什么想法空免?如何管理你的開發(fā)和生產(chǎn)構(gòu)建空另?給我留言評論分享您的想法