此篇文章完整範例呈現於GitHub,若有需要參考可直接clone 並切換到每個階段,有任何問題也歡迎直接在底下留言或在GitHub 開issue。


問題

在專案當中,有時候我們會透過類似以下的用法來判定是否為某一個開發環境:

struct Config {

    static let isProduction = false

    static let apiURL = isProduction ? "www.production.server.com" : "www.test.server.com"

}

如果我們需要release 不同環境的app 時,我們必須要手動去更改isProduction 的值,有時候一個不小心Build 了十幾分鐘發現自己忘了改、改錯了、不小心把設定Commit 了… 等等團隊開發中容易誤導的問題,都相當的困擾,因此應該用良好的方法來避免這樣的問題發生。

一個透過CocoaPods 管理相依的專案,他的初始狀態看起來會像這樣:

螢幕快照 2019-03-14 下午5.45.26

在Project Info 當中,會有一個Configurations 的區塊,而CocoaPods 在你使用pod install 指令時也偷偷暗藏了他們的設定檔在這邊。

我們可以看到,專案預設是兩種設定檔,分別是DebugRelease,這兩者的區分如下:

螢幕快照 2018-11-05 下午8.12.25

當你點擊Edit Scheme 時,可以看到:

螢幕快照 2018-11-05 下午8.13.09

RunArchive 使用了不同的Build Configuration,這也是一個iOS 專案的預設設定。

這樣的設定有什麼問題?如果公司內部平常都會打包ipa 並上傳至TestFlight 之類的平台測試,並且有可能連上「Production」或「Development」環境,這樣子你在Archive 時,兩種都是使用Release 的設定檔,那我們就沒辦法分辨出是哪個環境了.因此就必須要手動去切換上述的isProduction 這個flag,相當麻煩且危險。

解法

首先,我們回到Configuration ,點擊加號分別使用Duplicate "Debug" ConfigurationDuplicate "Release " Configuration 來新增兩個完全相同的設定檔。

至於命名的部分,可以依據喜好決定要叫做什麼名字,範例則使用如下圖所示:

螢幕快照 2018-11-05 下午8.23.45

設定完之後,我們打開Podfile 並加上:

target 'SeparateEnvironment' do

  use_frameworks!

  project 'SeparateEnvironment', 'ProductionDebug' => :debug, 'ProductionRelease' => :release

  pod 'IGListKit'  

end

我們必須指定額外新增的兩個Configuration 屬於debug 或release 環境,並且重新下pod install 指令來重新產生Project file。

接下來我們回到Project Info 並選擇我們的App target,然後搜尋condition

螢幕快照 2018-11-05 下午8.38.26

換看到在預設的狀態下,Debug 已經是一個預設的Condition ,我們可以在Swift code 當中使用:

struct Config {

    #if DEBUG
    static let isProduction = false
    #else
    static let isProduction = true
    #endif

    static let apiURL = isProduction ? "www.production.server.com" : "www.test.server.com"

}

但這並不符合我們的需求,我們希望在不同的設定檔下決定連上哪台server ,而不是分是不是Debug 狀態,因此我們只要加上我們自己的condition ,就可以達到預期效果:

螢幕快照 2018-11-05 下午8.42.06

struct Config {

    #if DEV_ENV
    static let isProduction = false
    #else
    static let isProduction = true
    #endif

    static let apiURL = isProduction ? "www.production.server.com" : "www.test.server.com"

}

加好設定檔之後,我們再回到Edit Scheme...->Manage Schemes...,點選加號之後,取一個如下圖的名字:

螢幕快照 2018-11-05 下午8.43.57

記得,後面的Shared 可以打勾,就可以跟團隊的人共享,不需要每個人都創建自己的Schame。

加完了Scheme 之後,必須再重新打開Edit Scheme...,並選擇剛剛新增的Scheme,點擊一下左邊的所有動作,並把相對應的Build Configuration 挑選成你要的,這樣才算是大功告成,下圖以Run 為例:

螢幕快照 2018-11-05 下午8.46.06

結論

螢幕快照 2018-11-05 下午8.47.14

做完上述的操作後,我們會有兩個Scheme,未來只要需要Build production 環境的話,就只要切換Scheme 即可,大幅降低弄錯得機會,再加上如果使用fastlane 等工具,只要新增proddev 兩個lane ,並且build 不同的Scheme 即可:

 lane :dev do |options|
    options[:scheme] = "SeparateEnvironmente"
    build(options)
  end

  lane :prod do |options|
    options[:scheme] = "[Prod] SeparateEnvironment"
    build(options)
  end

  private_lane :build do |options|
    scheme = options[:scheme]

    # before archive ...
    gym(scheme: scheme)
    # after archive ...
  end

收工!😎