{"id":15022192,"url":"https://github.com/reactivecircus/android-emulator-runner","last_synced_at":"2025-05-13T22:07:54.318Z","repository":{"id":41831117,"uuid":"219782401","full_name":"ReactiveCircus/android-emulator-runner","owner":"ReactiveCircus","description":"A GitHub Action for installing, configuring and running hardware-accelerated Android Emulators on macOS virtual machines.","archived":false,"fork":false,"pushed_at":"2025-03-28T14:52:59.000Z","size":1974,"stargazers_count":1055,"open_issues_count":76,"forks_count":207,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-04-25T08:26:50.356Z","etag":null,"topics":["android-emulators","ci","github-actions","testing"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ReactiveCircus.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ychescale9"}},"created_at":"2019-11-05T15:45:42.000Z","updated_at":"2025-04-23T20:15:55.000Z","dependencies_parsed_at":"2023-01-11T17:22:08.712Z","dependency_job_id":"97754c82-9ed4-4c6e-b2df-6bca4f6dad26","html_url":"https://github.com/ReactiveCircus/android-emulator-runner","commit_stats":{"total_commits":253,"total_committers":51,"mean_commits":4.96078431372549,"dds":0.5059288537549407,"last_synced_commit":"c77bfe7c0bb57698e777375b61762daf9d578400"},"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReactiveCircus%2Fandroid-emulator-runner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReactiveCircus%2Fandroid-emulator-runner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReactiveCircus%2Fandroid-emulator-runner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReactiveCircus%2Fandroid-emulator-runner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ReactiveCircus","download_url":"https://codeload.github.com/ReactiveCircus/android-emulator-runner/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251362138,"owners_count":21577398,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-emulators","ci","github-actions","testing"],"created_at":"2024-09-24T19:57:37.362Z","updated_at":"2025-04-29T21:23:26.879Z","avatar_url":"https://github.com/ReactiveCircus.png","language":"TypeScript","funding_links":["https://github.com/sponsors/ychescale9"],"categories":[],"sub_categories":[],"readme":"# GitHub Action - Android Emulator Runner\n\n\u003cp align=\"left\"\u003e\n  \u003ca href=\"https://github.com/ReactiveCircus/android-emulator-runner\"\u003e\u003cimg alt=\"GitHub Actions status\" src=\"https://github.com/ReactiveCircus/android-emulator-runner/workflows/Main%20workflow/badge.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA GitHub Action for installing, configuring and running hardware-accelerated Android Emulators on Linux and macOS virtual machines.\n\nThe old ARM-based emulators were slow and are no longer supported by Google. The modern Intel Atom (x86 and x86_64) emulators can be fast, but rely on two forms of hardware acceleration to reach their peak potential: [Graphics Acceleration](https://developer.android.com/studio/run/emulator-acceleration#accel-graphics), e.g. `emulator -gpu host` and [Virtual Machine(VM) Acceleration](https://developer.android.com/studio/run/emulator-acceleration#accel-vm), e.g. `emulator -accel on`. **Note:** GPU and VM Acceleration are two different and non-mutually exclusive forms of Hardware Acceleration.\n\nThis presents a challenge when running emulators on CI especially when running emulators within a docker container, because **Nested Virtualization** must be supported by the host VM which isn't the case for most cloud-based CI providers due to infrastructural limits.  If you want to learn more about Emulators on CI, here's an article [Yang](https://github.com/ychescale9) wrote: [Running Android Instrumented Tests on CI](https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76).\n\n## Running hardware accelerated emulators on Linux runners\n\nGitHub's [larger Linux runners support running hardware accelerated emulators](https://github.blog/changelog/2023-02-23-hardware-accelerated-android-virtualization-on-actions-windows-and-linux-larger-hosted-runners/) which is [free for public GitHub repos](https://github.blog/2024-01-17-github-hosted-runners-double-the-power-for-open-source/). It is now recommended to use the **Ubuntu** (`ubuntu-latest`) runners which are 2-3 times faster than the **macOS** ones which are also a lot more expensive. Remember to enable KVM in your workflow before running this action:\n\n```\n- name: Enable KVM group perms\n  run: |\n    echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n    sudo udevadm control --reload-rules\n    sudo udevadm trigger --name-match=kvm\n```\n\n## A note on VM Acceleration and why we don't need HAXM anymore\n\nAccording to [this documentation](https://developer.android.com/studio/run/emulator-acceleration#vm-mac), \"on Mac OS X v10.10 Yosemite and higher, the Android Emulator uses the built-in [Hypervisor.Framework](https://developer.apple.com/documentation/hypervisor) by default, and falls back to using Intel HAXM if Hypervisor.Framework fails to initialize.\" This means that **HAXM is only needed to achieve VM Acceleration if this default Hypervisor is not available on macOS machines.**\n\n**Note**: Manually enabling and downloading HAXM is not recommended because it is redundant and not needed (see above), and for users of macOS 10.13 High Sierra and higher: macOS 10.13 [disables installation of kernel extensions by default](https://developer.apple.com/library/archive/technotes/tn2459/_index.html#//apple_ref/doc/uid/DTS40017658). Because Intel HAXM is a kernel extension, we would need to manually enable its installation on the base runner VM. Furthermore, manually trying to install HAXM on a Github Runner [brings up a popup](https://github.com/ReactiveCircus/android-emulator-runner/discussions/286#discussioncomment-4026120) which further hinders tests from running.\n\n## Purpose\n\nThis action helps automate and configure the process of setting up an emulator and running your tests by doing the following:\n\n- Install / update the required **Android SDK** components including `build-tools`, `platform-tools`, `platform` (for the required API level), `emulator` and `system-images` (for the required API level).\n- Create a new instance of **AVD** with the provided [configurations](#configurations).\n- Launch a new Emulator with the provided [configurations](#configurations).\n- Wait until the Emulator is booted and ready for use.\n- Run a custom script provided by user once the Emulator is up and running - e.g. `./gradlew connectedCheck`.\n- Kill the Emulator and finish the action.\n\n## Usage \u0026 Examples\n\nA workflow that uses **android-emulator-runner** to run your instrumented tests on **API 29**:\n\n```yml\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v4\n\n      - name: Enable KVM\n        run: |\n          echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n          sudo udevadm control --reload-rules\n          sudo udevadm trigger --name-match=kvm\n\n      - name: run tests\n        uses: reactivecircus/android-emulator-runner@v2\n        with:\n          api-level: 29\n          script: ./gradlew connectedCheck\n```\n\nWe can also leverage GitHub Actions's build matrix to test across multiple configurations:\n\n```yml\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        api-level: [21, 23, 29]\n        target: [default, google_apis]\n    steps:\n      - name: checkout\n        uses: actions/checkout@v4\n\n      - name: Enable KVM\n        run: |\n          echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n          sudo udevadm control --reload-rules\n          sudo udevadm trigger --name-match=kvm\n\n      - name: run tests\n        uses: reactivecircus/android-emulator-runner@v2\n        with:\n          api-level: ${{ matrix.api-level }}\n          target: ${{ matrix.target }}\n          arch: x86_64\n          profile: Nexus 6\n          script: ./gradlew connectedCheck\n```\n\nIf you need specific versions of **NDK** and **CMake** installed:\n\n```yml\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v4\n\n      - name: Enable KVM\n        run: |\n          echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n          sudo udevadm control --reload-rules\n          sudo udevadm trigger --name-match=kvm\n\n      - name: run tests\n        uses: reactivecircus/android-emulator-runner@v2\n        with:\n          api-level: 29\n          ndk: 21.0.6113669\n          cmake: 3.10.2.4988404\n          script: ./gradlew connectedCheck\n```\n\nIf you need a specific [SDK Extensions](https://developer.android.com/guide/sdk-extensions) for the system image but not the platform:\n\n```yml\njobs:\n  test:\n    runs-on: ubuntu-latest\n    steps:\n      - name: checkout\n        uses: actions/checkout@v4\n\n      - name: Enable KVM\n        run: |\n          echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n          sudo udevadm control --reload-rules\n          sudo udevadm trigger --name-match=kvm\n\n      - name: run tests\n        uses: reactivecircus/android-emulator-runner@v2\n        with:\n          api-level: 34\n          system-image-api-level: 34-ext9\n          target: android-automotive\n          script: ./gradlew connectedCheck\n```\n\nWe can significantly reduce emulator startup time by setting up AVD snapshot caching:\n\n1. add a `gradle/actions/setup-gradle@v4` step for caching Gradle, more details see [#229](https://github.com/ReactiveCircus/android-emulator-runner/issues/229)\n2. add an `actions/cache@v4` step for caching the `avd`\n3. add a `reactivecircus/android-emulator-runner@v2` step to generate a clean snapshot - specify `emulator-options` without `no-snapshot`\n4. add another `reactivecircus/android-emulator-runner@v2` step to run your tests using existing AVD / snapshot - specify `emulator-options` with `no-snapshot-save`\n\n```yml\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        api-level: [21, 23, 29]\n    steps:\n      - name: checkout\n        uses: actions/checkout@v4\n\n      - name: Enable KVM\n        run: |\n          echo 'KERNEL==\"kvm\", GROUP=\"kvm\", MODE=\"0666\", OPTIONS+=\"static_node=kvm\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules\n          sudo udevadm control --reload-rules\n          sudo udevadm trigger --name-match=kvm\n\n      - name: Gradle cache\n        uses: gradle/actions/setup-gradle@v3\n        \n      - name: AVD cache\n        uses: actions/cache@v4\n        id: avd-cache\n        with:\n          path: |\n            ~/.android/avd/*\n            ~/.android/adb*\n          key: avd-${{ matrix.api-level }}\n\n      - name: create AVD and generate snapshot for caching\n        if: steps.avd-cache.outputs.cache-hit != 'true'\n        uses: reactivecircus/android-emulator-runner@v2\n        with:\n          api-level: ${{ matrix.api-level }}\n          force-avd-creation: false\n          emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none\n          disable-animations: false\n          script: echo \"Generated AVD snapshot for caching.\"\n\n      - name: run tests\n        uses: reactivecircus/android-emulator-runner@v2\n        with:\n          api-level: ${{ matrix.api-level }}\n          force-avd-creation: false\n          emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none\n          disable-animations: true\n          script: ./gradlew connectedCheck\n```\n\n## Configurations\n\n| **Input** | **Required** | **Default** | **Description** |\n|-|-|-|-|\n| `api-level` | Required | N/A | API level of the platform and system image - e.g. `23`, `33`, `35-ext15`, `Baklava`. **Minimum API level supported is 15**. |\n| `system-image-api-level` | Optional | same as `api-level` | API level of the system image - e.g. `34-ext10`, `35-ext15`. |\n| `target` | Optional | `default` | Target of the system image - `default`, `google_apis`, `playstore`, `android-wear`, `android-wear-cn`, `android-tv`, `google-tv`, `aosp_atd`, `google_atd`, `android-automotive`, `android-automotive-playstore` or `android-desktop`. Note that `aosp_atd` and `google_atd` currently require the following: `api-level: 30`, `arch: x86` or `arch: arm64-v8` and `channel: canary`. |\n| `arch` | Optional | `x86` | CPU architecture of the system image - `x86`, `x86_64` or `arm64-v8a`. Note that `x86_64` image is only available for API 21+. `arm64-v8a` images require Android 4.2+ and are limited to fewer API levels (e.g. 30). |\n| `profile` | Optional | N/A | Hardware profile used for creating the AVD - e.g. `Nexus 6`. For a list of all profiles available, run `avdmanager list device`. |\n| `cores` | Optional | 2 | Number of cores to use for the emulator (`hw.cpu.ncore` in config.ini). |\n| `ram-size` | Optional | N/A | Size of RAM to use for this AVD, in KB or MB, denoted with K or M. - e.g. `2048M` |\n| `heap-size` | Optional | N/A | Heap size to use for this AVD, in KB or MB, denoted with K or M. - e.g. `512M` |\n| `sdcard-path-or-size` | Optional | N/A | Path to the SD card image for this AVD or the size of a new SD card image to create for this AVD, in KB or MB, denoted with K or M. - e.g. `path/to/sdcard`, or `1000M`. |\n| `disk-size` | Optional | N/A | Disk size, or partition size to use for this AVD. Either in bytes or KB, MB or GB, when denoted with K, M or G. - e.g. `2048M` |\n| `avd-name` | Optional | `test` | Custom AVD name used for creating the Android Virtual Device. |\n| `force-avd-creation` | Optional | `true` | Whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`. |\n| `emulator-boot-timeout` | Optional | `600` | Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes. |\n| `emulator-port` | Optional | `5554` | Emulator port to use. Allows to run this action on multiple workers on a single machine at the same time. This input is available for the script as `EMULATOR_PORT` enviromental variable. This port is automatically used by android device related tasks in gradle |\n| `emulator-options` | Optional | See below | Command-line options used when launching the emulator (replacing all default options) - e.g. `-no-window -no-snapshot -camera-back emulated`. |\n| `disable-animations` | Optional | `true` | Whether to disable animations - `true` or `false`. |\n| `disable-spellchecker` | Optional | `false` | Whether to disable spellchecker - `true` or `false`. |\n| `disable-linux-hw-accel` | Optional | `auto` | Whether to disable hardware acceleration on Linux machines - `true`, `false` or `auto`.|\n| `enable-hw-keyboard` | Optional | `false` | Whether to enable hardware keyboard - `true` or `false`. |\n| `emulator-build` | Optional | N/A | Build number of a specific version of the emulator binary to use e.g. `6061023` for emulator v29.3.0.0. |\n| `working-directory` | Optional | `./` | A custom working directory - e.g. `./android` if your root Gradle project is under the `./android` sub-directory within your repository. Will be used for `script` \u0026 `pre-emulator-launch-script`. |\n| `ndk` | Optional | N/A | Version of NDK to install - e.g. `21.0.6113669` |\n| `cmake` | Optional | N/A | Version of CMake to install - e.g. `3.10.2.4988404` |\n| `channel` | Optional | stable | Channel to download the SDK components from - `stable`, `beta`, `dev`, `canary` |\n| `script` | Required | N/A | Custom script to run - e.g. to run Android instrumented tests on the emulator: `./gradlew connectedCheck` |\n| `pre-emulator-launch-script` | Optional | N/A | Custom script to run after creating the AVD and before launching the emulator - e.g. `./adjust-emulator-configs.sh` |\n\nDefault `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim`.\n\n## Who is using Android Emulator Runner?\n\nThese are some of the open-source projects using (or used) **Android Emulator Runner**:\n\n- [coil-kt/coil](https://github.com/coil-kt/coil/blob/master/.github/workflows)\n- [cashapp/sqldelight](https://github.com/cashapp/sqldelight/blob/master/.github/workflows)\n- [square/workflow-kotlin](https://github.com/square/workflow-kotlin/tree/main/.github/workflows)\n- [square/retrofit](https://github.com/square/retrofit/blob/master/.github/workflows)\n- [natario1/CameraView](https://github.com/natario1/CameraView/tree/master/.github/workflows)\n- [natario1/Transcoder](https://github.com/natario1/Transcoder/tree/master/.github/workflows)\n- [chrisbanes/insetter](https://github.com/chrisbanes/insetter/tree/main/.github/workflows)\n- [slackhq/keeper](https://github.com/slackhq/keeper/tree/main/.github/workflows)\n- [android/compose-samples](https://github.com/android/compose-samples/tree/main/.github/workflows)\n- [ReactiveCircus/streamlined](https://github.com/ReactiveCircus/streamlined/tree/main/.github/workflows)\n- [ReactiveCircus/FlowBinding](https://github.com/ReactiveCircus/FlowBinding/tree/main/.github/workflows)\n- [JakeWharton/RxBinding](https://github.com/JakeWharton/RxBinding/tree/master/.github/workflows)\n- [vinaygaba/Learn-Jetpack-Compose-By-Example](https://github.com/vinaygaba/Learn-Jetpack-Compose-By-Example/tree/master/.github/workflows)\n- [ashishb/adb-enhanced](https://github.com/ashishb/adb-enhanced/tree/master/.github/workflows)\n- [vgaidarji/ci-matters](https://github.com/vgaidarji/ci-matters/blob/master/.github/workflows/main.yaml)\n- [simpledotorg/simple-android](https://github.com/simpledotorg/simple-android/tree/master/.github/workflows)\n- [cashapp/copper](https://github.com/cashapp/copper/blob/trunk/.github/workflows/build.yaml)\n- [square/radiography](https://github.com/square/radiography/blob/main/.github/workflows/android.yml)\n- [Shopify/android-testify](https://github.com/Shopify/android-testify/blob/master/.github/workflows/sample_build.yml)\n- [square/leakcanary](https://github.com/square/leakcanary/tree/main/.github/workflows)\n- [hash-checker/hash-checker](https://github.com/hash-checker/hash-checker/tree/master/.github/workflows)\n- [hash-checker/hash-checker-lite](https://github.com/hash-checker/hash-checker-lite/tree/master/.github/workflows)\n- [Kiwix/kiwix-android](https://github.com/kiwix/kiwix-android/blob/develop/.github/workflows)\n- [wikimedia/apps-android-wikipedia](https://github.com/wikimedia/apps-android-wikipedia/blob/main/.github/workflows)\n- [google/android-fhir](https://github.com/google/android-fhir/tree/master/.github/workflows)\n- [google/accompanist](https://github.com/google/accompanist/blob/main/.github/workflows)\n- [dotanuki-labs/norris](https://github.com/dotanuki-labs/norris/blob/master/.github/workflows/main.yml)\n- [tinylog-org/tinylog](https://github.com/tinylog-org/tinylog/blob/v3.0/.github/workflows/build.yaml)\n- [hzi-braunschweig/SORMAS-Project](https://github.com/hzi-braunschweig/SORMAS-Project/blob/development/.github/workflows/sormas_app_ci.yml)\n- [ACRA/acra](https://github.com/ACRA/acra/blob/master/.github/workflows/test.yml)\n- [bitfireAT/davx5-ose](https://github.com/bitfireAT/davx5-ose/blob/dev-ose/.github/workflows/test-dev.yml)\n- [robolectric/robolectric](https://github.com/robolectric/robolectric/blob/master/.github/workflows/tests.yml)\n- [home-assistant/android](https://github.com/home-assistant/android/blob/master/.github/workflows/pr.yml)\n\nIf you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactivecircus%2Fandroid-emulator-runner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freactivecircus%2Fandroid-emulator-runner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactivecircus%2Fandroid-emulator-runner/lists"}