├── README.md ├── .github └── workflows │ └── main.yml └── start_emu_headless.sh /README.md: -------------------------------------------------------------------------------- 1 | Check the medium blog for further details 2 | 3 | https://medium.com/@Amr.sa/run-android-emulator-out-of-the-box-with-github-actions-b84cba766e62 4 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Android emulator 2 | on: 3 | workflow_dispatch: 4 | 5 | env: 6 | ANDROID_ARCH: x86_64 7 | ANDROID_TARGET: google_apis_playstore 8 | API_LEVEL: 33 9 | ANDROID_BUILD_TOOLS_VERSION: 33.0.2 10 | ANDROID_SDK_PACKAGES: system-images;android-33;google_apis_playstore;x86_64 platforms;android-33 build-tools;33.0.2 platform-tools emulator 11 | EMULATOR_TIMEOUT: 350 12 | EMULATOR_NAME: nexus 13 | 14 | jobs: 15 | playwright-emulator: 16 | timeout-minutes: 20 17 | runs-on: macos-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | 21 | - name: Add avdmanager and sdkmanager to system PATH 22 | run: | 23 | echo "$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/emulator:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/${{ env.ANDROID_BUILD_TOOLS_VERSION }}" >> $GITHUB_PATH 24 | 25 | - name: Install Sdk 26 | run: | 27 | yes Y | sdkmanager --licenses 28 | sdkmanager --install ${ANDROID_SDK_PACKAGES} 29 | 30 | - name: Build emulator 31 | run: | 32 | echo "no" | avdmanager --verbose create avd --force -n $EMULATOR_NAME --abi "${ANDROID_TARGET}/${ANDROID_ARCH}" -k "system-images;android-${API_LEVEL};${ANDROID_TARGET};${ANDROID_ARCH}" 33 | 34 | - name: Launch emulator 35 | run: | 36 | chmod +x ./start_emu_headless.sh 37 | EMULATOR_TIMEOUT=$EMULATOR_TIMEOUT EMULATOR_NAME=$EMULATOR_NAME ./start_emu_headless.sh 38 | -------------------------------------------------------------------------------- /start_emu_headless.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BL='\033[0;34m' 4 | G='\033[0;32m' 5 | RED='\033[0;31m' 6 | YE='\033[1;33m' 7 | NC='\033[0m' # No Color 8 | 9 | emulator_name=${EMULATOR_NAME} 10 | 11 | function check_hardware_acceleration() { 12 | if [[ "$HW_ACCEL_OVERRIDE" != "" ]]; then 13 | hw_accel_flag="$HW_ACCEL_OVERRIDE" 14 | else 15 | if [[ "$OSTYPE" == "darwin"* ]]; then 16 | # macOS-specific hardware acceleration check 17 | HW_ACCEL_SUPPORT=$(sysctl -a | grep -E -c '(vmx|svm)') 18 | else 19 | # generic Linux hardware acceleration check 20 | HW_ACCEL_SUPPORT=$(grep -E -c '(vmx|svm)' /proc/cpuinfo) 21 | fi 22 | 23 | if [[ $HW_ACCEL_SUPPORT == 0 ]]; then 24 | hw_accel_flag="-accel off" 25 | else 26 | hw_accel_flag="-accel on" 27 | fi 28 | fi 29 | 30 | echo "$hw_accel_flag" 31 | } 32 | 33 | hw_accel_flag=$(check_hardware_acceleration) 34 | 35 | function launch_emulator () { 36 | adb devices | grep emulator | cut -f1 | xargs -I {} adb -s "{}" emu kill 37 | options="@${emulator_name} -no-window -no-snapshot -screen no-touch -noaudio -memory 2048 -no-boot-anim ${hw_accel_flag} -camera-back none" 38 | if [[ "$OSTYPE" == *linux* ]]; then 39 | echo "${OSTYPE}: emulator ${options} -gpu off" 40 | nohup emulator $options -gpu off & 41 | fi 42 | if [[ "$OSTYPE" == *darwin* ]] || [[ "$OSTYPE" == *macos* ]]; then 43 | echo "im here" 44 | echo "${OSTYPE}: emulator ${options} -gpu swiftshader_indirect" 45 | nohup emulator $options -gpu swiftshader_indirect & 46 | fi 47 | 48 | if [ $? -ne 0 ]; then 49 | echo "Error launching emulator" 50 | return 1 51 | fi 52 | } 53 | 54 | function check_emulator_status () { 55 | printf "${G}==> ${BL}Checking emulator booting up status 🧐${NC}\n" 56 | start_time=$(date +%s) 57 | spinner=( "⠹" "⠺" "⠼" "⠶" "⠦" "⠧" "⠇" "⠏" ) 58 | i=0 59 | # Get the timeout value from the environment variable or use the default value of 300 seconds (5 minutes) 60 | timeout=${EMULATOR_TIMEOUT:-300} 61 | 62 | while true; do 63 | result=$(adb shell getprop sys.boot_completed 2>&1) 64 | 65 | if [ "$result" == "1" ]; then 66 | printf "\e[K${G}==> \u2713 Emulator is ready : '$result' ${NC}\n" 67 | adb devices -l 68 | adb shell input keyevent 82 69 | break 70 | elif [ "$result" == "" ]; then 71 | printf "${YE}==> Emulator is partially Booted! 😕 ${spinner[$i]} ${NC}\r" 72 | else 73 | printf "${RED}==> $result, please wait ${spinner[$i]} ${NC}\r" 74 | i=$(( (i+1) % 8 )) 75 | fi 76 | 77 | current_time=$(date +%s) 78 | elapsed_time=$((current_time - start_time)) 79 | if [ $elapsed_time -gt $timeout ]; then 80 | printf "${RED}==> Timeout after ${timeout} seconds elapsed 🕛.. ${NC}\n" 81 | break 82 | fi 83 | sleep 4 84 | done 85 | }; 86 | 87 | function disable_animation() { 88 | adb shell "settings put global window_animation_scale 0.0" 89 | adb shell "settings put global transition_animation_scale 0.0" 90 | adb shell "settings put global animator_duration_scale 0.0" 91 | }; 92 | 93 | function hidden_policy() { 94 | adb shell "settings put global hidden_api_policy_pre_p_apps 1;settings put global hidden_api_policy_p_apps 1;settings put global hidden_api_policy 1" 95 | }; 96 | 97 | launch_emulator 98 | sleep 2 99 | check_emulator_status 100 | sleep 1 101 | disable_animation 102 | sleep 1 103 | hidden_policy 104 | sleep 1 105 | --------------------------------------------------------------------------------