用Docker搭建Android CI环境
说实话,在没有容器化之前,我们的CI机器上总是装着各种互相冲突的SDK版本。有的项目要API 28,有的要API 30,升级一次模拟器就得重跑所有流水线。后来我用了Docker,才彻底摆脱了这个噩梦。
这一章,我就带你从头搭一个可用于TalkBack测试的Docker容器镜像。
为什么选择Docker?
- 环境一致性:本地、CI、生产环境使用同一镜像,杜绝「我这能跑」问题。
- 快速重建:模拟器崩溃?删容器重起,30秒恢复。
- 并行隔离:多个PR可以用不同容器跑测试,互不干扰。
你想想看,如果每个开发人员都要手动装一遍Android SDK、配置avd、调显卡驱动……那光环境搭建就能耗掉半天。用Docker,一条命令全搞定。
整体流程一览
先看一张架构图,理解我们接下来要做的事情:
第一步:编写Dockerfile
我个人习惯用Ubuntu 22.04做基础镜像,稳定性最好。
FROM ubuntu:22.04
# 避免交互式安装时卡住
ENV DEBIAN_FRONTEND=noninteractive
# 安装必要工具
RUN apt-get update && apt-get install -y --no-install-recommends \
wget unzip git openjdk-11-jdk \
libgtk-3-0 libxtst6 libxrender1 \
libdbus-glib-1-2 libx11-xcb1 \
qemu-kvm libvirt-daemon-system \
&& rm -rf /var/lib/apt/lists/*
# 设置ANDROID_HOME
ENV ANDROID_HOME=/opt/android-sdk
ENV ANDROID_SDK_ROOT=$ANDROID_HOME
ENV PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator
注意 KVM 权限:模拟器必须在内核支持虚拟化的环境下运行。CI节点如果是裸机或嵌套虚拟化,需要挂载
/dev/kvm 设备。我曾经在这个坑里卡了两天,后来发现是CI容器没有加 --device /dev/kvm 参数。
第二步:安装Android SDK与模拟器
这里用cmdline-tools来静默安装,干净利落。
# 下载并安装cmdline-tools
RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip \
&& unzip -q commandlinetools-linux-*.zip -d $ANDROID_HOME/cmdline-tools \
&& mv $ANDROID_HOME/cmdline-tools/cmdline-tools $ANDROID_HOME/cmdline-tools/latest \
&& rm commandlinetools-linux-*.zip
# 同意许可并安装SDK组件
RUN yes | sdkmanager --sdk_root=$ANDROID_HOME \
"platforms;android-30" \
"build-tools;30.0.3" \
"platform-tools" \
"emulator" \
"system-images;android-30;google_apis;x86_64"
嗯,这里要注意一点:国内下载系统镜像可能很慢。我建议在Dockerfile里加上代理变量,或者在CI配置里预缓存好镜像文件。
第三步:创建AVD
AVD配置文件写成脚本,方便后续重建。
# avd_create.sh
echo "no" | avdmanager create avd -n testAVD \
-k "system-images;android-30;google_apis;x86_64" \
-d pixel_4 --force
# 配置模拟器参数
echo "hw.gpu.enabled=no" >> ~/.android/avd/testAVD.avd/config.ini
echo "hw.ramSize=2048" >> ~/.android/avd/testAVD.avd/config.ini
echo "vm.heapSize=512" >> ~/.android/avd/testAVD.avd/config.ini
为什么关掉GPU? 因为无头环境下没有物理GPU,强行启用会导致模拟器闪退。我实测过,纯CPU渲染虽然慢一些,但稳定性非常好。
第四步:无头启动模拟器
核心命令就这一条:
emulator -avd testAVD -no-window -no-audio -no-boot-anim \
-gpu off -memory 2048 -port 5556
| 参数 | 说明 | 必要性 |
|---|---|---|
-no-window | 无窗口模式,适合CI | 必选 |
-no-audio | 禁用音频,减少资源 | 建议 |
-no-boot-anim | 跳过开机动画,加速启动 | 建议 |
-gpu off | 关闭GPU加速 | 必选 |
-port 5556 | ADB连接端口 | 可选 |
启动后需要等待系统完全就绪:
adb wait-for-device
# 等待系统启动完成(可能需要60秒)
while [ "$(adb shell getprop sys.boot_completed)" != "1" ]; do
sleep 5
done
核心技巧:在CI流水线中,建议把模拟器启动放到后台(&),然后配合
timeout 命令,防止测试卡死超过规定时间。
第五步:集成到CI流水线
拿GitLab CI举例,.gitlab-ci.yml的关键部分:
talkback_test:
image: my-registry/android-talkback:latest
services:
- docker:dind
variables:
DOCKER_HOST: tcp://docker:2375
before_script:
- echo "启动模拟器(后台)..."
- emulator -avd testAVD -no-window -no-audio -no-boot-anim -gpu off &
- adb wait-for-device
- while [ "$(adb shell getprop sys.boot_completed)" != "1" ]; do sleep 5; done
- echo "模拟器就绪"
script:
- ./gradlew :app:connectedCheck # 运行TalkBack测试
after_script:
- adb emu kill # 关闭模拟器
artifacts:
paths:
- app/build/reports/
哦对了,docker:dind 是为了支持Docker in Docker,如果你用Kubernetes Runner可能需要额外配置挂载 /dev/kvm。
常见坑与调优
- 模拟器启动超时:我遇到过CI节点资源不足导致启动时间超过2分钟。解决方案:增大CI超时时间,同时调低模拟器内存(如设为1024M)。
- AVD被锁定:如果前一次构建异常退出,下次启动会报错。可以在
before_script里先执行adb emu kill 2>/dev/null || true清理残留。 - TalkBack测试本身需要无障碍服务开启:在测试用例的Setup里用
UiAutomation开启即可,不用在模拟器里手动设置。
最终镜像大小与优化
完整镜像大概 4.5GB,其中系统镜像占了 1.8GB。如果你在意存储,可以去掉无用的语言包和字体。我自己常用的优化方法:
RUN rm -rf /opt/android-sdk/system-images/android-30/google_apis/x86_64/system.img.checksum \
&& rm -rf /opt/android-sdk/emulator/resources \
&& apt-get clean
这样能省出 300MB 空间。