environment-setup-android
Prepare and validate Android SDK, Java, and device tooling for Appium Android drivers
Skill body
environment-setup-android
Goal
Prepares a working Android automation environment for Appium by validating Java, Android SDK command-line tools, required SDK packages, environment variables, and ADB device visibility, with a verify-and-fix loop until all mandatory checks pass.
Decision Logic
- If host OS is unsupported for Android SDK setup: stop and ask the user to switch to macOS, Linux, or Windows.
- If
java -versionandjavac -versionalready succeed: keep the existing Java setup and do not reconfigureJAVA_HOME. - If host OS is macOS and Java setup is needed (fresh environment): use Android Studio app setup as the primary method for both
ANDROID_HOME($HOME/Library/Android/sdk) andJAVA_HOME(Android Studio JBR). Check both/Applications/Android Studio.appand$HOME/Applications/Android Studio.app, and prefer the official direct download flow before Homebrew. - If host OS is Linux and Java setup is needed (fresh environment): use Android Studio bundled JBR as the primary method when Android Studio is installed, then fallback to distro/package-manager OpenJDK.
- If host OS is Windows and Java setup is needed (fresh environment): use Android Studio bundled JBR as the primary method when Android Studio is installed, then fallback to Microsoft OpenJDK package install.
- If host OS is Linux: use package manager +
$HOME/Android/Sdkconventions. - If host OS is Windows: use Android SDK tools with persistent user environment variables.
- If
javaorjavacis missing: run step 3 to install/configure Java. - If the user wants official Android tooling setup flow: download Android Studio from the official site first, use its bundled JBR for Java, then bootstrap the SDK with the official
sdkmanager. - If
ANDROID_HOMEis unset/empty or theANDROID_HOMEpath does not exist: run step 2 to install command-line tools and create the SDK path. - If Java tooling is missing or broken (
java/javacchecks fail): run step 3 before Android SDK package/license commands. - If
adbis missing: installplatform-toolsviasdkmanager. - If emulator binary is missing under
ANDROID_HOME/emulator/emulator(or Windows equivalent): install emulator packages. - Prepare emulator instances using the latest stable system-image version by default.
- Use host-optimized emulator architecture (native architecture first, then fallback architecture).
- Skip step 7 emulator preparation if at least one device is already connected or at least one emulator instance already exists.
- If required SDK packages are missing: install them and re-run checks.
Instructions
- Detect OS and validate Java/base tooling
macOS/Linux:
uname -s java -version javac -version echo "$JAVA_HOME" command -v adb ls "$ANDROID_HOME/emulator/emulator" test -x "$ANDROID_HOME/emulator/emulator" && echo "emulator binary: OK"Windows PowerShell:
[System.Environment]::OSVersion.VersionString java -version javac -version $env:JAVA_HOME Get-Command adb.exe -ErrorAction SilentlyContinue Test-Path "$env:ANDROID_HOME\emulator\emulator.exe" - Install Android SDK tooling when
ANDROID_HOMEpath is missing Trigger checks:- macOS/Linux:
[ -n "$ANDROID_HOME" ] && [ -d "$ANDROID_HOME" ] || echo "run step 2" - Windows PowerShell:
if (-not $env:ANDROID_HOME -or -not (Test-Path $env:ANDROID_HOME)) { "run step 2" }Option A (Android Studio app path; macOS priority when app exists):
- Download Android Studio from
https://developer.android.com/studio. - On macOS, check for the app in both
/Applications/Android Studio.appand$HOME/Applications/Android Studio.app. - You may either complete first launch and install SDK components from SDK Manager, or use the bundled JBR plus the official command-line tools zip to bootstrap the SDK non-interactively with
sdkmanager. - Use platform default SDK path after setup:
- macOS:
$HOME/Library/Android/sdk - Linux:
$HOME/Android/Sdk - Windows:
%LOCALAPPDATA%\Android\Sdk
- macOS:
Option B (CLI tools only):
- macOS official command-line tools example:
curl -L -o /tmp/commandlinetools-mac-latest.zip https://dl.google.com/android/repository/commandlinetools-mac-14742923_latest.zip unzip -q /tmp/commandlinetools-mac-latest.zip -d /tmp/android-cmdline-tools export JAVA_HOME="$HOME/Applications/Android Studio.app/Contents/jbr/Contents/Home" if [ ! -d "$JAVA_HOME" ]; then export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" fi export PATH="$JAVA_HOME/bin:$PATH" /tmp/android-cmdline-tools/cmdline-tools/bin/sdkmanager --sdk_root="$HOME/Library/Android/sdk" "cmdline-tools;latest" - macOS/Homebrew fallback example:
[ -d "/Applications/Android Studio.app" ] || brew install --cask android-commandlinetools mkdir -p "$HOME/Library/Android/sdk/cmdline-tools/latest" cp -R /opt/homebrew/share/android-commandlinetools/* "$HOME/Library/Android/sdk/cmdline-tools/latest/" - Linux example (Debian/Ubuntu-style prerequisites + cmdline tools placement):
sudo apt-get update sudo apt-get install -y unzip wget openjdk-21-jdk mkdir -p "$HOME/Android/Sdk/cmdline-tools/latest" - Windows example (PowerShell, after extracting Android command-line tools zip):
New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\Android\Sdk\cmdline-tools\latest"
- macOS/Linux:
- Configure Java for fresh environments (skip if Java already works)
Trigger checks:
- macOS/Linux:
if command -v java >/dev/null 2>&1 && command -v javac >/dev/null 2>&1; then java -version >/dev/null 2>&1 && javac -version >/dev/null 2>&1 && echo "Java already available; skip step 3" || echo "run step 3" else echo "run step 3" fi - Windows PowerShell:
if ((Get-Command java.exe -ErrorAction SilentlyContinue) -and (Get-Command javac.exe -ErrorAction SilentlyContinue)) { java -version *> $null if ($LASTEXITCODE -eq 0) { javac -version *> $null if ($LASTEXITCODE -eq 0) { "Java already available; skip step 3" } else { "run step 3" } } else { "run step 3" } } else { "run step 3" }macOS primary method for fresh setup (Android Studio bundled JBR):
if [ -d "$HOME/Applications/Android Studio.app/Contents/jbr/Contents/Home" ]; then export JAVA_HOME="$HOME/Applications/Android Studio.app/Contents/jbr/Contents/Home" export PATH="$JAVA_HOME/bin:$PATH" java -version javac -version elif [ -d "/Applications/Android Studio.app/Contents/jbr/Contents/Home" ]; then export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" export PATH="$JAVA_HOME/bin:$PATH" java -version javac -version else echo "Android Studio JBR not found; use fallback method below" fimacOS fallback method (only when Android Studio is not installed):
brew install --cask temurin export JAVA_HOME="$(/usr/libexec/java_home -v 21)" export PATH="$JAVA_HOME/bin:$PATH" java -version javac -versionLinux primary method for fresh setup (Android Studio bundled JBR):
if [ -d "$HOME/android-studio/jbr" ]; then export JAVA_HOME="$HOME/android-studio/jbr" elif [ -d "/opt/android-studio/jbr" ]; then export JAVA_HOME="/opt/android-studio/jbr" elif [ -d "/usr/local/android-studio/jbr" ]; then export JAVA_HOME="/usr/local/android-studio/jbr" else echo "Android Studio JBR not found; use fallback method below" fi if [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ]; then export PATH="$JAVA_HOME/bin:$PATH" java -version javac -version fiLinux fallback method (OpenJDK 21 example):
export JAVA_HOME="/usr/lib/jvm/java-21-openjdk-amd64" export PATH="$JAVA_HOME/bin:$PATH" java -version javac -versionWindows primary method for fresh setup (Android Studio bundled JBR, persist for current user):
$studioJbrCandidates = @( "$env:LOCALAPPDATA\Programs\Android Studio\jbr", "C:\Program Files\Android\Android Studio\jbr" ) $studioJbr = $studioJbrCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1 if ($studioJbr) { [Environment]::SetEnvironmentVariable('JAVA_HOME', $studioJbr, 'User') $currentPath = [Environment]::GetEnvironmentVariable('Path', 'User') if ($currentPath -notlike "*$studioJbr\bin*") { [Environment]::SetEnvironmentVariable('Path', "$currentPath;$studioJbr\bin", 'User') } $env:JAVA_HOME = [Environment]::GetEnvironmentVariable('JAVA_HOME', 'User') $env:PATH = "$studioJbr\bin;$env:PATH" java -version javac -version } else { "Android Studio JBR not found; use fallback method below" }Windows fallback method (only when Android Studio is not installed):
winget install -e --id Microsoft.OpenJDK.17 --accept-source-agreements --accept-package-agreements $jdkRoot = Get-ChildItem "C:\Program Files\Microsoft" -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -like 'jdk-*' } | Sort-Object Name -Descending | Select-Object -First 1 if ($jdkRoot) { [Environment]::SetEnvironmentVariable('JAVA_HOME', $jdkRoot.FullName, 'User') $currentPath = [Environment]::GetEnvironmentVariable('Path', 'User') if ($currentPath -notlike "*$($jdkRoot.FullName)\\bin*") { [Environment]::SetEnvironmentVariable('Path', "$currentPath;$($jdkRoot.FullName)\\bin", 'User') } $env:JAVA_HOME = [Environment]::GetEnvironmentVariable('JAVA_HOME', 'User') $env:PATH = "$env:JAVA_HOME\\bin;$env:PATH" } java -version javac -version
- macOS/Linux:
- Configure Android environment variables and PATH
macOS (priority: Android Studio SDK path):
export ANDROID_HOME="$HOME/Library/Android/sdk" export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/emulator:$PATH" echo "$ANDROID_HOME" command -v adb ls "$ANDROID_HOME/emulator/emulator"Linux:
export ANDROID_HOME="$HOME/Android/Sdk" export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/cmdline-tools/latest/bin:$PATH" echo "$ANDROID_HOME" command -v adb ls "$ANDROID_HOME/emulator/emulator"Windows PowerShell (persist for current user):
[Environment]::SetEnvironmentVariable('ANDROID_HOME', "$env:LOCALAPPDATA\Android\Sdk", 'User') $androidPaths = "$env:LOCALAPPDATA\Android\Sdk\platform-tools;$env:LOCALAPPDATA\Android\Sdk\cmdline-tools\latest\bin" $currentPath = [Environment]::GetEnvironmentVariable('Path', 'User') if ($currentPath -notlike "*$androidPaths*") { [Environment]::SetEnvironmentVariable('Path', "$currentPath;$androidPaths", 'User') } $env:ANDROID_HOME = [Environment]::GetEnvironmentVariable('ANDROID_HOME', 'User') - Accept SDK licenses and install required packages
macOS/Linux:
if command -v sdkmanager >/dev/null 2>&1; then yes | sdkmanager --sdk_root="$ANDROID_HOME" --licenses; fi if command -v sdkmanager >/dev/null 2>&1; then sdkmanager --sdk_root="$ANDROID_HOME" "platform-tools" "build-tools;34.0.0" "platforms;android-34" "emulator"; fiWindows PowerShell:
if (Get-Command sdkmanager.bat -ErrorAction SilentlyContinue) { cmd /c "(for /l %i in (1,1,200) do @echo y)| sdkmanager.bat --licenses" } if (Get-Command sdkmanager.bat -ErrorAction SilentlyContinue) { sdkmanager.bat "platform-tools" "build-tools;34.0.0" "platforms;android-34" "emulator" }If license acceptance still fails in headless CI-like runs, pre-seed license hashes and retry package install:
$licensesDir = "$env:ANDROID_HOME\licenses" New-Item -ItemType Directory -Force $licensesDir | Out-Null Set-Content -Path "$licensesDir\android-sdk-license" -Value "24333f8a63b6825ea9c5514f83c2829b004d1fee`n8933bad161af4178b1185d1a37fbf41ea5269c55`nd56f5187479451eabf01fb78af6dfcb131a6481e" - Verify Android SDK and ADB state
macOS/Linux:
if command -v sdkmanager >/dev/null 2>&1; then sdkmanager --list | head -n 80; fi adb version command -v emulator ls "$ANDROID_HOME/emulator/emulator" test -x "$ANDROID_HOME/emulator/emulator" && echo "emulator binary: OK"Windows PowerShell:
if (Get-Command sdkmanager.bat -ErrorAction SilentlyContinue) { sdkmanager.bat --list } adb.exe version Test-Path "$env:ANDROID_HOME\emulator\emulator.exe" - Optional emulator instance preparation (if no physical device is connected and no emulator exists)
Skip step 7 when either of the following is true:
- At least one device is already connected (
adb devicesshows adeviceentry) - At least one emulator instance already exists (
emulator -list-avdsis non-empty)
Prepare an emulator instance using the latest stable system-image version and host-optimized architecture only when both are false. macOS/Linux (prefer native architecture first, then fallback):
ARCH=$(uname -m) if [ "$ARCH" = "arm64" ] || [ "$ARCH" = "aarch64" ]; then PRIMARY_ARCH="arm64-v8a" FALLBACK_ARCH="x86_64" else PRIMARY_ARCH="x86_64" FALLBACK_ARCH="arm64-v8a" fi LATEST_API=$(sdkmanager --list | grep -o "system-images;android-[0-9]\+;google_apis;${PRIMARY_ARCH}" | sed 's/.*android-\([0-9]\+\).*/\1/' | sort -n | tail -1) IMAGE_ARCH="$PRIMARY_ARCH" if [ -z "$LATEST_API" ]; then LATEST_API=$(sdkmanager --list | grep -o "system-images;android-[0-9]\+;google_apis;${FALLBACK_ARCH}" | sed 's/.*android-\([0-9]\+\).*/\1/' | sort -n | tail -1) IMAGE_ARCH="$FALLBACK_ARCH" fi IMAGE="system-images;android-${LATEST_API};google_apis;${IMAGE_ARCH}" sdkmanager "$IMAGE" echo "no" | avdmanager create avd -n "api${LATEST_API}-google-${IMAGE_ARCH}" -k "$IMAGE" emulator -list-avdsWindows PowerShell (prefer x86_64, fallback arm64-v8a):
$primaryArch = "x86_64" $fallbackArch = "arm64-v8a" $matches = sdkmanager.bat --list | Select-String "system-images;android-[0-9]+;google_apis;$primaryArch" $imageArch = $primaryArch if (-not $matches) { $matches = sdkmanager.bat --list | Select-String "system-images;android-[0-9]+;google_apis;$fallbackArch" $imageArch = $fallbackArch } $latestApi = ($matches | ForEach-Object { [int]([regex]::Match($_.Line, 'android-(\d+)').Groups[1].Value) } | Sort-Object)[-1] $image = "system-images;android-$latestApi;google_apis;$imageArch" sdkmanager.bat $image cmd /c "echo no| avdmanager.bat create avd -n api$latestApi-google-$imageArch -k $image" emulator.exe -list-avdsReport version details in the task result:
- macOS/Linux:
emulator -version emulator -list-avds if command -v sdkmanager >/dev/null 2>&1; then sdkmanager --list | grep "system-images;android-" | head -n 20; fi - Windows PowerShell:
emulator.exe -version emulator.exe -list-avds if (Get-Command sdkmanager.bat -ErrorAction SilentlyContinue) { sdkmanager.bat --list | Select-String "system-images;android-" | Select-Object -First 20 }
- At least one device is already connected (
- Completion criteria
Mark complete only when all are true:
java -versionandjavac -versionsucceedadbis executable fromPATH- Emulator binary exists under
ANDROID_HOME/emulator/emulator(or%ANDROID_HOME%\emulator\emulator.exeon Windows) - Required SDK packages are installed (
platform-tools, one platform, one build-tools version) - Existing Java setup is preserved when Java already works (no forced reconfiguration)
- On fresh setup, Android Studio bundled JBR is used as
JAVA_HOMEwhen Android Studio is present (macOS/Linux/Windows) - Android environment checks pass without requiring a connected device
- Latest stable emulator/system-image version is prepared with host-optimized architecture only when no connected devices and no existing emulators are present; otherwise step 7 is skipped and current version details are reported in the task result
Constraints
- Always use detect-first behavior and install only missing components.
- Re-run validation commands after each install/config change.
- Do not report success if
adbis unavailable or emulator binary check fails. - Treat optional dependencies and optional doctor warnings as non-blocking unless the user requests those features.
- Ask the user before installing optional dependencies; do not install them by default.
- If privileged commands are needed, pause and provide exact commands for user execution.
- Keep Android setup independent from Appium driver installation steps.
- Use shell-appropriate commands (
bashfor macOS/Linux, PowerShell/cmd for Windows).