logo
4
1
Login

Docker Android 构建镜像

简介

一个优化的 Docker 镜像,包含 Android SDKFlutter SDK

包含内容

最新 镜像始终包含最新的软件,包括最新的 8 个 Android SDK 平台及其相关构建工具。

最新的 标记 版本包含以下组件:

  • Ubuntu 22.04
  • Java - OpenJDK
    • 8 (1.8)
    • 11
    • 17
    • 21
  • Android SDK 平台:
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
  • Android 构建工具:
    • 28.0.1 28.0.2 28.0.3
    • 29.0.2 29.0.3
    • 30.0.0 30.0.2 30.0.3
    • 31.0.0
    • 32.0.0
    • 33.0.0 33.0.1 33.0.2 33.0.3
    • 34.0.0
    • 35.0.0
  • Android NDK - r28b
  • Android bundletool
  • Android 模拟器
  • cmake
  • TestNG
  • Python 3.8.10
  • Node.js 22, npm, React Native
  • Ruby, RubyGems
  • fastlane
  • Flutter 3.32.4
  • jEnv

拉取 Docker 镜像

该 Docker 镜像基于本仓库中的 DockerfileGithub Action 上公开自动构建,其中没有任何隐藏内容。

拉取最新的 Docker 镜像:

docker pull mingc/android-build-box:latest

提示: 你可以使用特定稳定版本的标签,而不是 latest 标签,以避免破坏你的构建。 例如:mingc/android-build-box:1.25.0

查看 标签列表 以获取所有可用标签,查看 变更日志 以了解标签之间的变化,以及查看 兼容性矩阵 以了解各种软件的详细信息,例如标签 1.2.0 包含 SDK x、y 和 z 等。

使用方法

使用镜像构建 Android 项目

关于如何使用缓存,请参阅 缓存部分

你可以使用以下 Docker 命令来构建你的 Android 项目:

cd <android 项目目录> # 切换到你的项目根目录。 docker run --rm -v `pwd`:/project mingc/android-build-box bash -c 'cd /project; ./gradlew build'

要构建 .aab 包发布版本,请使用 ./gradlew bundleRelease

cd <android 项目目录> # 切换到你的项目根目录。 docker run --rm -v `pwd`:/project mingc/android-build-box bash -c 'cd /project; ./gradlew bundleRelease'

以交互式 bash shell 运行 Docker 镜像:

docker run -v `pwd`:/project -it mingc/android-build-box bash -l

缓存

请注意,缓存不会减少所需的磁盘空间总量,反而会增加空间占用。例如,对于 Android SDK,缓存可能会使空间占用翻倍。首先是镜像本身所需的空间,其次是缓存所需的空间。例如,对于 1.25.0 版本,镜像需要 16.2GB 的空间,如果缓存 SDK(不做任何更改),则还需要额外的 6GB 空间:16.2GB(原始镜像) + SDK 缓存(默认为 6GB)。

jEnv 缓存

为了通过 jEnv 缓存全局 Java 设置(文件 /root/.jenv/version),最简单的方法是缓存整个 jEnv 文件夹 /root/.jenv/

首先在主机上创建用于缓存 jEnv 的目录。以下示例中,目录为 ~/.dockercache/jenv/

# mkdir ~/.dockercache/jenv

其次创建一个 命名卷,名为 jenv-cache命名卷 是必要的,以确保容器中的 jEnv 内容得以保留。最简单的方式如下:

# docker volume create --driver local --opt type=none --opt device=~/.dockercache/jenv/ --opt o=bind jenv-cache

最后,在创建或运行容器时,请确保通过以下命令包含 命名卷

-v jenv-cache:"/root/.jenv/"

例如:

# docker run --rm -v jenv-cache:"/root/.jenv/" mingc/android-build-box bash -l `echo "Hello World"`

Gradle 缓存

在 Docker 命令中添加以下参数以缓存主目录中的 Gradle 文件夹:

-v "$HOME/.dockercache/gradle":"/root/.gradle"

例如:

docker run --rm -v `pwd`:/project -v "$HOME/.dockercache/gradle":"/root/.gradle" mingc/android-build-box bash -c 'cd /project; ./gradlew build'

最后一步是通过在 gradle.properties 中添加以下内容启用缓存:

org.gradle.caching=true

可以添加到项目的 gradle.properties 或全局的 gradle.properties(位于 $HOME/.dockercache/gradle/gradle.properties)。

Android SDK 缓存

缓存 SDK 的好处是可以在镜像中更新或删除 SDK 平台/构建工具。例如,在 1.25.0 版本中,可以删除 SDK 27、28 和 29,并添加构建工具 34。从 1.25.0 开始,/opt/android-sdk/ 大约需要 6GB 的磁盘空间。

jEnv 缓存 类似,需要一个 命名卷

