一个优化的 Docker 镜像,包含 Android SDK 和 Flutter SDK。
最新 镜像始终包含最新的软件,包括最新的 8 个 Android SDK 平台及其相关构建工具。
最新的 标记 版本包含以下组件:
该 Docker 镜像基于本仓库中的 Dockerfile 在 Github Action 上公开自动构建,其中没有任何隐藏内容。
拉取最新的 Docker 镜像:
docker pull mingc/android-build-box:latest
提示: 你可以使用特定稳定版本的标签,而不是 latest 标签,以避免破坏你的构建。
例如:mingc/android-build-box:1.25.0。
查看 标签列表 以获取所有可用标签,查看 变更日志 以了解标签之间的变化,以及查看 兼容性矩阵 以了解各种软件的详细信息,例如标签 1.2.0 包含 SDK x、y 和 z 等。
关于如何使用缓存,请参阅 缓存部分。
你可以使用以下 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 缓存全局 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"`
在 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)。
缓存 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 设置以下 jvmargs:
-Xmx8192m
-XX:MaxMetaspaceSize=1024m
-XX:+UseContainerSupport
-XX:MaxRAMPercentage=97.5
容器可用的总内存应大于 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
如果你的 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/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 示例。
参考以下指南:
你可以编写一个脚本来创建并启动一个 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。
从 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 文件。
在构建之前,请检查你的磁盘空间,因为镜像大小可能在 ~10GB 到 ~16GB 之间。
使用 Docker buildx,因此至少需要 Docker Engine 19.03 或更高版本。
如果你想自己构建 Docker 镜像,可以使用以下命令:
docker buildx build -t android-build-box .
有三个构建目标。默认目标是 complete-flutter,其他两个目标是 minimal 和 complete。
| 构建目标 | SDK CLI 工具 | jEnv | platform-tools | platforms / build-tools | bundletool | NDK | Fastlane / Rake | Node 等 | 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 参数指定。