iOS/macOS 真的頗有趣。 你能夠在不少領域得到知識!你可能會了解 Bezier 或 3D 變換等圖形技術。你也須要了解如何使用數據庫、設計高效的架構。此外,你應該掌握嵌入式系統的內存管理方式(特別是那些處於 MRC 時代的人)。全部這些使得 iOS/macOS 的開發如此多元化而且具備挑戰性。前端
在這篇文章裏,咱們將要學習你可能想了解的另外一些知識:持續交付(CD)。持續交付是一種軟件方法,可幫助你隨時可靠地發佈產品。持續交付(CD)一般帶有術語持續集成(CI)。CI 也是一種軟件工程技術。這意味着系統始終將開發者的工做不斷地合併到主線。CI 和 CD 不只對一個大團隊有用,並且對單人團隊也有用。若是你是單人團隊的惟一開發人員,CD 對你來講可能意味着更多,由於每一個應用程序開發人員都沒法避免交付。所以,本文將重點介紹如何爲你的應用程序構建 CD 系統。幸運的是,全部這些技術也能夠用於構建 CI 系統。android
想象一下咱們正在開發一款名爲 Brewer 的 iOS 應用,咱們的工做流大概像下圖這樣:ios
首先,咱們開發。而後 QA 組的同事幫咱們手工測試應用。QA 人員批准構建測試後,咱們放出(提交到 AppStore 待審覈)咱們的應用。在不一樣的階段中,咱們有不一樣的環境。在開發期,咱們建立的應用在一個測試環境中,以備平時測試。當 QA 組正在測試時,咱們準備一個生產環境的應用,這多是每週專門提供給 QA 測試用。最後,咱們提交一個生產環境的應用。這樣,最終構建可能沒有一個明確的時間表。git
讓咱們深刻了解交付部分。你可能會發現咱們在構建測試應用程序方面有不少重複的工做。這是 CD 系統能夠幫助你的。具體來講,咱們的 CD 系統須要:github
如下是咱們在本文中要作的事情:正則表達式
開始以前,你可能須要看看這些:數據庫
若是你是個忙碌的帥哥或靚女,別擔憂,我爲你在公共倉庫裏準備了 Brewer 應用以及一些示例腳本!swift
那麼,讓咱們開始吧!後端
咱們一般在開發人員測試階段鏈接到開發服務器或測試服務器。咱們還須要在將應用發給 QA 組測試,或 AppStore 時,鏈接到生產服務器。經過編輯代碼切換服務器可能不是一個好主意。這裏咱們使用 Xcode 中的構建配置和編譯器標誌。咱們不會詳細介紹配置。若是你對該設置該興趣,能夠看看這篇 Yuri Chukhlib 寫的不錯的文章:xcode
在咱們的 Brewer 項目中,咱們有三個構建選項:
每一個都映射到特定的 Bundle 標識:
咱們經過設置標識,來讓代碼知曉咱們正在用哪一個環境。
所以咱們能夠像這樣來寫:
#if PROD
print(「We brew beer in the Production」)
#elseif STG
print(「We brew beer in the Staging」)
#endif
複製代碼
如今咱們可以不用修改代碼,經過構建選項來切換測試環境與生產環境了!🎉
這是每一個 iOS / macOS 開發人員熟知的紅色按鈕。咱們經過取消選中此框來啓動每一個項目。但爲何它如此臭名昭着?你可能知道它會下載證書和配置文件,並將其嵌入到你的項目和系統中。若是有任何文件遺漏,它會爲你製做一個新文件。對於單人的項目組來講,這裏不會有問題。可是若是你在一個大團隊中,你可能會無心中刷新原始證書,而後因爲證書無效而致使構建系統中止工做。對咱們來講,這是一個隱藏了太多信息的黑匣子。
因此在咱們 Brewer 項目中,咱們想手動作這件事,在咱們的配置中有有三個應用 ID:
咱們將在這篇文章裏關注前兩個配置,如今咱們要準備:
提醒下,咱們須要 p12 格式的證書文件,由於咱們但願其可用在不一樣的機器上,只有 .p12 格式包含了證書的私鑰。看這篇文章來了解如何將 .cer(DEM 格式)文件轉換爲 .p12(P12 格式)格式文件。
如今目錄下有咱們的證書籤名文件:
這些文件由 CD 系統使用,因此請將該文件夾放在 CD 機器上。 請不要將這些文件放到你的項目中,不要將它們提交到你的項目倉庫。 將代碼簽名文件託管在不一樣的私有倉庫中能夠。你可能但願瞭解有關安全問題的討論,能夠看看 match — fastlane docs。
fastlane 是讓開發和發佈工做流自動化的工具。好比,它能夠經過一個腳本構建應用、運行單元測試、向 Crashlytics 上傳二進制。你不須要一步一步手動地作這些事。
在這個項目中,咱們將要用 fastlane 完成兩項任務:
這兩種方法之間的區別僅僅在於配置。共同的任務包括:
明確了任務,咱們如今能夠開始編寫 fastlane 腳本了。咱們將使用 Swift 版 fastlane 在咱們的項目中編寫咱們的腳本。Swift 版 fastlane 還在測試階段,運行一切良好,但除了:
可是用 Swift 編寫腳本使得開發人員更易於閱讀和維護。並且你能夠輕鬆地將 Swift 腳本轉換爲 Ruby 腳本。因此讓咱們試試吧!
首先初始化咱們的項目(還記得 Bundler 吧?):
bundler exec fastlane init swift
複製代碼
而後,你能夠在 fastlane/Fastfile.swift 中找到腳本。在腳本中,有一個 fastfile 類。這是咱們的主要程序。在本類中用 Lane 爲後綴命名的每個方法都是一個 lane。咱們能夠將預約義的動做添加到 lane,並使用命令執行 lane:
bundle exec fastlane <lane name>.
複製代碼
讓咱們填充一些代碼:
class Fastfile: LaneFile {
func developerReleaseLane() {
desc("Create a developer release")
package(config: Staging())
crashlytics
}
func qaReleaseLane() {
desc("Create a qa release")
package(config: Production())
crashlytics
}
}
複製代碼
咱們爲任務建立兩個 lane:developerRelease 和 qaRelease。這兩個任務都作了一樣的事:用指定配置來構建打包,並將導出的 ipa 上傳到 Crashlytics。
兩個 lane 都有一個 package 方法。package() 方法的聲明看起來是這樣:
func package(config: Configuration) {
}
複製代碼
參數時一個遵循 Configuration 協議的對象。Configuration 的定義以下:
protocol Configuration {
/// file name of the certificate
var certificate: String { get }
/// file name of the provisioning profile
var provisioningProfile: String { get }
/// configuration name in xcode project
var buildConfiguration: String { get }
/// the app id for this configuration
var appIdentifier: String { get }
/// export methods, such as "ad-doc" or "appstore"
var exportMethod: String { get }
}
複製代碼
而後咱們建立兩個兩個遵循該協議的結構體:
struct Staging: Configuration {
var certificate = "ios_distribution"
var provisioningProfile = "Brewer_Staging"
var buildConfiguration = "Staging"
var appIdentifier = "works.sth.brewer.staging"
var exportMethod = "ad-hoc"
}
struct Production: Configuration {
var certificate = "ios_distribution"
var provisioningProfile = "Brewer_Production"
var buildConfiguration = "Production"
var appIdentifier = "works.sth.brewer.production"
var exportMethod = "ad-hoc"
}
複製代碼
使用該協議,咱們可以確保每一個配置都具備所需的設置。每當咱們有新的配置時,咱們不須要編寫 package 的詳細信息。
那麼,package(config:) 看起來如何?說愛你他須要從文件系統中導入證書。記住咱們的代碼簽名文件夾,咱們用 importCertificate action 來實現咱們的目標。
importCertificate(
keychainName: environmentVariable(get: "KEYCHAIN_NAME"),
keychainPassword: environmentVariable(get: "KEYCHAIN_PASSWORD"),
certificatePath: "\(ProjectSetting.codeSigningPath)/\(config.certificate).p12",
certificatePassword: ProjectSetting.certificatePassword
)
複製代碼
keychainName是你的鑰匙串的名稱,默認名稱是『登陸』。keychainPassword 是你鑰匙串的密碼,fastlane 使用它來解鎖你的鑰匙串。因爲咱們將 Fastfile.swift 提交到倉庫以確保交付代碼在每臺計算機中都是一致的,所以在 Fastfile.swift 中將密碼寫爲字符串文字可不是一個好主意。所以,咱們使用環境變量來替換字符串文字。在系統中,咱們用這個方式來保存環境變量:
export KEYCHAIN_NAME=」KEYCHAIN_NAME」;
export KEYCHAIN_PASSWORD=」YOUR_PASSWORD」;
複製代碼
在 Fastfile 中,咱們用 environmentVariable(get:) 得到環境變量的值。經過使用環境變量,咱們能夠避免代碼中出現密碼,來顯著提升安全性。
回到 importCertificate(),certificatePath 是你的 .p12 證書文件的路徑。咱們建立一個名爲 ProjectSetting 的枚舉來標識共享的項目設置。這裏咱們也用環境變量來傳遞密碼。
enum ProjectSetting {
static let codeSigningPath = environmentVariable(get: "CODESIGNING_PATH")
static let certificatePassword = environmentVariable(get: "CERTIFICATE_PASSWORD")
}
複製代碼
導入證書後,咱們將設置配置文件。咱們用 updateProjectProvisioning:
updateProjectProvisioning(
xcodeproj: ProjectSetting.project,
profile: "\(ProjectSetting.codeSigningPath)/\(config.provisioningProfile).mobileprovision",
targetFilter: "^\(ProjectSetting.target)$",
buildConfiguration: config.buildConfiguration
)
複製代碼
此操做獲取配置文件,導入配置文件並在指定的配置中修改你的項目設置。配置文件參數是提供配置文件的路徑。目標過濾器使用正則表達式符號來查找咱們要修改的目標。請注意,updateProjectProvisioning 不會修改你的項目文件,所以若是你想在本地計算機上運行它,請當心。CD 任務可有可無,由於 CD 系統不會對代碼庫進行任何更改。
好的,咱們完成了代碼簽名部分!如下部分將很是簡單明瞭,請耐心等待!
讓咱們如今來構建應用:
buildApp(
workspace: ProjectSetting.workspace,
scheme: ProjectSetting.scheme,
clean: true,
outputDirectory: "./",
outputName: "\(ProjectSetting.productName).ipa",
configuration: config.buildConfiguration,
silent: true,
exportMethod: config.exportMethod,
exportOptions: [
"signingStyle": "manual",
"provisioningProfiles": [config.appIdentifier: config.provisioningProfile] ],
sdk: ProjectSetting.sdk
)
複製代碼
buildApp 幫助你構建並導出項目。它底層是調用 xcodebuild 的。除了 exportOptions,每一個參數都很直觀。讓咱們看看它長啥樣:
exportOptions: [
"signingStyle": "manual",
"provisioningProfiles": [config.appIdentifier: config.provisioningProfile] ]
複製代碼
不像其餘參數,它是一個 dictionary。signingStyle 是你想要代碼簽名的方式,咱們在這裏放置了 manual。provisioningProfiles 也是一個字典。這是應用程序 ID 和相應的配置文件之間的映射。最後咱們完成了 fastlane 設置!如今你能夠直接執行:
bundle exec fastlane qaRelease
複製代碼
或是這樣:
bundle exec fastlane developerRelease
複製代碼
來用合適的配置發佈測試構建!
Jenkins是一個自動化服務器,可幫助你執行 CI 與 CD 任務。它運行一個 Web GUI 界面,而且很容易定製,因此它對於敏捷團隊來講是一個很好的選擇。Jenkins 在咱們項目中的規則如圖所示:
Jenkins 獲取項目的最新代碼並按期爲你運行任務。在執行腳本的部分,咱們能夠看到 Jenkins 實際上執行了咱們在前幾節中所作的任務。但如今咱們不須要本身作,Jenkins 無縫地爲你完成了這些!
從每晚構建做業開始,讓咱們開始建立一個 Jenkins 任務。首先,咱們建立一個『自定義項目』,並進入它的『配置』頁面。咱們須要配置的第一件事是源代碼管理(SCM)部分:
Repository URL 是項目源代碼的地址。若是你的倉庫是私有的,你須要添加 Credentials 以得到倉庫讀取權限。你能夠在 Branches to build 中設置目標分支,一般它是你的默認分支。
而後,接下來咱們能夠看到 Builder Trigger 部分。在本節中,咱們能夠決定是什麼觸發了構建做業。根據咱們的工做流,咱們但願它每週週末晚上開始。
而後咱們檢查 Poll SCM,這意味着 Jenkins 會按期輪詢指定的倉庫。日程安排文本區域要寫上如下內容:
H 0 * * 0–4
複製代碼
這是什麼意思呢?讓咱們先看看官方說明:
這個字段遵循 cron 的語法(有細微差異)。具體而言,每行包含由 TAB 或空格分隔的 5 個字段: MINUTE HOUR DOM MONTH DOW MINUTE 分鐘小時內的分鐘數(0-59) HOUR 小時一天中的小時(0-23) DOM 每個月的一天(1-31) MONTH(1-12) DOW 星期幾(0-7),其中0和7是星期日。
它由五部分構成
該字段能夠是數字。 咱們也能夠用『*』來表示『全部』數字。 咱們用『H』表示一個 hash,自動選擇『某個』數字。
因此咱們會這樣寫:
H 0 * * 0–4
複製代碼
意思是:任務將在週日到週四,每晚零點到一點執行。
最後,可是最重要的,來檢查下 Build 部分的內容,這是咱們但願 Jenkins 執行的東西:
export LC_ALL=en_US.UTF-8;
export LANG=en_US.UTF-8;
export CODESIGNING_PATH=」/path/to/cert」;
export CERTIFICATE_PASSWORD=」xxx」;
export KEYCHAIN_NAME=」XXXXXXXX」;
export KEYCHAIN_PASSWORD=」xxxxxxxxxxxxxx」
bundle install — path vendor/bundler
bundle exec fastlane developerRelease
複製代碼
前 6 行是設置咱們以前描述的環境變量。第 7 行安裝依賴項,包括 fastlane。而後最後一行執行一個名爲『developerRelease』的 lane。總之,這個任務每一個工做日晚上都會創建並上傳一個 developerRelease。這是咱們第一次每晚構建!🚀
你能夠經過單擊 Jenkins 項目頁面的側面菜單中的內部版本號來檢查構建狀態:
咱們一塊兒學會了如何用 fastlane 和 Jenkins 建立 CD 系統。咱們瞭解如何手動管理代碼簽名。咱們自動爲咱們建立了一條運行任務。咱們還探討了如何在不更改代碼的狀況下切換配置。最後,咱們創建了一個天天晚上構建應用程序的 CD 系統。
儘管許多 iOS 與 macOS 應用程序是由單人團隊建立的,但自動化交付流程仍然是一項高效的改進。經過自動化流程,咱們能夠下降配置錯誤的風險,避免被過時的代碼簽名所阻塞,並減小構建上傳的等待時間。
本文中介紹的工做流程可能與你的工做流程不徹底相同,但掌握每一個團隊本身的工做流程和步伐很是重要。因此你必須建立本身的 CD 系統來知足你的團隊的須要。經過將這些技術用做構建模塊,你必定可以構建本身定製的、更好的 CD 系統!
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。