Home
Perfecto的头像

Perfecto

React Native + Detox:Android AOSP 模拟器配置

AI 速览

这篇文章是一份简洁的操作指南,讲述了为什么以及如何使用 AOSP 模拟器替代 Google APIs 模拟器进行 E2E 测试。Google APIs 模拟器预装了 Google Play Services,这些后台服务会持续占用 CPU 资源,导致测试环境不稳定、经常出现 ANR(应用无响应)。AOSP 模拟器不包含这些服务,运行更加纯净稳定。文章提供了从安装系统镜像、创建模拟器、配置 Quick-Boot 快照到脚本化启动的完整步骤,可以直接复制使用


系列文章导航


背景

在使用 Detox 进行 Android E2E 测试时,Google APIs 镜像的模拟器经常出现卡顿和应用未响应的问题。Detox 官方文档 强烈推荐使用 AOSP 模拟器(不带 Google Play Services)进行自动化测试。

原因在于:Google APIs 模拟器预装了 Google Play Services,这些后台服务会持续占用 CPU 资源,导致测试环境不稳定。


环境

  • macOS + Apple Silicon (M3 Pro)
  • Android SDK 已安装
  • Detox 20.x

步骤 1:安装 cmdline-tools

检查是否已安装:

ls $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager

如果不存在,打开 Android Studio: Tools → SDK Manager → SDK Tools → Android SDK Command-line Tools (latest) → Apply


步骤 2:安装 AOSP 系统镜像

检测架构并安装对应镜像:

# Apple Silicon
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-35;default;arm64-v8a"
# Intel Mac / Linux
$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-35;default;x86_64"

关键点:default 表示 AOSP(不带 Google APIs),google_apisgoogle_apis_playstore 是带 Google 服务的版本。


步骤 3:创建 AOSP 模拟器

$ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd \
  -n Pixel_7_API_35_AOSP \
  -d pixel_7 \
  --package "system-images;android-35;default;arm64-v8a"

验证:

$ANDROID_HOME/emulator/emulator -list-avds
# 输出:Pixel_7_API_35_AOSP

步骤 4:配置 Quick-Boot 快照

Quick-Boot 可以让模拟器从快照启动,从 30 秒缩短到 5 秒左右。

首次配置(保存快照):

# 创建配置
echo "saveOnExit = true" > ~/.android/avd/Pixel_7_API_35_AOSP.avd/quickbootChoice.ini

# 启动模拟器
$ANDROID_HOME/emulator/emulator @Pixel_7_API_35_AOSP

# 等待完全启动后关闭(快照自动保存)

保存后禁用自动保存(避免测试污染快照):

echo "saveOnExit = false" > ~/.android/avd/Pixel_7_API_35_AOSP.avd/quickbootChoice.ini

步骤 5:集成 Test Butler

Test Butler 可以自动处理系统弹窗(ANR、崩溃对话框),避免这些弹窗阻塞测试。

下载 APK:

mkdir -p e2e/lib/testbutler
curl -o e2e/lib/testbutler/test-butler-app-2.2.1.apk \
  https://repo1.maven.org/maven2/com/linkedin/testbutler/test-butler-app/2.2.1/test-butler-app-2.2.1.apk

更新 .detoxrc.js

emulator: {
  type: 'android.emulator',
  device: {
    avdName: 'Pixel_7_API_35_AOSP',
  },
  utilBinaryPaths: ['e2e/lib/testbutler/test-butler-app-2.2.1.apk'],
},

添加到 .gitignore

