使用Jenkins搭建Flutter持續(xù)集成打包平臺

背景

目前項目功能開發(fā)已告一段落,后續(xù)進入項目實施階段热鞍∶颇颍考慮到后續(xù)有大量的測試和交付場景塑径,有必要對項目搭建持續(xù)集成打包平臺,方便后續(xù)測試交付填具。

由于公司已經(jīng)搭建有Jenkins统舀,而且作者以前也使用Jenkins搭建過Android持續(xù)集成打包平臺,對于Jenkins的安裝和配置就不多做講解劳景,如有需要可以參考使用Jenkins搭建iOS/Android持續(xù)集成打包平臺誉简。這里主要講解如何在Jenkins上配置和構建Flutter工程,以及遇到的問題盟广。

首先闷串,給大家展示下平臺搭建完成后的整體效果:

WX20210903-113445.png
WX20210902-142950.png

該平臺主要實現(xiàn)的功能:

  • 可選擇branch分支打包
  • 支持自定義版本號
  • 支持指定打包類型
  • 根據(jù)git提交sha命名文件
  • 打包生成二維碼網(wǎng)頁
  • 構建完成后通過釘釘推送到指定群通知

流程

開始搭建之前,我們需要先整理下我們的搭建思路:

  1. 在打包服務器(linux服務器)上安裝Flutter筋量、Android烹吵、JDK等構建所需SDK,安裝Python3桨武、amzqr用于生成二維碼
  2. 在Jenkins中構建項目肋拔,配置打包參數(shù)
  3. 添加項目構建命令,構建打包生成APK
  4. 根據(jù)下載地址生成二維碼呀酸,并寫入html文件生成掃碼下載網(wǎng)頁
  5. 上傳APK凉蜂、二維碼、掃碼下載html文件到指定倉庫提供下載
  6. 整個流程結束后通知開發(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

  1. 下載Flutter安裝包
wget https://storage.flutter-io.cn/flutter_infra_release/releases/stable/linux/flutter_linux_2.2.3-stable.tar.xz
  1. 解壓
cd ~/development
tar xf ~/Downloads/flutter_linux_2.2.3-stable.tar.xz
  1. 環(huán)境變量配置
vi /etc/profile
添加環(huán)境變量
source /etc/profile
  1. 測試環(huán)境是否正確
flutter doctor

在Jenkins中構建項目

在Jenkins新建一個項目,進入構建配置頁面

1. 源碼管理

  • 選擇Git管理填入git地址
  • 添加項目的用戶憑證
  • 指定分支為:$branch蝗砾,這里是引用的其他變量先较,用于分支的選擇
WX20210902-152431.png

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文件路徑
WX20210902-153306.png

4. 配置可選參數(shù)

  1. 在General中勾選This project is parameterized菜循,新增Git Paramter插件用于git分支的選擇:
WX20210902-153720.png
  1. 選擇Choice Pramter新增buildType配置可以打包的類型:
WX20210902-153730.png
  1. 選擇String Paramter配置應用的版本號翘地,默認使用代碼中的版本號
WX20210902-153739.png

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)境缺失導致抄囚,這里列舉我遇到的幾個問題:

  1. 缺少gcc
configure: error: no acceptable C compiler found in $PATH
該錯誤是因為本機缺少gcc編譯環(huán)境,只需安裝gcc即可
# 安裝命令
yum install -y gcc
  1. 缺少zlib
錯誤代碼
zipimport.ZipImportError: can't decompress data; zlib not available
該錯誤是因為本機缺少zlib解壓縮類庫橄务,只需安裝zlib即可
# 安裝命令
yum install -y zlib*
  1. 缺少libffi-devel
錯誤代碼
ModuleNotFoundError: No module named '_ctypes'
該錯誤是因為本機缺少libffi-devel包幔托,只需安裝此包即可
# 安裝命令
yum install -y libffi-devel
注意在安裝完缺少的依賴包后,仍需重新運行對應所在的配置蜂挪、編譯和執(zhí)行安裝命令

3. Pip3安裝失敗問題

  1. 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項目的搭建诡延、腳本命令的編寫五個步驟來完成涝焙,在實施過程中也遇到很多問題,踩過了很多的坑孕暇,同時也獲得了很多收獲和感悟:

  1. Linux操作系統(tǒng)很重要仑撞。Linux操作系統(tǒng)在非常多的地方都用到,還是非常有必要了解和熟悉的
  2. 遇到問題時要了解問題的本質(zhì)妖滔。安裝失敗或者存在環(huán)境問題時隧哮,多查詢相關資料,同時了解問題出現(xiàn)的原因和解決處理的本質(zhì)是什么
  3. 思路很重要座舍。做一件復雜的事情之前沮翔,有必要先明確自己的思路,先拆解任務后逐步實現(xiàn)
  4. 實踐出真知曲秉。很多事情看起來比較簡單采蚀,但我們不能忽視,只有在實踐之后我們才能得出結論承二,獲得更多感悟和提升
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末榆鼠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子亥鸠,更是在濱河造成了極大的恐慌妆够,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件负蚊,死亡現(xiàn)場離奇詭異神妹,居然都是意外死亡,警方通過查閱死者的電腦和手機家妆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門鸵荠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伤极,你說我怎么就攤上這事蛹找∫躺耍” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵熄赡,是天一觀的道長姜挺。 經(jīng)常有香客問我,道長彼硫,這世上最難降的妖魔是什么炊豪? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮拧篮,結果婚禮上词渤,老公的妹妹穿的比我還像新娘。我一直安慰自己串绩,他們只是感情好缺虐,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著礁凡,像睡著了一般高氮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上顷牌,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天剪芍,我揣著相機與錄音,去河邊找鬼窟蓝。 笑死罪裹,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的运挫。 我是一名探鬼主播状共,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谁帕!你這毒婦竟也來了峡继?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤雇卷,失蹤者是張志新(化名)和其女友劉穎鬓椭,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體关划,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年翘瓮,在試婚紗的時候發(fā)現(xiàn)自己被綠了贮折。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡资盅,死狀恐怖调榄,靈堂內(nèi)的尸體忽然破棺而出踊赠,到底是詐尸還是另有隱情,我是刑警寧澤每庆,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布筐带,位于F島的核電站,受9級特大地震影響缤灵,放射性物質(zhì)發(fā)生泄漏伦籍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一腮出、第九天 我趴在偏房一處隱蔽的房頂上張望帖鸦。 院中可真熱鬧,春花似錦胚嘲、人聲如沸作儿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽攻锰。三九已至,卻和暖如春妓雾,著一層夾襖步出監(jiān)牢的瞬間娶吞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工君珠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留寝志,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓策添,卻偏偏與公主長得像材部,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子唯竹,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容