前要
如果在完全的网络环境中实现对于 Flutter 的 CI/CD, 可能会直接使用 ghcr.io/cirruslabs/flutter
, 而由于特殊的网络环境, 则改为 ghcr.nju.edu.cn
的镜像,即便如此,也有可能无法拉取, 从而需要使用从纯净的 ubuntu:lastest
镜像开始构建。即便如此, Github 具有易用的 Actions 功能, 从而能很方便的配置, 而在 Gitlab 上则需要手动配置 .gitlab-ci.yml
文件。而在我们的环境中, 便有着比较不畅通的网络环境和私有部署的 Gitlab, 并要求完成 Flutter 框架应用对 Linux 和 Android 平台的构建。
Gitlab CI/CD 配置
在 Gitlab CI/CD 中, 我们需要配置 .gitlab-ci.yml
文件来指定构建流程。我们可以先简单指定使用的镜像和阶段, 再添加缓存配置以加快构建速度。
image: ubuntu:latest
stages:
- setup
- build
cache:
key:
files:
- pubspec.lock
paths:
- flutter/
- android_sdk/
变量配置
我们首先简单指定 Android SDK 和 Flutter 的安装路径以及下载 url, 对于我们的场景来说, 固定版本更加便于维护
variables:
FLUTTER_ROOT: "${CI_PROJECT_DIR}/flutter"
ANDROID_HOME: "${CI_PROJECT_DIR}/android_sdk"
FLUTTER_SDK_URL: "https://storage.flutter-io.cn/flutter_infra_release/releases/stable/linux/flutter_linux_3.32.4-stable.tar.xz"
ANDROID_COMMANDLINETOOLS_URL: "https://googledownloads.cn/android/repository/commandlinetools-linux-13114758_latest.zip"
依赖
根据官方文档 及 flutter doctor
的提示, 我们使用 apt 先换源并安装 Flutter 在 Linux 和 Android 平台上所需的依赖
before_script:
- sed -i 's/archive.ubuntu.com/mirrors.seu.edu.cn\/ubuntu/g' /etc/apt/sources.list.d/ubuntu.sources
- apt-get update && apt-get install -y -qq git curl zip unzip wget openjdk-17-jdk\
libglx-mesa0 libgl1 libglib2.0-0 lib32z1 libbz2-1.0 xz-utils clang cmake ninja-build\
pkg-config libgtk-3-dev
安装 Flutter
我们从上述的 url 下载 Flutter SDK, 并解压到指定目录, 同时设置 PATH
环境变量及 Flutter 的国内镜像地址, 最后配置 Git 以允许 Flutter 在 CI/CD 环境中运行。
# 接上述 before_script
- if [ ! -d "$FLUTTER_ROOT" ]; then\
mkdir -p "$FLUTTER_ROOT" && wget -qO /tmp/flutter_sdk.tar.xz "$FLUTTER_SDK_URL" &&\
tar xJf /tmp/flutter_sdk.tar.xz -C "$CI_PROJECT_DIR" && rm /tmp/flutter_sdk.tar.xz;\
fi
- export PATH="$FLUTTER_ROOT/bin:$PATH"
- export PUB_HOSTED_URL="https://pub.flutter-io.cn"
- export FLUTTER_STORAGE_BASE_URL="https://storage.flutter-io.cn"
- git config --global --add safe.directory "$FLUTTER_ROOT"
Flutter 初始化
我们将每次 Flutter 都需执行的步骤封装为一个单独的阶段 setup_flutter
, 以便在后续的构建阶段中使用, 其包括简单的环境检查、获取依赖和生成本地化文件。
setup_flutter:
stage: setup
script:
- flutter doctor -v
- flutter pub get
- flutter gen-l10n
Flutter Linux 构建
Linux 的构建非常简单, 后续的打包步骤也只需要通过 zip
将构建的文件进行打包。
build_linux:
stage: build
script:
- flutter build linux --release
- cd build/linux/x64/release/bundle && zip -r x64.zip .
dependencies:
- setup_flutter
artifacts:
paths:
- build/linux/x64/release/bundle/x64.zip
Flutter Android 构建
Android 的构建首先从 cmdline-tools
的下载和安装开始。使用 sdkmanager
接受许可协议并注意其返回值为 1 可能打断 CI 流程, 因此我们使用 || true
来忽略错误。接着安装 Android SDK, 通过设置 SDK_TEST_BASE_URL
来指定下载 url 的前缀, 方法来自 stackoverflow, 这对 Flutter 的构建是必要的, 即使 Flutter 会自动安装 Android SDK, 但必须首先保证预先存在一个版本。随后我们使用 flutter build apk
命令来构建生成不同架构 Android apk 与 SHA1 签名。
build_android_apk:
stage: build
script:
- if [ ! -d "$ANDROID_HOME" ]; then mkdir -p "$ANDROID_HOME"; fi
- if [ ! -d "$ANDROID_HOME/cmdline-tools" ]; then cd "$ANDROID_HOME" &&\
wget "$ANDROID_COMMANDLINETOOLS_URL" && unzip commandlinetools-linux-*.zip -d cmdline-tools &&\
cd cmdline-tools && mv cmdline-tools latest && chmod +x latest/bin/*;\
fi
- export PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH"
- cd "${CI_PROJECT_DIR}"
- yes | sdkmanager --licenses || true
- SDK_TEST_BASE_URL=https://googledownloads.cn/android/repository/ sdkmanager "platforms;android-34" "build-tools;35.0.1" "platform-tools" || true
- flutter build apk -v --release --split-per-abi
dependencies:
- setup_flutter
artifacts:
paths:
- build/app/outputs/flutter-apk/
Android Gradle 构建修改
当仅仅只对 .gitlab-ci.yml
进行修改时, 可能会遇到 Android 构建过程中卡死的问题, 具体原因暂时未知, 但我们可以手动绕过出问题的 Gradle Task。具体来说与 R8 最小化和 Android Lint 有关, 关闭后 apk 包的体积会略有膨胀, 我们需要在 android/app/build.gradle.kts
中添加以下配置来跳过这些步骤:
buildTypes {
release {
// Signing
isMinifyEnabled = false
isShrinkResources = false
}
}
lint {
checkReleaseBuilds = false
}
结语
整体流程配置完成后, 我们可以在 Gitlab CI/CD 中看到构建的结果。对于一个简单应用, setup_flutter
与 build_linux
大概耗时两分钟左右, 而 build_android_apk
则需要大约一刻钟左右。由于 CI/CD 的修改比较难以在本机调试, 故整个修改过程还是比较痛苦的, 并且也无法真正完成全平台的配置(理论上 Windows/Linux/macOS 各需要一台开发机)。后续如果遇到更严肃的场景, 或许可以考虑 fastlane 等更为成熟的方案。