e2e/lib/testbutler/*.apk

步骤 6:自动化脚本

为了让团队成员(或 CI)能一键配置,创建了 scripts/setup-android-e2e.sh

#!/bin/bash
#
# Android E2E 测试环境设置脚本
# 支持 Apple Silicon (arm64) 和 Intel (x86_64) 架构
# 适用于本地开发和 CI 环境
#

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 配置
AVD_NAME="Pixel_7_API_35_AOSP"
DEVICE_TYPE="pixel_7"
API_LEVEL="35"
TEST_BUTLER_VERSION="2.2.1"
TEST_BUTLER_PATH="e2e/lib/testbutler"
TEST_BUTLER_APK="test-butler-app-${TEST_BUTLER_VERSION}.apk"

echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}  Android E2E 测试环境设置${NC}"
echo -e "${GREEN}========================================${NC}"

# 检测 ANDROID_HOME
if [ -z "$ANDROID_HOME" ]; then
  if [ -d "$HOME/Library/Android/sdk" ]; then
    export ANDROID_HOME="$HOME/Library/Android/sdk"
  elif [ -d "$HOME/Android/Sdk" ]; then
    export ANDROID_HOME="$HOME/Android/Sdk"
  else
    echo -e "${RED}错误: 未找到 ANDROID_HOME,请先安装 Android SDK${NC}"
    exit 1
  fi
fi
echo -e "${GREEN}✓${NC} ANDROID_HOME: $ANDROID_HOME"

# 检测 CPU 架构
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
  SYSTEM_IMAGE_ARCH="arm64-v8a"
  echo -e "${GREEN}✓${NC} 检测到 Apple Silicon (ARM64) 架构"
elif [ "$ARCH" = "x86_64" ]; then
  SYSTEM_IMAGE_ARCH="x86_64"
  echo -e "${GREEN}✓${NC} 检测到 Intel (x86_64) 架构"
else
  echo -e "${RED}错误: 不支持的架构: $ARCH${NC}"
  exit 1
fi

SYSTEM_IMAGE="system-images;android-${API_LEVEL};default;${SYSTEM_IMAGE_ARCH}"
SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
AVDMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/avdmanager"
EMULATOR="$ANDROID_HOME/emulator/emulator"

# 检查 cmdline-tools
if [ ! -f "$SDKMANAGER" ]; then
  echo -e "${YELLOW}警告: 未找到 sdkmanager${NC}"
  echo "请在 Android Studio 中安装: Tools → SDK Manager → SDK Tools → Android SDK Command-line Tools (latest)"
  exit 1
fi
echo -e "${GREEN}✓${NC} sdkmanager 可用"

# 步骤 1: 安装 AOSP 系统镜像
echo ""
echo -e "${YELLOW}[1/4] 安装 AOSP 系统镜像...${NC}"
echo "镜像: $SYSTEM_IMAGE"
"$SDKMANAGER" "$SYSTEM_IMAGE" --verbose | tail -5
echo -e "${GREEN}✓${NC} 系统镜像安装完成"

# 步骤 2: 创建 AOSP 模拟器
echo ""
echo -e "${YELLOW}[2/4] 创建 AOSP 模拟器...${NC}"

# 检查是否已存在
if "$EMULATOR" -list-avds 2>/dev/null | grep -q "^${AVD_NAME}$"; then
  echo -e "${YELLOW}  模拟器 ${AVD_NAME} 已存在,跳过创建${NC}"
else
  echo "no" | "$AVDMANAGER" create avd \
    -n "$AVD_NAME" \
    -d "$DEVICE_TYPE" \
    --package "$SYSTEM_IMAGE"
  echo -e "${GREEN}✓${NC} 模拟器 ${AVD_NAME} 创建完成"
fi

# 步骤 3: 下载 Test Butler APK
echo ""
echo -e "${YELLOW}[3/4] 下载 Test Butler APK...${NC}"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
APK_DIR="$PROJECT_ROOT/$TEST_BUTLER_PATH"
APK_FILE="$APK_DIR/$TEST_BUTLER_APK"

mkdir -p "$APK_DIR"

if [ -f "$APK_FILE" ]; then
  echo -e "${YELLOW}  Test Butler APK 已存在,跳过下载${NC}"
else
  MAVEN_URL="https://repo1.maven.org/maven2/com/linkedin/testbutler/test-butler-app/${TEST_BUTLER_VERSION}/${TEST_BUTLER_APK}"
  echo "下载: $MAVEN_URL"
  curl -f -o "$APK_FILE" "$MAVEN_URL"
  echo -e "${GREEN}✓${NC} Test Butler APK 下载完成"
fi

# 步骤 4: 配置 Quick-Boot (可选,仅本地环境)
echo ""
echo -e "${YELLOW}[4/4] 配置 Quick-Boot...${NC}"

AVD_DIR="$HOME/.android/avd/${AVD_NAME}.avd"
QUICKBOOT_FILE="$AVD_DIR/quickbootChoice.ini"

if [ -d "$AVD_DIR" ]; then
  # 检查是否已有快照
  if [ -f "$QUICKBOOT_FILE" ]; then
    echo -e "${YELLOW}  Quick-Boot 配置已存在${NC}"
  else
    # 创建初始配置(saveOnExit = true)
    echo "saveOnExit = true" > "$QUICKBOOT_FILE"
    echo -e "${GREEN}✓${NC} Quick-Boot 配置已创建"
    echo ""
    echo -e "${YELLOW}提示: 请手动完成快照保存:${NC}"
    echo "  1. 运行: \$ANDROID_HOME/emulator/emulator @${AVD_NAME}"
    echo "  2. 等待模拟器完全启动"
    echo "  3. 关闭模拟器(快照会自动保存)"
    echo "  4. 运行: echo 'saveOnExit = false' > $QUICKBOOT_FILE"
  fi
else
  echo -e "${YELLOW}  AVD 目录不存在,跳过 Quick-Boot 配置${NC}"
fi

# 完成
echo ""
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}  设置完成!${NC}"
echo -e "${GREEN}========================================${NC}"
echo ""
echo "可用的模拟器:"
"$EMULATOR" -list-avds
echo ""
echo "运行 Android E2E 测试:"
echo "  pnpm test:run-e2e-android"
echo ""

脚本会:

  1. 检测 CPU 架构
  2. 安装对应的 AOSP 镜像
  3. 创建模拟器
  4. 下载 Test Butler
  5. 配置 Quick-Boot

CI 规划

目前 E2E 测试只在本地跑。未来上 GitHub Actions 时的考虑:

  • 架构差异:本地 Apple Silicon 用 arm64-v8a,CI 用 x86_64
  • 成本优化:本地用 macOS 调试,CI 用 Linux + Android 模拟器
  • 脚本兼容:setup 脚本已支持架构自动检测

遇到的坑

  1. cmdline-tools 缺失:Android Studio 默认不装,需要手动在 SDK Manager 勾选安装
  2. 镜像安装不完整:之前目录里只有 .installer,重新运行 sdkmanager 安装完整

配置验证清单

完成配置后,使用以下命令验证环境是否就绪:

# 1. 检查模拟器是否创建成功
$ANDROID_HOME/emulator/emulator -list-avds
# 预期输出:Pixel_7_API_35_AOSP

# 2. 检查 Test Butler APK 是否存在
ls e2e/lib/testbutler/test-butler-app-*.apk

# 3. 启动模拟器验证
$ANDROID_HOME/emulator/emulator @Pixel_7_API_35_AOSP

# 4. 运行 E2E 测试
pnpm test:run-e2e-android

参考

技术实践 APP开发 React Native E2E测试