作者:Eugene Trapeznikov,原文鏈接,原文日期:2016-01-18
譯者:小鍋;校對:Channe;定稿:numbbbbb
一些初學(xué)者可能會(huì)好奇,為什么在開發(fā)應(yīng)用的時(shí)候我們需要用兩套隔離的數(shù)據(jù)庫和環(huán)境。這是因?yàn)樵谀愠掷m(xù)地開發(fā)應(yīng)用或增加新特性的時(shí)候,可能希望將開發(fā)版本和已經(jīng)存在的生產(chǎn)版本的應(yīng)用進(jìn)行區(qū)分。標(biāo)準(zhǔn)的開發(fā)實(shí)踐是針對不同版本的軟件使用不同的環(huán)境,而對我們來說,這個(gè)軟件就是 iPhone 應(yīng)用。一般來講,開發(fā)版應(yīng)用使用的數(shù)據(jù)庫(或其它系統(tǒng),比如說統(tǒng)計(jì)分析系統(tǒng))應(yīng)該與生產(chǎn)版應(yīng)用進(jìn)行區(qū)分。在測試或者開發(fā)環(huán)境中,我們經(jīng)常使用到類似 "test comment", "argharghargh" 和 "one more test comment" 這樣的測試數(shù)據(jù)。很顯然,我們并不想讓真實(shí)的用戶看到這樣的信息。如果應(yīng)用使用了統(tǒng)計(jì)分析系統(tǒng),在測試階段我們可能會(huì)發(fā)送成千上萬次的統(tǒng)計(jì)事件。我們當(dāng)然也不想讓這樣的數(shù)據(jù)跟真實(shí)的統(tǒng)計(jì)數(shù)據(jù)混在一起。這就是為什么我們應(yīng)該區(qū)分開發(fā)環(huán)境和生產(chǎn)環(huán)境。
當(dāng)使用不同的環(huán)境開發(fā)時(shí),應(yīng)用需要知道它當(dāng)前使用的環(huán)境。一種通用的做法是在程序的 AppDelegate 中定義一個(gè)可以將應(yīng)用初始化為開發(fā)或者生產(chǎn)模式的全局變量。
enum environmentType {
case development, production
}
let environment:environmentType = .production
switch environment {
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)境的時(shí)候改變?nèi)肿兞康闹怠km然這種方法很方便也很快捷,但是它存在很大的局限性。首先,因?yàn)樵陂_發(fā)與生產(chǎn)環(huán)境中都使用了同一個(gè) bundle ID,我們就不能在同一個(gè)設(shè)備上同時(shí)安裝應(yīng)用的不同版本。再者,這種方法有可能導(dǎo)致我們不小心把開發(fā)版本的應(yīng)用提交到 App Store 上。如果忘記切換全局變量的值,我們就會(huì)提交錯(cuò)誤版本的應(yīng)用。我曾經(jīng)就有一次在提交應(yīng)用之前忘記改變?nèi)肿兞康闹担Y(jié)果用戶就使用到了我的開發(fā)版本。這實(shí)在是太糟糕了。
在本篇文章中我將會(huì)展示一種更好的方法來區(qū)分開發(fā)和生產(chǎn)的構(gòu)建版本。更確切地來說,我們將會(huì)在 Xcode 中創(chuàng)建一個(gè)開發(fā)版的 target。這個(gè)方法同時(shí)適用于新建的或現(xiàn)存的大型項(xiàng)目,所以你可以使用一個(gè)現(xiàn)有的項(xiàng)目來跟著這個(gè)教程進(jìn)行實(shí)踐。
使用這種方法,生產(chǎn)版和開發(fā)版的應(yīng)用都會(huì)使用同一套基礎(chǔ)代碼,但是可以有不同的圖標(biāo)、bundle ID 以及不同的數(shù)據(jù)庫。分發(fā)和提交應(yīng)用的過程也會(huì)十分簡單。更重要地,應(yīng)用的測試人員和管理人員可以在同一個(gè)設(shè)備上同時(shí)安裝應(yīng)用的兩個(gè)版本,這樣他們就可以更加清楚地了解他們現(xiàn)在試用的是哪一個(gè)版本。
如何創(chuàng)建新的 Target
那么我們?nèi)绾卧?Xcode 當(dāng)中新建一個(gè)開發(fā)版的 target 呢?我會(huì)使用我提供的示例項(xiàng)目 "todo" 來一步一步地進(jìn)行演示。你可以使用自己的項(xiàng)目,并跟隨這些步驟進(jìn)行操作:
-
在 Project Navigator 面板上選擇項(xiàng)目,進(jìn)入設(shè)置。在 Targets 小節(jié)下面,右擊現(xiàn)有的 target 并且選擇
Duplicate
來對一個(gè)現(xiàn)在的 target 進(jìn)行復(fù)制。Duplicate-target -
Xcode 會(huì)詢問你這個(gè) target 是不是針對于 iPad 開發(fā)的。對于本教程來說,我們只需要選擇 "Duplicate Only" 就可以了。
Duplicate-only提示:如果你的項(xiàng)目支持通用設(shè)置,則 Xcode 不會(huì)提示上面的消息。
-
現(xiàn)在我們有了一個(gè)名為
todo copy
的新 target 和構(gòu)建 scheme 。讓我們來重命名一下以便于區(qū)分。在 TARGETS 列表中選擇新創(chuàng)建的 target。按下
回車鍵
來對它的名稱進(jìn)行編輯,并且給它起一個(gè)合適的名稱。我傾向于使用 "todo Dev"。當(dāng)然你可以使用你喜歡的任何名字。-
接下來,來到 "Manage Schemes…",選擇在第 1 步中新建的 scheme,并按下
回車鍵
。把新 scheme 命名為跟新 target 一樣的名字(?即我們上一小步中使用的名字)Target and scheme
-
這一步是可選的,不過我強(qiáng)烈建議進(jìn)行這一步。如果想讓開發(fā)版跟生產(chǎn)版的應(yīng)用更加容易區(qū)分,我們應(yīng)該提供不同的應(yīng)用圖標(biāo)和啟動(dòng)界面。這可以使測試更加清楚他們現(xiàn)在使用的版本,并且可以防止我們提交開發(fā)版本的應(yīng)用到商店中。 ??
選中
Assets.xcassets
然后添加新的 App 圖標(biāo)。選擇 icon > App Icons & Launch Images > New iOS App Icon. 將新圖標(biāo)命名為 "AppIcon-Dev" 并且添加你需要的圖片。image-asset-dev -
現(xiàn)在回到項(xiàng)目設(shè)置,選擇開發(fā)版的 target 然后修改 bundle ID。可以簡單地在原來的 ID 上添加一個(gè) "Dev" 后綴。如果有操作過第 4 步,在這里確保你的 app 圖標(biāo)設(shè)置為在上一步中添加的圖標(biāo)。
New App ID Icon Xcode 會(huì)自動(dòng)為新的 target 創(chuàng)建一個(gè) plist 文件(一般命名為 todo copy-Info.plist)。可以在項(xiàng)目的根目錄下找到這個(gè)文件。將 "copy" 修改為 "Dev",然后將它放到原來的 plist 文件下方。這樣可以更方便我們對文件進(jìn)行操作。
-
現(xiàn)在選擇開發(fā)版 target 下的 "Build Settings",滾動(dòng)到 "Packaging",然后修改指定 plist 文件為開發(fā)版 plist(即剛剛的 todo Dev.plist)。
new plist -
最后,為生產(chǎn)版和開發(fā)版 target 同時(shí)設(shè)置一個(gè)預(yù)處理宏和編譯器標(biāo)志。這樣在之后的開發(fā)中我們就可以在代碼中使用這個(gè)標(biāo)識(shí)來檢測當(dāng)前運(yùn)行的應(yīng)用是哪個(gè)版本。
對于 Objective-C 項(xiàng)目,來到
Building Settings
,滾動(dòng)到Apple LLVM 7.0 - Preprocessing
。展開Preprocessor Macros
并且為 Debug 和 Release 添加一個(gè)變量。對于開發(fā)版 target(即 todo Dev),設(shè)置變量的值為DEVELOPMENT=1
(校對注:等號兩邊不能有空格)。相對地,設(shè)置開發(fā)版 target 的值為DEVELOPMENT=0
。dev-macro-1
dev-macro-2對于 Swift 項(xiàng)目,編譯器不再支持預(yù)處理指令了。相對地,它使用了運(yùn)行期屬性(compile-time attributes)和構(gòu)建配置。為了增加開發(fā)版構(gòu)建的標(biāo)志,選擇開發(fā) target。來到
Build Settings
,向下滾動(dòng)到Swift Compiler - Custom Flags
小節(jié)。設(shè)置值為-DDEVELOPMENT
來表明當(dāng)前為 target 為開發(fā)版。swift-compiler-flag現(xiàn)在我們已經(jīng)創(chuàng)建并配置好了開發(fā)版的 target,接下來要做什么呢?
使用 Target 和宏
因?yàn)樵O(shè)置過了 DEV_VERSION
的宏,我們就可以在代碼中利用這個(gè)宏對項(xiàng)目使用動(dòng)態(tài)檢測了。這里有一個(gè)簡單的使用示例:
Objective-C:
objc
#if DEVELOPMENT
#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 當(dāng)中,我們可以使用 #if
來對 DEVELOPMENT
的狀態(tài)進(jìn)行檢測,并且為 URL/API 設(shè)置對應(yīng)的值。
Swift:
#if DDEVELOPMENT
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 當(dāng)中,我們依然可以使用 #if
來對構(gòu)建配置進(jìn)行動(dòng)態(tài)判斷。然而,我們不再使用 #define
來定義一個(gè)常量,而是簡單地使用 let
來定義一個(gè) Swift 中全局常量。
提示:一般情況下,我們會(huì)將上面的代碼放在 AppDelegate 當(dāng)中。不過最終取決于你想在哪里初始化應(yīng)用的配置。
當(dāng)選擇 "todo Dev" 的 scheme 并運(yùn)行項(xiàng)目,我們就會(huì)創(chuàng)建一個(gè)開發(fā)版的構(gòu)建并自動(dòng)將服務(wù)器配置設(shè)置為開發(fā)版的環(huán)境。你現(xiàn)在可以放心地上傳這個(gè)開發(fā)版到 TestFlight 或者 HockeyApp 讓應(yīng)用的測試人員或者管理人員進(jìn)行測試了。
以后如果需要?jiǎng)?chuàng)建一個(gè)生產(chǎn)版的構(gòu)建,只要簡單地選擇 "todo" 的 scheme。一行代碼都不需要改變。
關(guān)于管理多個(gè) Target 的一些注意事項(xiàng)
-
當(dāng)為項(xiàng)目添加新文件時(shí),不要忘記同時(shí)勾選多個(gè) target 來保持各個(gè) target 中的代碼一致。
-
如果你的項(xiàng)目中使用了 Cocoapods,不要忘記在 podfile 中增加新的 target。我們可以使用
link_with
來指定多個(gè) target。可以在 Cocoapods 文檔中找到更詳細(xì)的內(nèi)容。現(xiàn)在 Podfile 看起來應(yīng)該是這樣的:source 'https://github.com/CocoaPods/Specs.git' platform :ios, '7.0' workspace 'todo' link_with 'todo', 'todo Dev' pod 'Mixpanel' pod 'AFNetworking'
如果使用了持續(xù)集成系統(tǒng),比如 Travis CI 或 Jenkins,不要忘了每個(gè) target 的構(gòu)建和交付都要配置。
你覺得這個(gè)教程怎么樣呢?你是如何管理你的開發(fā)和生產(chǎn)構(gòu)建版本的?可以留言來告訴我你的想法。
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán),最新文章請?jiān)L問 http://swift.gg。