Ubuntu搭建Jenkins+Android自動化打包
本文主要介紹如何在Ubuntu搭建Jenkins實現Android專案的自動化打包,一般部署在我們的伺服器,這裡我通過虛擬機器安裝Ubuntu來進行演示
目錄
環境配置
下載並配置java環境
- 通過 ofollow,noindex">java官網 下載對應jdk版本
- 開啟終端,輸入以下命令列進行解壓
tar -zxvf jdk-8u181-linux-x64.tar.gz
- 將解壓後的資料夾移動到/opt目錄下
sudo mv jdk1.8.0_181 /opt/
- 修改環境變數
sudo vi ~/.bashrc
在末尾新增如下配置:
#set Java environment export JAVA_HOME=/opt/jdk1.8.0_181 export JRE_HOME=${JAVA_HOME}/jre export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH=${JAVA_HOME}/bin:$PATH
- 儲存退出,使用source命令使其生效
source ~/.bashrc
- 驗證java環境是否配置成功
java -vsersion
Git安裝
sudo apt-get install git
安裝配置nginx
為了使得外部能下載相關資源,安裝並配置本地目錄對映
sudo apt-get install nginx sudo service nginx start sudo vi /etc/nginx/nginx.conf
簡單修改配置檔案,新增如下內容
server { listen 81; server_name 192.168.80.140; client_max_body_size 4G; root /home/cc/pkg_bak; location / { autoindex on; autoindex_exact_size on; autoindex_localtime on; } }
使配置生效
sudo service nginx reload
Jenkins安裝
可以根據 Jenkins官網 文件進行安裝
wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add - sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list' sudo apt-get update sudo apt-get install jenkins
修改Jenkins配置
sudo vi /etc/default/jenkins
修改埠號
# 預設是8080埠 HTTP_PORT=8081
啟動Jenkins
sudo service jenkins start
啟動完成,通過瀏覽器訪問 http://192.168.80.140:8081 即可看到啟動介面

啟動jenkins.png
根據提示通過檢視 /var/lib/jenkins/secrets/initialAdminPassword 獲取到密碼即可
然後根據提示安裝需要的外掛,建立使用者,完成後出現下面的介面,Jenkins 搭建完成

搭建完成.png
配置Android專案編譯環境
安裝常用外掛
路徑:系統管理-外掛管理-可選外掛,在搜尋框輸入你需要安裝的外掛進行安裝即可
常用外掛有以下:
- Git plugin
- Git Parameter
- GitLab Plugin
- Gradle Plugin
- Android Emulator Plugin
- Android Lint Plugin
- description setter plugin
- Checkstyle Plug-in
- FindBugs Plug-in
- PMD Plug-in
- SSH Agent
- Role-based Authorization Strategy
- OWASP Markup Formatter Plugin
配置Git
路徑:系統管理-全域性工具配置-Git
因為Ubuntu已經安裝了Git,所以預設配置即可

配置Git.png
配置JDK
路徑:系統管理-全域性工具配置-JDK
下載需要一個Oracle的帳號,新增完賬戶就可以了

配置JDK.png
配置Gradle
路徑:系統管理-全域性工具配置-Gradle

配置Gradle.png
配置Android SDK
路徑:系統管理-系統設定-Android
填寫SDK的存放路徑,同時勾選自動下載,警告可以忽略

配置AndroidSDK.png
這個時候有一個問題需要注意,必須在sdk的目錄下 新增license檔案,去你本地的sdk下拷貝一份進去
新建工程

新建工程.png
填寫General
一般會勾選丟棄舊的構建,防止伺服器累計過多次的編譯

填寫General.png
填寫原始碼管理
使用Git來拉取程式碼

填寫原始碼管理.png
構建配置

配置構建介面.png
上內容述執行的是:
- 重置,清空專案內容
- 將存在伺服器的金鑰資訊、sdk目錄等資訊(local.properties),拷貝到專案中
- 使用工程下的gradlew來構建專案,保持gradle版本與本地一致,Tasks中輸入專案要編譯的任務
因為我的金鑰讀取是放到 local.properties 檔案中的,所以可以做到伺服器管控打包金鑰,local.properties 內容如下
KEY_STORE=金鑰路徑 KEY_STORE_PASSWORD=密碼 KEY_ALIAS=金鑰別名 KEY_ALIAS_PASSWORD=密碼 sdk.dir=sdk路徑
構建後配置
需要收集相應的apk和mapping檔案

配置構建後介面.png
最後點選儲存,通過簡單配置,到此已經可以實現專案的構建了
更多定製化配置
通過Git Parameter外掛實現分支選擇

