原文:How to Use Xcode Targets to Manage Development and Production Builds
作者:EugeneTrapeznikov
譯者:CocoaChina--skymoon(CC論壇ID)
編者提示:這篇文章由Eugene Trapeznikov貢獻。想象一下,你已經完成了應用程序的開發和測試,現在准備提交正式版本。問題是,一些web服務的url指向了測試服務器,同時API密鑰被配置用於測試環境。在提交app給蘋果審核前,你需要修改所有這些API密鑰和URL以適應生產版本。這聽起來還好,對吧?但是相較於在開發環境和生產環境之間來回修改相關數值,有沒有更好的方法來處理開發和生產版本的構建?這正是接下來Eugene要和你討論的。
進入Eugene的教程
對於初學者來說,有些人可能會奇怪,在App開發過程中,為什麼需要使用兩個單獨的數據庫和環境。原因是當你繼續構建新的功能特性或繼續開發你的應用,你希望區分開現有的公開版本和生產版本。
標准的軟件開發實踐是在不同的開發環境下開發不同版本的軟件,像我們案例中講到的開發iphone應用。應用程序的開發版本通常使用一個不同於生產環境的數據庫(或如分析的其他系統)。這就是為什麼我們應該為不同的環境中使用單獨的服務器和數據庫。開發人員在測試期間通常都使用虛擬圖像或虛擬數據。在測試環境中,使用諸如 “test comment”, “argharghargh” 和 “one more test comment”之類的測試數據並不少見。顯然,你不希望你的真實用戶看到這樣的消息。如果你的應用程序使用了一個分析系統的情況下,你甚至會在測試階段發送成千上萬的事件。同樣的,你不會把測試數據和生產數據放在同一個數據庫中。這就是為什麼總是推薦區分開發和生產環境。
在使用兩個獨立的環境時,你的應用程序需要有一個辦法找出它應該連接到的環境。一種常用的方法是在你的主應用代理裡定義一個全局變量,它會將您的應用程序初始化為開發或生產模式。
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") }
這種方法需要你每次切換環境時改變全局變量。雖然這種方法也許快捷,方便,但是它有一些重要的限制。首先,因為我們在開發和生產兩個環境中使用一個Bundle ID,你不能在一台設備上安裝應用的兩個版本。當你需要要測試開發版本的應用程序時,同時仍在該設備上使用生產版本的應用,這就變的不方便了。此外,這種方法很有可能將應用的開發版本上傳到應用商店。如果你忘記了改變這個全局變量,你將會上傳錯誤的應用給你的用戶。我記得有一次在提交應用程序到應用商店之前我忘記改變全局變量,用戶下載的是應用的開發版本,這是可怕的。
在這篇文章中,我將展示一個更好的方法來區分開發和生產構建。具體而言,我們將在Xcode中創建一個開發的target。這種方法法適用於新的和現有的大型項目,所以你可以用一個現有的應用程序對照本教程。
通過應用這種方法,應用的開發和生產版本將使用相同的基礎代碼,但可以有不同的圖標,bundle ID 和指向不同的數據庫。發布和提交過程將會非常簡單。最重要的是,你的測試人員和經理可以在同一設備上安裝兩個版本的應用程序,所以他們完全知道他們在體驗哪個版本。
如何創建一個新的Target
所以你如何在Xcode中創建一個開發的target?我使用示例項目“todo”引導您一步一步完成整個過程。。您也可以使用自己的項目並按照步驟:
1. 在項目的導航面板進入項目設置。在Targets區域下,右鍵單擊現有目標並選擇 `Duplicate` 復制現有的目標。
2.Xcode會詢問你新的target是否是為iPad開發。對於本教程,我們只是選擇“Duplicate Only”。
提示:如果您的項目支持通用設備,Xcode不會提示上述消息。
3.現在我們有一個名為`todo copy`的新的target和build scheme。重命名並使之更容易理解。
在Targets列表中選擇新的target。按Enter鍵編輯文本,添加一個更合適的名字。我更傾向於“todo Dev”。你可以自由選擇任何你喜歡的名字。
接下來,找到“Manage Schemes…”,選擇您在步驟1中創建的shceme,並按“輸入”,使scheme的名稱和新的target的名稱相同(這是你為新的target所選擇的名字)
4. 步驟4是可選的,但強烈推薦。如果你想簡單地區分開發和生產版本構建,你應該為每個版本使用單獨的icon和啟動頁。這將使測試人員更清晰地知道正在使用哪個app,防止上傳開發版本。
跳到 `Assets.xcassets` 添加一個新的圖標。右擊圖標 > App Icons & Launch Images > New iOS App Icon. 新圖標重命名為“AppIcon-Dev”同時添加自己的圖片。
5.現在回到項目設置,選擇您的開發target,並改變Bundle Identifier。你可以簡單地將“Dev”追加到原來的ID上。如果執行了步驟4,請確保更改應用app icon,設置為在上一步中創建的。
6. Xcode會自動為你的target添加plist文件(如todo copy-Info.plist)。你可以在項目的根文件夾找到它。將它從“copy”重命名為“Dev”,並將它放在原始的plist文件下。這裡你將更容易管理文件。
7. 現在打開你開發target的“Build Settings”,滾動到“Packaging”,並將值改為開發的plist文件(todo Dev.plist)。
8. 最後,我們會為生產和開發target配置預處理宏/編譯器標識。之後我們就可以使用該標識在我們的代碼來檢測應用程序正在運行的版本。
對於Objective-C的項目,去到`Build Settings`下`Apple LLVM 7.0 - Preprocessing`。拓展`Preprocessor Macros`在Rebug和Release區域添加一個變量。對於開發target(即todo Dev),將該值設置為`DEVELOPMENT = 1`。另一個,將值設為`DEVELOPMENT=0`來表示生產版本。
對於swift的項目,編譯器不再支持預處理指令。作為替代,它使用編譯時的屬性和build配置。選中開發target,添加一個標識表示開發版本。找到`Build Setting`往下滾動到`Swift Compiler - Custom Flags`部分。將值設為`-DDEVELOPMENT`表示這個target作為開發版本。
現在,您已經創建並配置了開發target,下一步呢?
使用Target和宏
根據已配置的宏DEV_VERSION,我們可以在代碼中利用它動態地編譯項目。下面是一個簡單的例子:
Objective-C:
#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中你可以使用`#if`檢查`DEVELOPMENT`的環境,並相應的設置URLs/ API密鑰。
Swift:
#if DEVELOPMENT 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的參數動態編譯。然而,除了使用`#define`定義基本常量,在swift中我們也可以用`let`定義一個全局常量。
提示:通常,你會把上面的代碼放在app delegate中。但這最終是取決於你在哪裡初始化應用程序設置。
現在,當您選擇“todo Dev”scheme運行項目,你創建開發版本會自動將服務器的配置設置為開發環境。現在,您可以上傳開發版本到TestFlight 或 HockeyApp供測試人員和管理人員來測試。
接著如果你需要創建一個生產版本,您可以簡單地選擇"todo"scheme。不需要更改代碼。
管理多個target的一些注意事項
1.當你添加新的文件到項目中,不要忘記選擇兩個target,以保持你的代碼同步在兩個版本。
2.如果你使用的CocoaPods,不要忘了添加新的target到你的podfile中。您可以使用`link_with`指定多個target。您可以進一步細節請查閱的 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.如果你使用持續集成系統,如 Travis CI 或Jenkins,別忘了配置兩個target的build和deliver。
你對這個教程有什麼想法?如何管理你的開發和生產構建?給我留言評論分享您的想法。