首先在主机上创建用于缓存 SDK 的目录。以下示例中,目录为 ~/.dockercache/android-sdk/

# mkdir ~/.dockercache/android-sdk

其次创建一个 命名卷,名为 android-sdk-cache命名卷 是必要的,以确保容器中的内容得以保留。最简单的方式如下:

# docker volume create --driver local --opt type=none --opt device=~/.dockercache/android-sdk/ --opt o=bind android-sdk-cache android-sdk-cache

最后,在创建或运行容器时,请确保通过以下命令包含 命名卷

-v android-sdk-cache:"/opt/android-sdk/"

例如:

# docker run --rm -v android-sdk-cache:"/opt/android-sdk/" mingc/android-build-box bash -l

现在可以在容器内使用 sdkmanager 来安装构建工具、平台等。以下是一些常用命令: 列出已安装的内容:

# sdkmanager --list_installed

卸载一个平台:

# sdkmanager --uninstall 'platforms;android-26'

安装一个平台:

# sdkmanager --install 'platforms;android-26'

--install--uninstall 标志都支持传递列表,例如:

# sdkmanager --uninstall 'platforms;android-26' 'platforms;android-27'

完整文档请参阅 此处

推荐的 gradle.properties 配置

建议为 Gradle 设置以下 jvmargs

  • -Xmx8192m
    • 设置 JVM 可使用的最大内存为 8192m,支持以 g(即 GB)为单位的值。
  • -XX:MaxMetaspaceSize=1024m
    • 必须设置,因为 Gradle 存在 bug gradle/gradle#19750,否则元空间大小将无限制。
  • -XX:+UseContainerSupport
    • 允许 JVM 知道它在容器中运行,默认可选。
  • -XX:MaxRAMPercentage=97.5
    • 允许 JVM 最多使用容器中 97.5% 的 RAM,可以设置为 1。

容器可用的总内存应大于 Xmx 值 + MaxMetaspaceSize 值。例如,如果为容器分配了 10GB 内存,并使用上述值,则 10GB = 8GB (Xmx) + 1GB (MaxMetaspaceSize) + 1GB(开销/缓冲区/其他)。如果容器只有 4GB 可用内存,则以下配置是合理的:4GB = 3072m (Xmx) + 756m (MaxMetaspaceSize) + 256mb(开销等)。

完整的 gradle.properties 配置如下:

org.gradle.jvmargs=-Xmx8192m -XX:MaxMetaspaceSize=1024m -XX:+UseContainerSupport -XX:MaxRAMPercentage=97.5

org.gradle.jvmargs=-Xmx3072m -XX:MaxMetaspaceSize=756m -XX:+UseContainerSupport -XX:MaxRAMPercentage=97.5

使用 Bitbucket Pipelines 构建 Android 项目

如果你的 Android 项目托管在 Bitbucket 仓库中,并希望使用流水线功能来构建它,你可以直接指定这个 Docker 镜像。 以下是一个 bitbucket-pipelines.yml 的示例:

image: mingc/android-build-box:latest pipelines: default: - step: caches: - gradle - gradle-wrapper - android-emulator script: - . ~/.bash_profile - jenv global 11 # 切换 Java 版本 - bash ./gradlew assemble definitions: caches: gradle-wrapper: ~/.gradle/wrapper android-emulator: $ANDROID_HOME/system-images/android-21

缓存用于 存储从之前构建中下载的依赖项,以加速后续构建。

使用 Github Actions 构建 Flutter 项目

以下是一个 .github/workflows/main.yml 的示例,用于使用此 Docker 镜像构建 Flutter 项目:

name: CI on: [push] jobs: build: runs-on: ubuntu-20.04 container: mingc/android-build-box:latest steps: - uses: actions/checkout@v3 - uses: actions/cache@v3 with: path: /root/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: | ${{ runner.os }}-gradle- - name: Build run: | echo "Work dir: $(pwd)" echo "User: $(whoami)" flutter --version flutter analyze flutter build apk - name: Archive apk uses: actions/upload-artifact@v3 with: name: apk path: build/app/outputs/apk - name: Test run: flutter test - name: Clean build to avoid action/cache error run: rm -fr build

注意:为了提高安全性,请直接通过提交哈希引用 action,而不是标签。请参考我们的 action 示例。

在 Docker 构建机器中运行 Android 模拟器

参考以下指南:

你可以编写一个脚本来创建并启动一个 ARM 模拟器,用于运行集成测试、仪器测试或单元测试:

