Skip to content

Instantly share code, notes, and snippets.

@mrk-han
Last active February 24, 2024 09:06
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mrk-han/db70c7ce2dfdc8ac3e8ae4bec823ba51 to your computer and use it in GitHub Desktop.
Save mrk-han/db70c7ce2dfdc8ac3e8ae4bec823ba51 to your computer and use it in GitHub Desktop.
Select Emulator, Wait for Emulator to Start, Wait for Emulator to Boot, then Install Android.apk
#!/usr/bin/env bash
####################################################################################
# Adapted from various wait-for-boot scripts found online
# This is the most robust version I could write for MacOS
# MUST have upgraded Bash to run mapfile
# Can adapt the last 2 functions if you want to start an Emulator on CI
# This is part of a script we run locally before starting Appium automation on Android
####################################################################################
ANDROID_APP="path/to/android.apk"
BOOT_ANIMATION=""
FAIL_COUNTER=0
SECONDS_UNTIL_TIMEOUT=60
LINE="$(printf %"$(tput cols)"s | tr " " "-")" # https://stackoverflow.com/a/42763333/9470346
AVD_ARGS=" -wipe-data -no-snapshot" # You need a SPACE before the first argument. Find more args to use here: https://developer.android.com/studio/run/emulator-commandline
function selectAndLaunchEmulator() {
# Check if the emulator command exists on path first
if ! type emulator >/dev/null; then # >/dev/null hides stdout message.
echo "emulator command not found, make sure \"export PATH=\$PATH:\$ANDROID_HOME/emulator\" is in your Bash Profile and the Android SDK Tools are installed"
exit 1
fi
if ! type mapfile >/dev/null; then
echo "${LINE}"
echo "mapfile command not found, this is usually because your bash version is outdated. please run: \"brew install bash\""
echo "${LINE}"
exit 1
fi
# Gather emulators that exist on this computer
# DEVICES=( $(emulator -list-avds 2>&1) ) # 2>&1 reroutes stderr message to same output value as stdout(&1)
mapfile -t DEVICES < <(emulator -list-avds 2>&1)
# Display list of emulators
echo -e "\nAvailable Emulators
----------------------------------------"
N=1
for DEVICE in "${DEVICES[@]}"; do # Create DEVICES Array and use [@] to allow us to iterate through it
echo "$N) $DEVICE" # Iterate through Emulators and display their name next to a number which will be how the user selects the emulator
((N = N + 1))
done
# Request user input to decide which emulator to start
read -rp "
Choose an emulator by entering a number: " emulatorNumber
# If the input is valid, launch our emulator
if [[ ${emulatorNumber} -lt ${N} ]] && [[ ${emulatorNumber} -gt 0 ]]; then
DEVICE=${DEVICES[$emulatorNumber - 1]}
# shellcheck disable=SC2086
(emulator @${DEVICE}${AVD_ARGS} >/dev/null 2>&1 &)
else
echo "Invalid Entry. Please enter the number next to the Emulator name. You entered: $emulatorNumber"
fi
}
function waitForEmulatorToStart() {
until [[ "$BOOT_ANIMATION" =~ "stopped" ]]; do
BOOT_ANIMATION=$(adb -e shell getprop init.svc.bootanim 2>&1 &) # Checks state of emulator while in the boot animation
if [[ "$BOOT_ANIMATION" =~ "device not found" || "$BOOT_ANIMATION" =~ "device offline" || "$BOOT_ANIMATION" =~ "running" ]]; then
((FAIL_COUNTER += 1))
echo -e "\nWaiting for emulator to start.. $FAIL_COUNTER"
echo "Boot Animation State: $BOOT_ANIMATION"
if [[ ${FAIL_COUNTER} -gt ${SECONDS_UNTIL_TIMEOUT} ]]; then
echo -e "\nTimeout of $SECONDS_UNTIL_TIMEOUT seconds reached; failed to start emulator"
exit 1
fi
fi
sleep 1
done
echo -e "\n${LINE}"
echo -e "\nEmulator is ready!"
}
function waitForBootAnimationThenInstall() {
# After the boot animation stops, and while the emulator is starting up there can be an error, so we attempt to install until there isn't this error.
ADB_INSTALL_OUTPUT=$(adb install -r "${ANDROID_APP}" 2>&1)
regex="Can't find service"
until ! [[ "${ADB_INSTALL_OUTPUT}" =~ $regex ]]; do
echo ""
ADB_INSTALL_OUTPUT=$(adb install -r "${ANDROID_APP}" 2>&1)
echo -e "\nRetrying..."
echo -e "\n${ADB_INSTALL_OUTPUT}"
sleep 2
done
}
function main() {
selectAndLaunchEmulator
waitForEmulatorToStart
waitForBootAnimationThenInstall
}
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment