基於Jekins+GitLab的混合工程實現Flutter自動化打包方案

sinat_36416780發表於2020-12-23

簡介

Android專案想要依賴Flutter工程,存在兩種依賴方式:1、直接採用專案工程依賴(需要組內成員配置flutter環境)2、通過aar工程產物的方式依賴,對原生侵入較小,組內其他成員無感知。

因此這裡採用了方案二。

注意由於Flutter 1.22.x後,flutter版本有了較大的變化,其中flutter engine從flutter通過打包命令生成的aar剝離,因此直接依賴aar的方式並不能達到要求。

這是Android專案對Flutter專案的依賴主要分為三部分:flutter-release.aar,flutter engine,第三方plugins。

這裡又有了兩種處理方式:

  • 我們可以在專案的build.gradle中,將所有的依賴寫上,但這顯然會讓專案的build.gradle 檔案變得混亂。
  • 使用fat-aar的方式將所有的依賴裝在到flutter-release.aar中,簡化專案結構。

這裡,採用方案二。

至此,大體的打包過程我們已經知悉,接下來,我們可以通過命令列,和修改配置檔案的方式,手動打包成功。

將aar遷移到Android專案中,就可以正常執行了。

但是,作為一個成熟的專案,這樣的人工打包方案自然是不能長久,因此gitlab+jekins的自動打包流程就需要建立起來了。

 

自動打包需求

1、在jekins介面可以一鍵完成flutter自動打包,Android依賴包更新。

2、支援flutter開發分支和master分支切換,來滿足開發和釋出的需求變更。

3、Android可以支援露出flutter的git commit id,來確認flutter的程式碼是否是最新程式碼。

自動化打包方案

方案一:dart指令碼+maven倉庫遠端依賴方式,也是我最開始採用的方案。

步驟一:建立maven倉庫,諮詢了公司運維,得知還沒有自己的maven私庫後,找運維同學分配了主機,通過nexus建立了maven私庫。

               建立成功後介面如下:

 

其中maven-release,為版本釋出的aar倉庫依賴,maven-snapshot為開發階段的快照aar依賴。

步驟二:

通過指令碼修改.adroid下的部分配置檔案,打包生成aar。

 

具體的指令碼邏輯可以自己檢視,主要參考了http://jsshou.cn/blog/flutter/flutter_build_android.html#%E8%84%9A%E6%9C%AC%E5%BC%80%E5%8F%91

 

步驟三:通過dart指令碼上傳aar到maven倉庫。

將上述的檔案配置完成後,就可以執行命令了,其中上傳maven庫時,要尤其主要地址和artifact-id的問題。

步驟四:在專案中通過類似其他網路庫的依賴方式進行依賴:

 

方案二:shell指令碼+jekins打包機檔案遷移

方案一提供了一個很好地版本管理和快照的maven倉庫方式,但是並沒有和jekins很好地結合,例如無法獲取flutter專案的commint_id,動態依賴不同的flutter分支,因此這裡採用了第二種方式。

區別點主要在兩點:

  1. 修改dart命令為shell命令,剝離整體對flutter的專案依賴,直接通過shell命令修改flutter程式碼中的build檔案。
  2. 不再執行上傳操作,直接在打包機中將生成的aar遷移到android的lib目錄下依賴。
  3. 同時生成commit檔案,遷移到android專案的assets目錄下。

 

綜上:採用了方案二來完成打包的邏輯。

打包實現邏輯

1、分支選擇及路徑配置

 

#!/bin/bash
#初始化預設值
build_configuration="release"
flutter_git="stable"

while [ "$1" != "" ]; do
  case $1 in
  -b | --build_configuration)
    shift
    build_configuration=("$1")
    ;;
  -f | --flutter_git)
    shift
    flutter_git="$1"
    ;;
  esac
  shift
done

  if [ "$build_configuration" = "daily" ]; then
    flutter_git="dev"
  elif [ "$build_configuration" = "daily_new" ]; then
    flutter_git="dev"
  elif [ "$build_configuration" = "debug" ]; then
    flutter_git="dev"
  else
    flutter_git="stable"
  fi
echo "${build_configuration} 當前選擇 git 分支 ${flutter_git}"

work_path=${PWD}
cd ${work_path} # 當前位置跳到指令碼位置
echo "work_path == ${work_path}"
flutter_path="${work_path}/stock_flutter/.android/Flutter/build/outputs/aar"
echo "flutter_path == ${flutter_path}"
target_path="${work_path}/libcommon/libs"
echo "target_path == ${target_path}"
target_asset_path="${work_path}/libcommon/src/main/assets/"

function moveArchiveFile() {
  # echo "moveFile ${build_configuration}"
  if [ $build_configuration = "Debug" ]; then
    echo "done =="
    exit
  fi

  filesPath="${flutter_path}/"
  cd $filesPath
  files=$(ls ${PWD})
  length=0
  for filename in $files; do
    let length=length+1
  done
  limitedLength=0
  echo "length == ${length}"

  if [[ $length -gt $limitedLength ]]; then
    for filename in $files; do
      #       echo "file1 == ${target_path}${filename}"
      #       echo "file2 == ${filesPath}${filename}"
      echo "file $filename"
         moveArrFile $filename
      echo "flutter 依賴包移動成功"
    done
  else
    echo "flutter 資源打包失敗"
  fi
}
function moveArrFile() {
if [ ! -d ${target_asset_path} ];then
  mkdir ${target_asset_path}
else
  echo "資料夾已經存在"
fi
 if [[ $1 == *"txt"* ]]; then
    echo "txt"
      rm -rf "${target_asset_path}$1"
      mv -f "${filesPath}$1" "${target_asset_path}"
    else
      rm -rf "${target_path}$1"
      mv -f "${filesPath}$1" "${target_path}"
fi

}


clone flutter倉庫程式碼

echo "*************************  更新本地檔案 Flutter  *************************"

cd ${work_path}
#exit

echo "*************************  開始下載、打包 flutter 資源  *************************"

export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

echo "remove cache data"
rm -rf "${work_path}/stock_flutter"

git clone ssh://git@git.5th.im:2222/long-bridge-frontend/stock_flutter.git stock_flutter -b master

cd stock_flutter
git checkout -f ${flutter_git}
git pull

#git submodule update --init
git submodule update --force --recursive --init --remote

#read commit id
git_commit_id=$(git rev-parse --short HEAD)
echo "commit id = ${git_commit_id}"

echo "./flutterw clean"
./flutterw clean
./flutterw doctor
./flutterw pub get

修改flutter 打包的配置檔案

由於需要區分google和普通release,主要是v7和v8的不同。

其中主要是

  1. .android下的build.gradle  .android/Flutter/build.gradle 版本修改。
  2. .android/gradle/wrapper/gradle.properties 版本修改,這裡修改是由於我們專案的打包機上gradle版本問題,只能和android專案的保持一致。

 

echo "*************************  開始修改flutter-build相關檔案  *************************"
#這裡可以使用shell命令來修改檔案
#${work_path}/stock_flutter/.flutter/bin/dart ${work_path}/stock_flutter/configs/build_android.dart
googleGradlePlugin="
  dependencies {\n
   embed \"io.flutter:flutter_embedding_release:1.0.0-a1440ca392ca23e874a105c5f3248b495bd0e247\"\n
    embed \"io.flutter:arm64_v8a_release:1.0.0-a1440ca392ca23e874a105c5f3248b495bd0e247\"\n
    embed \"io.flutter:armeabi_v7a_release:1.0.0-a1440ca392ca23e874a105c5f3248b495bd0e247\"\n
    def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()\n
    def plugins = new Properties()\n
    def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')\n
    if (pluginsFile.exists()) {\n
        pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }\n
    }\n
    plugins.each { name, path->\n
        File editableAndroidProject = new File(path, 'android' + File.separator + 'build.gradle')\n
        println name\n
        if (editableAndroidProject.exists()) {\n
            embed project(path: \":\$name\", configuration: 'default')\n
        }\n
    }\n
}"
gradlePlugin="
  dependencies {\n
   embed \"io.flutter:flutter_embedding_release:1.0.0-a1440ca392ca23e874a105c5f3248b495bd0e247\"\n
    embed \"io.flutter:armeabi_v7a_release:1.0.0-a1440ca392ca23e874a105c5f3248b495bd0e247\"\n
    def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()\n
    def plugins = new Properties()\n
    def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')\n
    if (pluginsFile.exists()) {\n
        pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }\n
    }\n
    plugins.each { name, path->\n
        File editableAndroidProject = new File(path, 'android' + File.separator + 'build.gradle')\n
        println name\n
        if (editableAndroidProject.exists()) {\n
            embed project(path: \":\$name\", configuration: 'default')\n
        }\n
    }\n
}
"
cd .android
sed -ig 's/3.5.0/3.4.0/' build.gradle
sed -i '' '10a\'$'\nclasspath "com.kezong:fat-aar:1.2.5"\n' build.gradle
cd Flutter
sed -i '' '$a\'$'\napply plugin: "com.kezong.fat-aar"\n' build.gradle
sed -i '' '$a\'$'\napply from: "../config/dependencies_gradle_plugin.gradle"\n' build.gradle
cd ..
mkdir "config"
cd config
touch dependencies_gradle_plugin.gradle
if [ "$build_configuration" = "google" ];then
  echo  ${googleGradlePlugin} > dependencies_gradle_plugin.gradle
else
echo  ${gradlePlugin} > dependencies_gradle_plugin.gradle
fi
cd ..
cd gradle
cd wrapper
sed -ig 's/5.6.2/5.6.4/' gradle-wrapper.properties
echo "*************************   結束脩改flutter-build相關檔案  *************************"

打包生成aar檔案 遷移aar檔案

 

echo "*************************  開始打包 flutter 資源  *************************"
cd ${work_path}
cd stock_flutter
if [ "$build_configuration" = "google" ];then
  ./flutterw build aar --no-debug --no-profile --target-platform android-arm64
else
   ./flutterw build aar --no-debug --no-profile --target-platform android-arm
fi

cd ${flutter_path}
echo "commit id=${git_commit_id}" >flutter_version.txt
ls
moveArchiveFile
sleep 5
cd ${work_path}

遠端打包方式

遠端打包通過jekins配置,主要需要配置的點在於

 

--build_configuration 後的配置區別:

  1. 不配置,對應 flutter分支為stable,主要用於專案發版
  2. daily ,對應 flutter分支為dev,主要用於Android  daily開發中需要更新最新的flutter程式碼。
  3. google,對應 flutter分支為stable,但是對應架構為v8,主要用於google市場上架。

 

相關文章