背景
目前項目功能開發(fā)已告一段落,后續(xù)進入項目實施階段热鞍∶颇颍考慮到后續(xù)有大量的測試和交付場景塑径,有必要對項目搭建持續(xù)集成打包平臺,方便后續(xù)測試交付填具。
由于公司已經(jīng)搭建有Jenkins统舀,而且作者以前也使用Jenkins搭建過Android持續(xù)集成打包平臺,對于Jenkins的安裝和配置就不多做講解劳景,如有需要可以參考使用Jenkins搭建iOS/Android持續(xù)集成打包平臺誉简。這里主要講解如何在Jenkins上配置和構建Flutter工程,以及遇到的問題盟广。
首先闷串,給大家展示下平臺搭建完成后的整體效果:
該平臺主要實現(xiàn)的功能:
- 可選擇branch分支打包
- 支持自定義版本號
- 支持指定打包類型
- 根據(jù)git提交sha命名文件
- 打包生成二維碼網(wǎng)頁
- 構建完成后通過釘釘推送到指定群通知
流程
開始搭建之前,我們需要先整理下我們的搭建思路:
- 在打包服務器(linux服務器)上安裝Flutter筋量、Android烹吵、JDK等構建所需SDK,安裝Python3桨武、amzqr用于生成二維碼
- 在Jenkins中構建項目肋拔,配置打包參數(shù)
- 添加項目構建命令,構建打包生成APK
- 根據(jù)下載地址生成二維碼呀酸,并寫入html文件生成掃碼下載網(wǎng)頁
- 上傳APK凉蜂、二維碼、掃碼下載html文件到指定倉庫提供下載
- 整個流程結束后通知開發(fā)人員構建完成
Linux常用命令
由于用到了linux服務器性誉,很多l(xiāng)inux服務器是不支持遠程圖形化界面展示的窿吩,所以我們需要了解一些常用的linux操作命令:
ls(英文全拼:list files): 列出目錄及文件名
cd(英文全拼:change directory):切換目錄
pwd(英文全拼:print work directory):顯示目前的目錄
mkdir(英文全拼:make directory):創(chuàng)建一個新的目錄
rmdir(英文全拼:remove directory):刪除一個空的目錄
cp(英文全拼:copy file): 復制文件或目錄
rm(英文全拼:remove): 刪除文件或目錄
mv(英文全拼:move file): 移動文件與目錄,或修改文件與目錄的名稱
Tip:如果大家不熟悉Linux系統(tǒng)可以參考Linux教程
Shell常用命令
Flutter項目構建不同于Android原生可以采用Gradle直接構建艾栋,需要用到shell腳本爆存,所以我們對于一些常用的shell命令也需要熟悉:
變量
傳遞參數(shù)
Shell echo命令
Shell 流程控制
Shell 輸入/輸出重定向
Tip:先關資料可以參考Shell教程
Linux上安裝Flutter
- 下載Flutter安裝包
wget https://storage.flutter-io.cn/flutter_infra_release/releases/stable/linux/flutter_linux_2.2.3-stable.tar.xz
- 解壓
cd ~/development
tar xf ~/Downloads/flutter_linux_2.2.3-stable.tar.xz
- 環(huán)境變量配置
vi /etc/profile
添加環(huán)境變量
source /etc/profile
- 測試環(huán)境是否正確
flutter doctor
在Jenkins中構建項目
在Jenkins新建一個項目,進入構建配置頁面
1. 源碼管理
- 選擇Git管理填入git地址
- 添加項目的用戶憑證
- 指定分支為:$branch蝗砾,這里是引用的其他變量先较,用于分支的選擇
2. 構建
在Execute shell中添加項目構建命令:
cd /data/jenkins/workspace/xxx
source /etc/profile
flutter clean
#執(zhí)行打包腳本
sh app.sh
#執(zhí)行圖片二維碼腳本
sh qr.sh
#復制安裝包携冤、圖片、html到指定目錄
cp -rf build/app/outputs/flutter-apk/xxx* /data/ftp/apps/xxx/
#釘釘配置
PRO_NAME=xxx
PRO_NAME_CN=xxx【移動端APP】開發(fā)環(huán)境
DINGDING_PATH=/data/dingdingpusher
DINGDING_JSON=$DINGDING_PATH/$PRO_NAME.json
SERVER_IP=xxx
#編寫釘釘通知腳本
echo {\"msgtype\": \"markdown\", \
\"markdown\": { \
\"title\":\"jenkins編譯提示\", \
\"text\": \"# **jenkins編譯通知**\\n#### jenkins編譯《$PRO_NAME_CN》已經(jīng)發(fā)布到[$SERVER_IP]中闲勺,訪問地址為:http://xxx:1080/apps/xxx/ \\n## 變動內(nèi)容:${SCM_CHANGELOG}\" \
} \
} > $DINGDING_JSON
echo "打印$DINGDING_JSON內(nèi)容:"
cat $DINGDING_JSON
3. 構建后的操作
上述思路有提到曾棕,構建成功后需要在釘釘上通知開發(fā)者,這里是用的是Jenkins中的Dingding Json Pusher插件:
填入釘釘?shù)腁ccess token
項目的json文件路徑
4. 配置可選參數(shù)
- 在General中勾選This project is parameterized菜循,新增Git Paramter插件用于git分支的選擇:
- 選擇Choice Pramter新增buildType配置可以打包的類型:
- 選擇String Paramter配置應用的版本號翘地,默認使用代碼中的版本號
5. App打包腳本
#!/bin/bash -ilex
#獲取Git SHA1
GIT_SHA1=`(git show-ref --head --hash=8 2> /dev/null || echo 00000000) | head -n1`
#默認打包類型
DEFAULT_BUILD_TYPE=release
#打包類型
if [ ! $buildType ]; then
type=$DEFAULT_BUILD_TYPE
else
type=$buildType
fi
#獲取版本號
versionCode=""
version=""
versionCodeSpe=""
pubspecFile="pubspec.yaml"
if [ -e $pubspecFile ]
then
if [ -r $pubspecFile ]
then
if [ -w $pubspecFile ]
then
#修改文件
#webview
version=`sed -n '18p' $pubspecFile`
else
echo "文件不可寫"
fi
else
echo "文件不可讀"
fi
else
echo "文件不存在"
fi
#對IFS變量 進行替換處理 拆分分號
OLD_IFS="$IFS"
IFS=": "
array=($version)
IFS="$OLD_IFS"
#拆分加號
OLD_IFS="$IFS"
IFS="+"
array=(${array[1]})
IFS="$OLD_IFS"
versionName=${array[0]}
#versionCode=`expr "${versionName}"|sed "s/\.*//g"`
versionCode=${array[1]}
#指定版本號
if [ ! $buildVersionName ]; then
echo "沒有指定版本,默認使用配置文件的版本"
else
versionName=$buildVersionName
fi
time=$(date "+%m%d")
test=Test
#執(zhí)行打包
flutter build apk --$type --obfuscate --split-debug-info=xx --build-name=$versionName --build-number=$versionCode
#修改包名稱
mv "build/app/outputs/flutter-apk/app-${type}.apk" "build/app/outputs/flutter-apk/hn_lottery_${versionName}+${versionCode}_${GIT_SHA1}_${type}.apk"
6. 圖片二維碼腳本
#!/bin/bash -ilex
#獲取Git SHA1
GIT_SHA1=`(git show-ref --head --hash=8 2> /dev/null || echo 00000000) | head -n1`
#默認打包類型
DEFAULT_BUILD_TYPE=release
#打包類型
if [ ! $buildType ]; then
type=$DEFAULT_BUILD_TYPE
else
type=$buildType
fi
#amzqr路徑配置
amzqr=/usr/local/bin/amzqr
#獲取版本號
versionCode=""
version=""
versionCodeSpe=""
pubspecFile="pubspec.yaml"
#pubspecFile="utils/web_socket_utils.dart"
if [ -e $pubspecFile ]
then
if [ -r $pubspecFile ]
then
if [ -w $pubspecFile ]
then
#修改文件
#webview
version=`sed -n '18p' $pubspecFile`
else
echo "文件不可寫"
fi
else
echo "文件不可讀"
fi
else
echo "文件不存在"
fi
#對IFS變量 進行替換處理 拆分分號
OLD_IFS="$IFS"
IFS=": "
array=($version)
IFS="$OLD_IFS"
#拆分加號
OLD_IFS="$IFS"
IFS="+"
array=(${array[1]})
IFS="$OLD_IFS"
versionName=${array[0]}
#versionCode=`expr "${versionName}"|sed "s/\.*//g"`
versionCode=${array[1]}
#指定版本號
if [ ! $buildVersionName ]; then
echo "沒有指定版本癌幕,默認使用配置文件的版本"
else
versionName=$buildVersionName
fi
baseUrl="http://xxx:1080/apps/xxx_app"
fileName="xxx_${versionName}+${versionCode}_${GIT_SHA1}_${type}"
apkUrl="${baseUrl}/${fileName}.apk"
apkPicUrl="${baseUrl}/${fileName}.png"
$amzqr "$apkUrl" -n "${fileName}.png" -d "build/app/outputs/flutter-apk/"
echo "<!doctype html>
<html>
<head>
<meta http-equiv=\"content-type\" content=\"text/html;\">
<meta charset=\"utf-8\">
<meta name=\"viewport\" content=\"width=device-width; initial-scale=1.0\">
<meta name=\"keywords\" content=\"test\" />
<meta name=\"description\" content=\"\">
<title>Android測試包下載頁</title>
<link rel=\"stylesheet\" type=\"text/css\" href=\"style/css/mobile.css\" /></head>
<body>
<div class=\"doc\">
<br/>
<br/>
<p align = \"center\">
<a id=\"ipaPathHref\" href=\"$apkUrl\">$apkUrl</a>
</p>
<br/>
<br/>
<p align=\"center\">
<a id=\"plistPathHref\" href=\"$apkUrl\">
<img alt=\"\" src=\"$apkPicUrl\" style=\"height:300px; width:300px\" /></a>
</p>
<br/>
<br/>
<br/>
<p align=\"center\">請使用Android系統(tǒng)掃一掃</p>
<p align=\"center\">或使用應用瀏覽器掃碼進行下載</p>
<br/></div>
</body>
</html>
" > "build/app/outputs/flutter-apk/${fileName}.html"
7. 圖片二維碼的生成
在上述圖片二維碼的腳本中我們可以看到如下命令:
$amzqr "$apkUrl" -n "${fileName}.png" -d "build/app/outputs/flutter-apk/"
這個命令是amazing-qr(github上搜索衙耕,簡書被屏蔽)的使用,這個一個開源的Python 二維碼生成器勺远,基于Python3來運行橙喘,因此我們需要先安裝Python3然后再安裝amazing-qr
1. Linux中安裝Python3
Linux系統(tǒng)中的安裝方式有很多種,由于服務器上很多運行插件都沒有安裝胶逢,所以我采用下載解壓的方式來安裝:
wget https://www.python.org/ftp/python/3.9.7/Python-3.9.7.tgz
tar -zxvf Python-3.9.7.tgz
cd Python-3.9.7
./configure
make && make install
2. 安裝amazing-qr
amazing-qr是基于Python來安裝的厅瞎,這里用到命令:
python3 -m pip install amzqr
問題(遇到的坑)
總體流程看下來比較清晰,操作也比較簡單初坠,基本是一步一步的往下走和簸,但是事情往往沒有想象中的順利,中途也遇到的很多問題
1. Jenkins讀取不到系統(tǒng)環(huán)境變量的問題
在第2步構建的Execute shell中碟刺,我們用到如下命令:
source /etc/profile
主要是因為Jenkins在運行時讀取不到系統(tǒng)環(huán)境變量锁保,需要我們在shell中設置生效。
還有另外一種方式南誊,通過shell頭文件定義身诺,但是在Jenkins運行時會看不到執(zhí)行日志
#!/bin/bash -i1
2. Python3安裝失敗問題
linux上Python安裝失敗主要是因為相關插件、環(huán)境缺失導致抄囚,這里列舉我遇到的幾個問題:
- 缺少gcc
configure: error: no acceptable C compiler found in $PATH
該錯誤是因為本機缺少gcc編譯環(huán)境,只需安裝gcc即可
# 安裝命令
yum install -y gcc
- 缺少zlib
錯誤代碼
zipimport.ZipImportError: can't decompress data; zlib not available
該錯誤是因為本機缺少zlib解壓縮類庫橄务,只需安裝zlib即可
# 安裝命令
yum install -y zlib*
- 缺少libffi-devel
錯誤代碼
ModuleNotFoundError: No module named '_ctypes'
該錯誤是因為本機缺少libffi-devel包幔托,只需安裝此包即可
# 安裝命令
yum install -y libffi-devel
注意在安裝完缺少的依賴包后,仍需重新運行對應所在的配置蜂挪、編譯和執(zhí)行安裝命令
3. Pip3安裝失敗問題
- SSL模塊不存在
錯誤代碼
Can't connect to HTTPS URL because the SSL module is not available.
說明ssl安裝有問題重挑,或者沒有安裝ssl。解決方法去python3 的安裝目錄下的/usr/local/python3/Python-3.6.8/Modules/Setup文件里棠涮,去掉下面四行的注釋
SSL=/user/local/ssl
_ssl _ssl.c \
-DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
-L$(SSL)/lib -lssl -lcrypto
4. amzing-qr安裝失敗問題
Pip無法在環(huán)境變量中定義谬哀。由于Python和Pip都是采用的下載tag文件解壓的方式,并且Pip是基于Python進行安裝严肪,導致直接運行Pip命令系統(tǒng)無法識別史煎,我們也無法在環(huán)境中配置Pip谦屑,解決方式是通過Python來運行Pip
python3 -m pip install amzqr
5. amzing-qr命令無法在shell中運行問題
amzing-qr安裝完成后,服務器本地使用amzqr運行正常篇梭,但是在shell中運行一直識別不到該命令氢橙,即使是在系統(tǒng)環(huán)境變量中配置了也不行,需要指定amzqr的執(zhí)行文件目錄才可以
#amzqr路徑配置
amzqr=/usr/local/bin/amzqr
由于amzing-qr是基于Pip進行安裝恬偷,而Pip又是基于Python運行悍手,所以出現(xiàn)該問題目前無法得知明確的原因,目前的解決方式是在Jenkins中配置amzing-qr的環(huán)境變量以此來運行
總結
平臺的搭建從流程思路的明確袍患、操作命令的學習坦康、環(huán)境的安裝、Jenkins項目的搭建诡延、腳本命令的編寫五個步驟來完成涝焙,在實施過程中也遇到很多問題,踩過了很多的坑孕暇,同時也獲得了很多收獲和感悟:
- Linux操作系統(tǒng)很重要仑撞。Linux操作系統(tǒng)在非常多的地方都用到,還是非常有必要了解和熟悉的
- 遇到問題時要了解問題的本質(zhì)妖滔。安裝失敗或者存在環(huán)境問題時隧哮,多查詢相關資料,同時了解問題出現(xiàn)的原因和解決處理的本質(zhì)是什么
- 思路很重要座舍。做一件復雜的事情之前沮翔,有必要先明確自己的思路,先拆解任務后逐步實現(xiàn)
- 實踐出真知曲秉。很多事情看起來比較簡單采蚀,但我們不能忽視,只有在實踐之后我們才能得出結論承二,獲得更多感悟和提升