填寫GitParameter.png
整合360加固
從360官方下載相關檔案,拷貝到/home/cc/backup/360jiagu目錄,使用命令列的方式進行加固,詳細可以檢視 官方說明文件 ,這裡採用編寫指令碼檔案實現自動加固,檔案內容如下:
指令碼jiagu_360.sh存放路徑/home/cc/backup/360jiagu/jiagu
#!/bin/bash BASE_JAR=/home/cc/backup/360jiagu/jiagu/jiagu.jar JIA_GU_NAME=賬號 JIA_GU_PSD=密碼 echo "------ jiagu running! ------" java -jar ${BASE_JAR} -version java -jar ${BASE_JAR} -login ${JIA_GU_NAME} ${JIA_GU_PSD} LOCAL_PATH=$1 echo "local.properties:${LOCAL_PATH}" KEY_STORE=`cat ${LOCAL_PATH} |grep KEY_STORE= | awk -F= '{print $2}'` KEY_STORE_PASSWORD=`cat ${LOCAL_PATH} |grep KEY_STORE_PASSWORD= | awk -F= '{print $2}'` KEY_ALIAS=`cat ${LOCAL_PATH} |grep KEY_ALIAS= | awk -F= '{print $2}'` KEY_ALIAS_PASSWORD=`cat ${LOCAL_PATH} |grep KEY_ALIAS_PASSWORD= | awk -F= '{print $2}'` java -jar ${BASE_JAR} -importsign ${KEY_STORE} ${KEY_STORE_PASSWORD} ${KEY_ALIAS} ${KEY_ALIAS_PASSWORD} java -jar ${BASE_JAR} -showsign BuildApkLine=$2 Build_JiaGu_Dir=$3 echo "BuildApkLine:${BuildApkLine}, Build_JiaGu_Dir=${Build_JiaGu_Dir}" java -jar ${BASE_JAR} -jiagu $BuildApkLine $Build_JiaGu_Dir -autosign echo "------ jiagu finished! ------"
生成二維碼,在構建歷史展示更多資訊
description setter plugin
sudo apt-get install qrencode
- 修改構建任務,在專案編譯完加固完成後執行下面命令
BuildApkLine=`find ./jiagu -name *_jiagu_sign.apk` # 備份到檔案伺服器 PkgBakDir="/home/cc/pkg_bak/${JOB_NAME}" if [ ! -d "$PkgBakDir" ]; then mkdir $PkgBakDir fi BuildDir="$PkgBakDir/${BUILD_NUMBER}" if [ ! -d "$BuildDir" ]; then mkdir $BuildDir fi ApkName=${BuildApkLine##*/} LastestApkName="dev_lastest.apk" cp $BuildApkLine $BuildDir if [ -f "$PkgBakDir/$LastestApkName" ]; then rm $PkgBakDir/$LastestApkName fi ln -s "$BuildDir/$ApkName" "$PkgBakDir/$LastestApkName" QrcodeValue="http://192.168.80.140:81/${JOB_NAME}/${BUILD_NUMBER}/$ApkName" echo "QrcodeValue is $QrcodeValue" LastQrcodeValue="http://192.168.80.140:81/${JOB_NAME}/$LastestApkName" echo "LastQrcodeValue is $LastQrcodeValue" # 將debug apk的下載地址 生成二維碼,以供下載 qrencode -o qrcode.png $QrcodeValue # 將debug apk的下載地址 生成二維碼,以供下載 qrencode -o last_qrcode.png $LastQrcodeValue # 輸出debug apk的下載地址,機械號,版本名稱 echo "BuildUrl: $QrcodeValue,$VersionCode,$VersionName,$dev_branch,$Tasks"
-
構建後操作,新增Set build description
構建後操作.png
這裡解釋一下這兩個引數:
- Regular expression:BuildUrl: (. ),(. ),(. ),(. )
通過正則匹配獲取到上面BuildUrl的4個引數,分別為apk地址、機械號、版本名稱、分支名稱 - Description,描述,這裡以html格式輸出其中 \1,\2..分別對應上面匹配的4個引數
-
完成後的結果如下:
效果圖.png
整合fir自動上傳
打包完成後實現自動上傳到fir,可參考 fir官方文件 ,這裡我們通過編寫Python指令碼實現自動上傳功能,指令碼程式碼如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- import requests import json import sys # 需要的引數 REQUEST_PARAM = { 'api_token': '這裡填寫自己的token資訊', 'type': 'android', 'applicationId': 'com.xxx.xxx', 'appName': '應用名稱', 'versionName': '1.0.1.0', 'versionCode': '10', 'changelog_path': 'changelog檔案地址', 'apk_path': 'apk地址' } # 初始化傳入的引數 def init_param(): print('獲取到傳遞過來的引數:', str(sys.argv)) REQUEST_PARAM['type'] = sys.argv[1] REQUEST_PARAM['applicationId'] = sys.argv[2] REQUEST_PARAM['appName'] = sys.argv[3] REQUEST_PARAM['versionName'] = sys.argv[4] REQUEST_PARAM['versionCode'] = sys.argv[5] REQUEST_PARAM['changelog_path'] = sys.argv[6] REQUEST_PARAM['apk_path'] = sys.argv[7] # 獲取上傳憑證 def get_cert(): print('發起獲取上傳憑證請求') param = {'type': REQUEST_PARAM['type'], 'bundle_id': REQUEST_PARAM['applicationId'], 'api_token': REQUEST_PARAM['api_token']} print('獲取上傳憑證請求引數:', param) req = requests.post(url='http://api.fir.im/apps', data=param) cert_response = req.content print('獲取上傳憑證響應:', str(cert_response)) return cert_response # 上傳到fir def upload_fir(binary, apk_path): binary_key = binary['key'] binary_token = binary['token'] binary_upload_url = binary['upload_url'] print('開始上傳Apk') changelog_str = open(REQUEST_PARAM['changelog_path']).read() file = {'file': open(apk_path, 'rb')} param = { "key": binary_key, "token": binary_token, "x:name": REQUEST_PARAM['appName'], 'x:version': REQUEST_PARAM['versionName'], 'x:build': REQUEST_PARAM['versionCode'], "x:changelog": changelog_str } req = requests.post(binary_upload_url, files=file, data=param) print('上傳結果:', req.content) if __name__ == '__main__': init_param() response = get_cert() # 得到獲取上傳憑證回撥資訊 cert_json = json.loads(response) cert_binary = cert_json['cert']['binary'] # 上傳fir upload_fir(cert_binary, REQUEST_PARAM['apk_path'])
指令碼程式碼註釋也比較詳細,不再展開說明,最後通過在上面加固完成後的shell指令碼後面追加以下內容來實現自動上傳
# 編寫日誌內容 ChangeLog=changelog.txt echo "Uploaded by fir cli" >> $ChangeLog echo "構建編號:${BUILD_NUMBER}" >> $ChangeLog echo "修改記錄:">> $ChangeLog echo "${SCM_CHANGELOG}">> $ChangeLog cat $ChangeLog python /home/cc/backup/fir/uploadFir.py android $ApplicationId $AppName $VersionCode $VersionName $ChangeLog $BuildApkLine
常見問題
Jenkins啟動可能出現的問題
Job for jenkins.service failed because the control process exited with error code. See “systemctl status jenkins.service” and “journalctl -xe” for details.
根據提示輸入 sudo systemctl status jenkins.service
● jenkins.service - LSB: Start Jenkins at boot time Loaded: loaded (/etc/init.d/jenkins; generated) Active: failed (Result: exit-code) since Thu 2018-10-18 11:19:37 CST; 21s ago Docs: man:systemd-sysv-generator(8) Process: 3896 ExecStart=/etc/init.d/jenkins start (code=exited, status=1/FAILURE) 10月 18 11:19:37 cc-virtual-machine systemd[1]: Starting LSB: Start Jenkins at boot time... 10月 18 11:19:37 cc-virtual-machine jenkins[3896]: ERROR: No Java executable found in current PATH: /bin:/usr/bin: 10月 18 11:19:37 cc-virtual-machine jenkins[3896]: If you actually have java installed on the system make sure the 10月 18 11:19:37 cc-virtual-machine systemd[1]: jenkins.service: Control process exited, code=exited status=1 10月 18 11:19:37 cc-virtual-machine systemd[1]: jenkins.service: Failed with result 'exit-code'. 10月 18 11:19:37 cc-virtual-machine systemd[1]: Failed to start LSB: Start Jenkins at boot time.
從錯誤日誌可以看出找不到java路徑,解決方法:建立一條軟連結
sudo ln -s /opt/jdk1.8.0_191/bin/java /usr/bin/java
Jenkins許可權問題
Jenkins在執行shell指令碼的時候可能出現許可權問題,我們可以把jenkins賬戶加入到root組
- 將jenkins賬戶加入到root組
sudo gpasswd -a root jenkins
- 修改 /etc/default/jenkins 內容
# user and group to be invoked as (default to jenkins) JENKINS_USER=root JENKINS_GROUP=root
- 重啟jenkins
sudo service jenkins restart
- 檢視是否已經加入到root組
cat /etc/group |grep jenkins
jenkins:x:127:root
檔案許可權問題
錯誤資訊
/home/cc/backup/360jiagu/jiagu/jiagu_360.sh ./local.properties app/build/bakApk/resguard/ry_taxi_passenger20_1.0.2.0.apk ./jiagu /tmp/jenkins9129980792461988922.sh: 20: /tmp/jenkins9129980792461988922.sh: /home/cc/backup/360jiagu/jiagu/jiagu_360.sh: Permission denied
修改該檔案許可權即可
chmod 777 /home/cc/backup/360jiagu/jiagu/jiagu_360.sh