這是我基于英文原文翻譯的譯文,如果你對本文感興趣而且想轉發,你應該在轉發文章里加上本文的鏈接

想象一下當你完成開發和測試,準備提交到生產環境時的場景時,你會遇到這么一個問題:所有你的API keys,URL,icon或者其他啟動配置都是開發環境的。所以在你發布你的app的時候,你不得不為了適應生產環境而把他們全部改過來。顯然,這做法不太好。有時候,由于你的app太復雜,你可能會忘記一些改動,從而導致服務不能正常工作。
不像這些糟糕的做法,本文的做法將會根據我們的需要去配置不同的環境,并且改動配置非常簡單。現在,我們將討論幾種最常見的環境配置管理的方法:
- 1、使用注釋
- 2、使用全局變量或枚舉
- 3、通過一個全局標記flag使用配置和schemes
- 4、通過 *.plist 文件使用配置和schemes
1、使用注釋
當你有兩個獨立的環境,你的應用需要知道它應該使用那個環境。想象一下,你有生產,開發,演示三個環境和API接口。那么環境切換的最快最簡單方法就是注釋其他兩個環境。
// MARK: - Development
let APIEndpointURL = "http://mysite.com/dev/api"
let analyticsKey = "jsldjcldjkcs"
// MARK: - Production
// let APIEndpointURL = "http://mysite.com/prod/api"
// let analyticsKey = "sdcsdcsdcdc"
// MARK: - Staging
// let APIEndpointURL = "http://mysite.com/staging/api"
// let analyticsKey = "lkjllnlnlk
這個方法非常暴力,混亂,讓人看到都想哭。有時不需要關心代碼質量和可維護性的時候,我會使用這種黑科技。換句話說,我強力建議不要使用這種方法。
2、使用全局變量或枚舉
另一種流行的做法,是通過一個全局變量或枚舉(這個會好一點)來處理不同的配置環境。你需要在某個地方(例如AppDelegate)聲明您的三個不同環境的枚舉和設置它們的值。
enum Environment {
case development
case staging
case production
}
let environment: Environment = .development
switch environment {
case .development:
// set web service URL to development
// set API keys to development
print("It's for development")
case .staging:
// set web service URL to staging
// set API keys to development
print("It's for staging")
case .production:
// set web service URL to production
// set API keys to production
print("It's for production")
}
這種做法保證你可以只改變一處代碼就能配置不同的環境。與之前的方法不同,這個會好很多。這種做法非常靈活,可讀性更強,但它有很多局限性。首先,在不同環境下運行都只有一個相同的Bundle ID。這就意味著你講不能同時裝上不同環境的相同app。這種做法其實也是不太合適。
除此以外,這種做法也不能根據不同的環境改變app的icons。而且,如果你在提交app之前忘記更改這個全局變量,你肯定會出問題。
我們再看看其他兩種更好的實現方法。這些方法對于新項目和舊項目都適合。跟著這個教程,你可以很容易將它應用到就項目中。
After applying these approaches your app will have the same codebase for every environment, but you will be able to have different icons and different Bundle ID’s for every configuration. The distribution process also will be very easy. And what is the most important, your managers and testers will be able to have all your environments as separated apps on their devices. So they will fully understand which version they’re trying out.
使用這些方法后,你的app只有一份代碼庫,但你可以根據不同環境配置有不同icons和Bundle ID。這會讓你的發布變得非常簡單。最重要的是,你的老大和測試可以有多個不同環境的相同app,因此他們非常清楚他們正在測試的是那個版本的應用。
3、通過一個全局標記flag使用配置和schemes
在這種做法中,我們將創建三個不同的配置,三個不同的schemes和與schemes相關的配置。為了演示這種做法,我將新建一個“Environments”項目,你也可以創建一個新項目或者在老項目中做。
在項目導航的面板中找到項目設置,在targets的列表中右擊已存在的target,然后選擇 Duplicate 來復制當前target。
現在我們有不止一個的target和叫‘Environments copy’的build scheme。我們先把它們改成對應的名字。點擊您的新target和按下“Enter”鍵,改target的名字為“Environments Dev”。然后,去到“Manage Schemes…”,選擇剛才新創建的scheme,按下“Enter”,重命名你的target,避免命名混亂。
同樣的,我們可以新建一個icon asset,這樣測試和老大就能知道打開的是哪個app配置。去到Assets.xcassets,點擊 “+” ,選擇“New iOS App Icon”。修改它的名字為“AppIcon-Dev”。
現在我們要建立新的icons asset和我們開發環境的聯系。去到“Targets”,點擊你的開發環境,找到“App Icon Source”選擇新的icons asset。
就是這樣,現在你有每個環境的不同icons。請注意,當我們新建第二個配置時,第二個 *.plist 文件也會生成出來。
值得注意,我們現在有兩種不同的做法去處理兩種不同的配置:
- 1、添加一個預編譯宏標記去區分生產和開發targets。
- 2、在 *plist 文件中添加一個變量。
我們嘗試第一種方法。我們添加一個標記變量去標記選擇的開發環境。在“Build Settings”中,找到“Swift Compiler?—?Custom Flags”這個選項。設置 -DEVELOPMENT 來標記這個target是開發的build。
然后配置的代碼就像如下所示:
#if DEVELOPMENT
let SERVER_URL = "http://dev.server.com/api/"
let API_TOKEN = "asfasdadasdass"
#else
let SERVER_URL = "http://prod.server.com/api/"
let API_TOKEN = "fgbfkbkgbmkgbm"
#endif
現在,如果你選擇 Dev 的scheme運行,你就自動使用開發配置來啟動你的app了。
4、通過 *.plist 文件使用配置和schemes
在這種做法中,我們將重復之前那個創建新scheme的步驟。在做完這個步驟后,不像之前一樣添加一個全局標記,我們將把必要的值添加進我們的*.plist中。同樣的,我們將添加一個 serverBaseURL 字符串變量到每個 .plist 文件中,并把URLs作為值進行設置。現在每個.plist文件都包含一個URL,我們可以通過代碼來調用它。我認為,為我們的Bundle創建一個extension是一個好主意,像下面的代碼一樣:
extension Bundle {
var apiBaseURL: String {
return object(forInfoDictionaryKey: "serverBaseURL") as? String ?? ""
}
}
//And call it from the code like this:
let baseURL = Bundle.main.apiBaseURL
個人認為,我更喜歡這種方式多一點,因為你不需要在你的代碼中檢查你的配置。你僅僅需要選擇你的Bundle,然后它就會返回他自己當前的配置。
當使用多個targets時需要注意一些情況
- 記住在一個 *.plist 文件中你的數據存儲能被讀取是很可能不安全的。解決方法就是,把你的敏感的值放到代碼中,只把不敏感的放到 *.plist 文件中。
- 當添加一個新的文件時,不要忘記添加到所有的target中,以保證你的代碼在所有配置環境中都是一樣的。
- 如果你使用持續集成服務,例如 Travis CI 或 Jenkins,不要忘記正確配置它們。
Conclusion
結論
一開始用一種可讀性強且靈活的方法,去區分不同app環境,是很有必要的。甚至是那種我們避免使用的,最簡單的處理不同配置的方法,都能很好的提高我們的代碼質量。
我們從最簡單的開始,討論了幾種不同的做法。但是,還有很多其他不同環境配置方法我們沒有涉及到,我很希望在下面評論中看到其他的做法。
感謝大家的閱讀 :)
本文Github地址