前言:
實際實踐過程中,發現通過 .pkg 包來安裝的 Jenkins 存在各種各樣的問題,比如 SSH 配置問題,Git Clone 超時問題,Provisioning Profile 讀取權限問題(因為Jenkins的工作目錄會建立在/Users/Shared/Jenkins)等,很難去解決!而通過 Homebrew 命令來安裝的 Jenkins 就沒有這些問題,強烈推薦在 macOS 上采用 Homebrew 命令來安裝 Jenkins,而不是通過官方網站上下載的 .pkg 包來安裝!
1、環境配置:
1、Mac OS 10.14.4
2、Xcode10.2
3、Homebrew安裝:https://juejin.im/post/5a6d969bf265da3e2366b853
4、JavaSDK安裝:下載Java的JDK
2、Jenkins安裝:
2.1、通過Homebrew安裝Jenkins,終端中輸入:
?brew install jenkins
2.2、然后執行war包(注意下面的命令需要自己更換對應的版本號),終端中輸入:
java -jar /usr/local/Cellar/jenkins/版本號/libexec/jenkins.war --httpPort=8080
出現下面界面說明jenkins已經啟動成功了
3.3、在瀏覽器中輸入localhost:8080出現下面界面:
.jenkins是隱藏文件,可以按住shift+command+. 查看mac上的隱藏文件,找到initialAdminPassword復制其中的密碼,然后按住shift+command+. 隱藏mac上的隱藏文件。
3.4、安裝推薦的插件
3.5、創建管理員用戶
3.6、進入到以下頁面,就表明 macOS 上 Jenkins 的安裝與配置成功!
3.7、安裝依賴插件
如果是GitLab來管理源代碼,Jenkins本身并沒有自帶GitLab插件,所以我們需要依次選擇 系統管理->管理插件,在“可選插件”中選中“GitLab Plugin”和“Gitlab Hook Plugin”這兩項,然后安裝。
如果你想用Xcode插件作為配置打包任務可以下載 xcode integration插件,下載方式也是系統管理->管理插件,在“可選插件”中搜索下載。不過我還是偏向與腳本的方式,因為腳本雖然麻煩些但是更加靈活。比如我們打包的命名方式,打完包的存放文件路徑等都可以通過腳本做配置。
如果你工程使用了cocoapods,需要下載CocoaPods Jenkins Integration插件。
自動打包的job任務配置也需要添加鑰匙串和描述文件,這時需要安裝Keychains and Provisioning Profiles Management插件,安裝后在Jenkins首頁點擊系統管理會找到這個插件,點擊進去。
3.8、為Jenkins配置Keychains and Provisioning Profiles Management
去 macOS 以下地址:/Users/{username}/Library/Keychains找到 login.keychain 文件,有的時候你可能看到的是 login.keychain-db 文件,沒關系,將 login.keychain-db拷貝桌面一份并將文件修改成 login.keychain。然后通過 Upload Keychain or Provisioning Profile File -> Choose File -> Upload 上傳:
上傳好了之后,就會出現以下配置:
Password 一欄就填寫當前 macOS 用戶的登錄密碼。Code Signing Identity 這個地方我們填寫相關證書的標識符,我目前電腦上配置了一個調試證書和一個 Ad Hoc 發布證書,當然后面你還需要一個 App Store 發布證書,這個操作流程都是一樣的,后面自己處理就好。我們去到 Keychain Access -> login,找到你的 iPhone Developer 和 iPhone Distribution 證書,選擇其中一個,然后復制標識符,填寫到此位置,保存即可!
說明:這個操作步驟,可以理解為 Jenkins 有權以你這臺電腦(login.keychain 文件)來獲取調試和發布 iOS 應用的證書(證書標識符)。
然后我們拿到調試證書和 Ad Hoc 證書對應的 .mobileprovision 文件,建議去 Apple 開發者后臺去下載,也可以去到 /Users/{username}/Library/MobileDevice/Provisioning Profiles 這個路徑下去找,但是如果你的配置文件太多的話,你很難分辨是哪個文件,而且這個地方的名稱都是 UUID 值標記的。我們拿到對應的 .mobileprovision 文件,同樣的位置點擊上傳,出現以下頁面:
會自動識別出 .mobileprovision 文件的 UUID 值。對于 Provisioning Profiles Directory Path,根據大家 macOS 當前登錄的用戶名的不同,我們填寫:/Users/{username}/Library/MobileDevice/Provisioning Profiles。
說明:這個操作步驟,可以理解為 Jenkins 可以讀取你位于 /Users/{username}/Library/MobileDevice/Provisioning Profiles 目錄下的配置文件,同時知道應該讀取那個對應的配置文件(識別 UUID 值)。
保存好了之后,整個 iOS 工程項目相關的證書和配置文件都配置好了。
3.9、為Jenkins配置Credentials
為了方便訪問遠程的 Git 倉庫,我們需要配置用于登錄驗證的信息。Jenkins -> Manage Jenkins -> Configure Credentials -> Credentials -> System -> Global Credentials -> Add Credentials。
說明:我們可以通過兩種方式來訪問遠程 Git 倉庫,一個是用戶名 + 密碼的形式,另外一個是 SSH 形式,關于 SSH 的公鑰、私鑰的制作與關聯使用,請參見《在 Mac OS X 上關聯 GitHub》。我們這里就追加兩種方式的登錄信息,以防止一種出現問題,另外一種還可以使用。
用戶名和密碼形式,Kind 選擇:Username with password。Scope 選擇 Global,Username 為你登錄 GitLab 的用戶名,Password 為你登錄 GitLab 的密碼。ID 默認不用填寫,Description 我們這里寫一個可以區分當前登錄信息的字符串即可。
SSH 形式,Kind 選擇:SSH Username with private key,Scope 還是選擇 Global,Username 還是 GitLab 登錄的用戶名,Private Key 我們去到通過我以上文章方式生成的用于 SSH 的公鑰和私鑰文件夾:/Users/{username}/.ssh:打開 id_rsa,然后復制內容到 Key 里面,Description 還是和上面一樣,寫一個可以區分當前登錄信息的字符串即可。
保存好這兩種登錄方式的信息之后,我們在列表中可以看到以下內容,說明保存成功了!
3.10、關聯一個遠程 GitLab 的 iOS 工程項目
Jenkins -> New Item -> 輸入名稱 -> Freestyle project -> OK
3.11、配置 iOS 工程項目
Jenkins -> ios-bluethooth-vioce-assistant?-> Configure,其中?ios-bluethooth-vioce-assistant 為新建的Jenkins工程名稱
相關的配置如下:
(1)Description:項目的一個簡要的描述:
? ? ? ? 我們的項目是:iOS 藍牙語音助手。
(2)Source Code Management:項目代碼版本管理方式:
????????我們的項目是使用 Git 托管在 GitLab 上面,所以我們選擇 Git。Repository URL 我們填寫 Git 倉庫的地址。請注意:如果你選擇的是 http:// 打頭的 Git 倉庫地址,那么 Credentials 就要選擇:用戶名和密碼形式。如果你選擇的是 git@ 打頭的 Git 倉庫地址,那么 Credentials 就要選擇:SSH 形式。需要 Build 的分支我們就默認 master。其他參數默認即可,說明:你選擇 git@ SSH 形式訪問遠程 Git 倉庫,有可能會出現以下提示:
????????你可以參考這篇文章嘗試解決:http://www.lxweimin.com/p/ed0edb93e234,我個人由于沒有解決掉這個問題,就采用 http:// 方式訪問了。另外我猜測這個是由于通過 .pkg 包安裝的方式來安裝的,會生成一個共享的 Jenkins 賬戶,而通過 Brew 命令來安裝的則是會安裝到當前用戶目錄底下,賬戶之間的權限訪問問題,比如你配置的是當前用戶底下的 .ssh 信息,但是實際上 Jenkins 嘗試去 /Users/Shared/Jenkins 底下獲取相關的 .ssh 信息。
(3)Build Triggers構建觸發器:
????????就是希望以什么樣的機制來觸發項目的構建。由于是獨立的單個項目,一般采用的方式有兩種:Build periodically,無論遠程倉庫代碼是否變化,周期性構建。Poll SCM,當遠程倉庫代碼有變化時,才進行周期性構建。我們目前采用 Poll SCM 形式。大家要注意的就是如何去寫這個配置參數,在配置這個參數之前,我們需要了解一個非常重要的概念:Crontab,還有一個非常好的針對?Crontab 的工具網站。了解清楚之后,我們就可以先配置一個測試的 Crontab:*/5 * * * *。表示每五分鐘構建一次,我上圖中填寫的是:H/5 * * * *,兩個意思是一樣的。當你填寫 */5 * * * * 的時候,Jenkins 會提醒你寫成:H/5 * * * * 形式更好。
(4)Build Environment構建環境:
????????這個地方主要配置的是針對 iOS 項目的證書和配置文件。勾選上:Keychains and Code Signing Identities,這個時候出現 login.keychain 的信息。但是可能會出現 Code Signing Identity 沒有可以選擇的情況,你需要先點擊保存一下,讓相關的數據加載,不然你是無法選擇這個 Code Signing Identity。這是一個小坑!我們選擇 iPhone Developer 的證書,那么底下勾選上:Mobile Provisioning Profiles 之后,選擇的配置文件是要和 iPhone Developer 證書對應。當你選擇 iPhone Distribution 證書之后,Mobile Provisioning Profiles 要選擇和 iPhone Distribution 證書對應的配置文件。
(5)Build構建:
????????我們選擇 Execute shell,執行一段 Shell 命令。我們這邊執行 Shell 命令,需要注意針對 iOS 項目是否有引入 CocoaPods 而不同。有經驗的 iOS 開發者都知道,如果你引入了 CocoaPods,那么你需要通過 .xcworkspace 文件載入工程,而不是 . xcodeproj 文件載入工程。
(6)引入了 CocoaPods 的項目編譯的 Shell 命令示例:
#bin/bsah - l
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
cd ~/.jenkins/workspace/ios-bluethooth-vioce-assistant
/usr/local/bin/pod install --verbose --no-repo-update
# 項目名稱:iOS 項目工程中的名稱
PROJECT_NAME="VoiceAssistant"
# Scheme 名稱:iOS 項目工程中 Scheme 名稱
SCHEME_NAME="VoiceAssistant"
# Info.Plist 文件的路徑,請注意有時候 Info.Plist 的文件名和路徑可能不同
SCHEME_INFO_PLIST_PATH="./${PROJECT_NAME}/Info.plist"
# 從 Info.Plist 文件中讀取版本號
VERSION=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" "${SCHEME_INFO_PLIST_PATH}")
# 從 Info.Plist 文件中讀取構建號
BUILD=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" "${SCHEME_INFO_PLIST_PATH}")
# 獲取當前日期
DATE="$(date +%Y%m%d%H%M)"
# 編譯之后的 .ipa 文件名稱
IPA_NAME="${SCHEME_NAME}_v${VERSION}_${DATE}"
# 編譯之后的 .xcarchive 文件名稱
ARCHIVE_NAME="${SCHEME_NAME}_v${VERSION}_${DATE}"
# 編譯之后的 .ipa 文件導出路徑
IPA_EXPORT_PATH="/Users/ifeegoo/workspace/jenkins/${PROJECT_NAME}/${SCHEME_NAME}/${VERSION}/"
# 存檔打包導出 .ipa 文件
xcodebuild archive -scheme ${SCHEME_NAME} -archivePath ${IPA_EXPORT_PATH}${IPA_NAME}.xcarchive -workspace ${PROJECT_NAME}.xcworkspace
xcodebuild -exportArchive -archivePath ${IPA_EXPORT_PATH}${ARCHIVE_NAME}.xcarchive -exportPath ${IPA_EXPORT_PATH}${IPA_NAME}.ipa -exportOptionsPlist /Users/ifeegoo/workspace/jenkins/${PROJECT_NAME}/${SCHEME_NAME}/ExportOptions.plist
(7)未引入 CocoaPods 的項目編譯的 Shell 命令示例:
# 項目名稱:iOS 項目工程中的名稱
PROJECT_NAME="VoiceAssistant"
# Scheme 名稱:iOS 項目工程中 Scheme 名稱
SCHEME_NAME="VoiceAssistant"
# Info.Plist 文件的路徑,請注意有時候 Info.Plist 的文件名和路徑可能不同
SCHEME_INFO_PLIST_PATH="./${PROJECT_NAME}/Info.plist"
# 從 Info.Plist 文件中讀取版本號
VERSION=$(/usr/libexec/PlistBuddy -c "print CFBundleShortVersionString" "${SCHEME_INFO_PLIST_PATH}")
# 從 Info.Plist 文件中讀取構建號
BUILD=$(/usr/libexec/PlistBuddy -c "print CFBundleVersion" "${SCHEME_INFO_PLIST_PATH}")
# 獲取當前日期
DATE="$(date +%Y%m%d)"
# 編譯之后的 .ipa 文件名稱
IPA_NAME="${SCHEME_NAME}_v${VERSION}_${DATE}"
# 編譯之后的 .xcarchive 文件名稱
ARCHIVE_NAME="${SCHEME_NAME}_v${VERSION}_${DATE}"
# 編譯之后的 .ipa 文件導出路徑
IPA_EXPORT_PATH="/Users/ifeegoo/workspace/jenkins/${PROJECT_NAME}/${SCHEME_NAME}/${VERSION}/"
# 存檔打包導出 .ipa 文件
xcodebuild archive -scheme ${SCHEME_NAME} -archivePath ${IPA_EXPORT_PATH}${IPA_NAME}.xcarchive -workspace ${PROJECT_NAME}.xcodeproj
xcodebuild -exportArchive -archivePath ${IPA_EXPORT_PATH}${ARCHIVE_NAME}.xcarchive -exportPath ${IPA_EXPORT_PATH}${IPA_NAME}.ipa -exportOptionsPlist /Users/ifeegoo/workspace/jenkins/${PROJECT_NAME}/${SCHEME_NAME}/ExportOptions.plis
當然,執行以上命令的前提是當前 macOS 已經安裝了 Xcode!
你一定注意到了,上面針對于是否引入 CocoaPods 不同的 Shell 命令,唯一的區別就是在最后面載入不同格式的工程文件。另外你也可能注意到了,編譯的 Shell 命令里面有一個 ExportOptions.plist 的文件,有些疑惑這個文件是哪里來的,第一次的時候,我們可以通過Xcode打包導出對應的 Development/Ad Hoc/App Store 包,該包里面包含這幾個文件:DistributionSummary.plist、ExportOptions.plist、VoiceAssistant.ipa、Packaging.log,如果你想要 Build Development 的包,你就需要通過 Development 證書和對應的配置文件來導出包,獲得這個文件。如果你想要 Build Ad Hoc 的包,你就需要通過 Ad Hoc 證書和對應的配置文件來導出包,獲得這個文件。ExportOptions.plist 文件內容示例:
以上是通過 Xcode 導出的 Ad Hoc 包的 ExportOptions.plist 文件,這個記錄當前工程導出的相關配置。注意:我們將以上配置文件中第六行修改成 false,因為 compileBitcode 默認的 true 可能導致編譯失敗。然后將此文件放置到:/Users/ifeegoo/workspace/jenkins/${PROJECT_NAME}/ 目錄底下:/Users/ifeegoo/workspace/jenkins/${PROJECT_NAME}/ExportOptions.plist。
3.12、至此,所有的準備工作都已經就緒,去到工程頁面,點擊左側的:Build Now,第一次通過手動觸發構建。
左下角顯示第一次構建的進度,最后變成了紅色。很顯然構建失敗了,這個也很正常,一次成功的例子在開發中是不常見的。不要慌,點擊編譯失敗的任務,彈出框選擇:Console Output
很明顯我們可以看到,上面提示 timeout=10,針對這種超時的提醒,對 Git 有經驗的開發者來說,已經很熟悉了。意思就是 10 分鐘的 Git Clone 動作已經超時了,一般會出現在初次 Clone 時網絡不太好或者遠程 Git 倉庫過大造成的,我們現在要做的就是調大超時時間:
還是去到當前項目的配置頁面:Source Code Management -> Additional Behaviours -> Advanced clone behaviours -> Timeout (In Minutes) for clone and fetch operations -> 設置成 60 (分鐘),根據自己的網絡實際情況和遠程倉庫的大小。保存之后,再次手動構建一下。
當你發現時間設置成 120 分鐘這種超長時間,然后 Git Clone 還是一直卡在那里,同時我們也嘗試了去 Clone 一個非常小的項目,確定還是同樣的情況,這個就說明,不是超時時間設置的問題,網上有人說可能是因為防火墻設置,導致 Git Clone 出現問題,推薦使用 SSH 方式 Clone 項目,但是前面說了,通過 .pkg 文件安裝的 Jenkins,是掛在 Jenkins 用戶底下的,需要單獨針對這個 Jenkins 來配置 SSH 信息,我也沒有解決這個問題,所以,當你遇到這個問題之后,推薦采用 Brew 命令來安裝 Jenkins,而且在實際的時間過程中,你會發現通過 .pkg 包安裝的 Jenkins,要解決很多問題,有的問題還不好解決,而通過 Brew 命令安裝的 Jenkins,相對來說,出問題的情況少些!!!
當你發現通過 .pkg 安裝的 Jenkins 有太多問題解決不了的話,先卸載,然后通過 Homebrew 命令行來安裝 Jenkins!
通過 Homebrew 命令來安裝 Jenkins 之后,前面的配置步驟都是一樣的!我們同樣嘗試 SSH 形式訪問遠程 Git 倉庫。再次 Build,發現沒有 Git Clone 超時的問題!
如果遇到git lfs的錯誤,說明需要安裝?Git LFS,終端執行brew install git-lfs