#!/bin/bash # ARM 模拟器可能较慢,因此增加 adb 超时时间以避免错误。 export ADB_INSTALL_TIMEOUT=30 # 下载 ARM 系统镜像以创建 ARM 模拟器。 sdkmanager "system-images;android-22;default;armeabi-v7a" # 创建一个 ARM AVD 模拟器,带有 100MB 的 SD 卡存储空间。 # 使用 `echo "no"` 是因为它会询问是否使用自定义硬件配置文件,而你不希望使用。 # 参考:https://medium.com/@AndreSand/android-emulator-on-docker-container-f20c49b129ef echo "no" | avdmanager create avd \ -n Android_5.1_API_22 \ -k "system-images;android-22;default;armeabi-v7a" \ -c 100M \ --force # 在后台启动模拟器 $ANDROID_HOME/emulator/emulator -avd Android_5.1_API_22 -no-skin -no-audio -no-window -no-boot-anim -gpu off & # 注意:你需要添加适当的延迟时间,以等待模拟器启动。

注意:目前不支持 x86_64 模拟器。详情请参阅 Issue #18

选择系统 Java 版本

1.23.0 版本开始,使用 jenv 来切换 java 版本。1.23.0 之前的版本使用 update-alternatives,简要文档可参考 此处

请参阅 已安装的 Java 版本矩阵 了解已安装的 Java 版本,以及 jEnv 缓存 了解如何缓存 全局 Java 版本。

为了让 jenv 正常工作,请在执行任何 jenv 命令之前运行以下命令:

. ~/.bash_profile

以下文档适用于 jenv。请注意,如果容器被移除(即使用 --rm 标志运行),除非 jEnv 被缓存,否则 全局 更改将不会保留。

列出所有可用的 java 版本:

# jenv versions system 11 11.0 11.0.17 17 * 17.0 (set by /root/.jenv/version) 17.0.5 1.8 1.8.0.352 openjdk64-11.0.17 openjdk64-17.0.5 openjdk64-1.8.0.352

全局 java 版本切换为 Java 8

root@f7e7773edb7f:/project# jenv global 1.8 root@f7e7773edb7f:/project# java -version openjdk version "1.8.0_352" OpenJDK Runtime Environment (build 1.8.0_352-8u352-ga-1~20.04-b08) OpenJDK 64-Bit Server VM (build 25.352-b08, mixed mode)

全局 java 版本切换为 Java 11

root@f7e7773edb7f:/project# jenv global 11 root@f7e7773edb7f:/project# java -version openjdk version "11.0.17" 2022-10-18 OpenJDK Runtime Environment (build 11.0.17+8-post-Ubuntu-1ubuntu220.04) OpenJDK 64-Bit Server VM (build 11.0.17+8-post-Ubuntu-1ubuntu220.04, mixed mode, sharing)

将本地(即当前文件夹)java 版本切换为 Java 1.8

root@f7e7773edb7f:/project# jenv local 1.8 root@f7e7773edb7f:/project# java -version openjdk version "1.8.0_352" OpenJDK Runtime Environment (build 1.8.0_352-8u352-ga-1~20.04-b08) OpenJDK 64-Bit Server VM (build 25.352-b08, mixed mode) root@f7e7773edb7f:/project# cd .. root@f7e7773edb7f:/# java -version openjdk version "17.0.5" 2022-10-18 OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04) OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)

也可以通过在当前目录中创建 .java-version 文件来实现。示例请参考 SampleProject 文件

构建 Docker 镜像

在构建之前,请检查你的磁盘空间,因为镜像大小可能在 ~10GB 到 ~16GB 之间。

使用 Docker buildx,因此至少需要 Docker Engine 19.03 或更高版本。

如果你想自己构建 Docker 镜像,可以使用以下命令:

docker buildx build -t android-build-box .

有三个构建目标。默认目标是 complete-flutter,其他两个目标是 minimalcomplete

构建目标SDK CLI 工具jEnvplatform-toolsplatforms / build-toolsbundletoolNDKFastlane / RakeNode 等Flutter
minimal
complete
complete-flutter

无论选择哪个构建目标,默认都会获取最新的软件。这意味着最新的 SDK CLI 工具、jEnv 等。对于 platforms 和 build-tools,会使用最新的 8 个平台及其相关的构建工具和扩展。

如果你想使用文件中指定的软件版本,必须将 _TAGGED 构建参数设置为 tagged。如果你想指定要安装的软件版本,则必须按照上述方式设置 _TAGGED 参数,并将 _VERSION 构建参数设置为所需的版本。

例如,构建目标为 minimal,SDK CLI 工具版本为 4333796,jEnv 版本为 0.5.6

docker buildx build --target minimal --build-arg ANDROID_SDK_TOOLS_TAGGED="tagged" --build-arg ANDROID_SDK_TOOLS_VERSION="4333796" --build-arg JENV_TAGGED="tagged" --build-arg JENV_RELEASE="0.5.6"

请参阅 Dockerfile 获取所有变量名称。请注意,jEnv 是特殊的,其版本由 JENV_RELEASE 参数指定。

参考资料