Featured image of post 国内 Gitlab CI 构建 Flutter for Android

国内 Gitlab CI 构建 Flutter for Android

前要

如果在完全的网络环境中实现对于 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_flutterbuild_linux 大概耗时两分钟左右, 而 build_android_apk 则需要大约一刻钟左右。由于 CI/CD 的修改比较难以在本机调试, 故整个修改过程还是比较痛苦的, 并且也无法真正完成全平台的配置(理论上 Windows/Linux/macOS 各需要一台开发机)。后续如果遇到更严肃的场景, 或许可以考虑 fastlane 等更为成熟的方案。

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计