mirror of
https://github.com/reactivecircus/android-emulator-runner.git
synced 2026-09-01 10:09:33 +00:00
Compare commits
35 Commits
v2.26.0
...
yc/m1-runner
| Author | SHA1 | Date | |
|---|---|---|---|
| 437356159b | |||
| fa92a0ff54 | |||
| bc2cd2aaea | |||
| 61a61f94a9 | |||
| 426fbd2820 | |||
| e1bd48ca1d | |||
| 1e33853aad | |||
| c479bb6c0f | |||
| 677db68893 | |||
| f9c2835191 | |||
| 1036f55734 | |||
| 5a481d20f1 | |||
| f72f505164 | |||
| fabc29122a | |||
| 2cfd145246 | |||
| e1bdfefaa7 | |||
| b35b1c6e69 | |||
| acd15a6841 | |||
| a2c97ef57f | |||
| 8c71f5ed72 | |||
| 743ec40c5b | |||
| bad4154821 | |||
| bdaf04916f | |||
| 8e947e5bd6 | |||
| e1248ae048 | |||
| 8d5c4be650 | |||
| ce60a72e42 | |||
| 3c9349d876 | |||
| 949d52fd17 | |||
| 87e972298f | |||
| ea00f72211 | |||
| a4845e8d39 | |||
| a47c099672 | |||
| 411cd10ea9 | |||
| 9320c5114f |
@@ -5,9 +5,6 @@
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"globals": {
|
||||
|
||||
+23
-12
@@ -1,5 +1,6 @@
|
||||
name: Main workflow
|
||||
on:
|
||||
workflow_call:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
@@ -17,15 +18,11 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
api-level: [16, 23, 29]
|
||||
os: [ubuntu-latest]
|
||||
api-level: [23, 29]
|
||||
target: [default, google_apis]
|
||||
arch: [x86]
|
||||
exclude:
|
||||
- os: ubuntu-latest
|
||||
api-level: 23
|
||||
- os: ubuntu-latest
|
||||
api-level: 29
|
||||
- target: google_apis
|
||||
api-level: 16
|
||||
- target: google_apis
|
||||
@@ -33,17 +30,21 @@ jobs:
|
||||
- target: google_apis
|
||||
api-level: 29
|
||||
include:
|
||||
- os: macos-latest
|
||||
- os: ubuntu-latest
|
||||
api-level: 24
|
||||
target: playstore
|
||||
arch: x86
|
||||
- os: macos-latest
|
||||
- os: ubuntu-latest
|
||||
api-level: 30
|
||||
target: aosp_atd
|
||||
arch: x86
|
||||
- os: macos-11
|
||||
- os: macos-14
|
||||
api-level: 31
|
||||
target: google_apis
|
||||
arch: arm64-v8a
|
||||
- os: ubuntu-latest
|
||||
api-level: 34
|
||||
target: aosp_atd
|
||||
arch: x86_64
|
||||
|
||||
steps:
|
||||
@@ -60,11 +61,11 @@ jobs:
|
||||
npm run lint
|
||||
npm test
|
||||
|
||||
- name: Java 15
|
||||
uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 15
|
||||
java-version: 21
|
||||
|
||||
- uses: actions/cache@v3
|
||||
id: avd-cache
|
||||
with:
|
||||
@@ -80,6 +81,13 @@ jobs:
|
||||
build-root-directory: test-fixture
|
||||
arguments: assembleAndroidTest
|
||||
|
||||
- name: enable KVM for linux runners
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: run emulator to generate snapshot for caching
|
||||
if: steps.avd-cache.outputs.cache-hit != 'true'
|
||||
uses: ./
|
||||
@@ -114,6 +122,9 @@ jobs:
|
||||
disable-animations: true
|
||||
working-directory: ./test-fixture/
|
||||
channel: canary
|
||||
pre-emulator-launch-script: |
|
||||
echo "Running pre emulator launch script. Printing the working directory now:"
|
||||
pwd
|
||||
script: |
|
||||
echo $GITHUB_REPOSITORY
|
||||
adb devices
|
||||
|
||||
@@ -5,7 +5,7 @@ on:
|
||||
os:
|
||||
description: 'OS'
|
||||
required: true
|
||||
default: 'macos-latest'
|
||||
default: 'ubuntu-latest'
|
||||
api-level:
|
||||
description: 'API level of the platform and system image'
|
||||
required: true
|
||||
@@ -51,17 +51,21 @@ jobs:
|
||||
npm run lint
|
||||
npm test
|
||||
|
||||
- name: Java 15
|
||||
uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 15
|
||||
- uses: actions/cache@v3
|
||||
java-version: 21
|
||||
|
||||
- uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
|
||||
gradle-home-cache-cleanup: true
|
||||
|
||||
- name: enable KVM for linux runners
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: run action
|
||||
uses: ./
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
name: Re-Run Tests on PR Comment Workflow
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
rerun-tests-job:
|
||||
if: github.event.issue.pull_request && contains(github.event.comment.body, 'run tests') # if comment is created on a PR, can also use the syntax if: contains(github.event.comment.html_url, '/pull/')
|
||||
uses: ./.github/workflows/main.yml
|
||||
@@ -1,5 +1,36 @@
|
||||
# Change Log
|
||||
|
||||
## v2.30.1
|
||||
|
||||
* Run action on Node 20. - [#371](https://github.com/ReactiveCircus/android-emulator-runner/pull/371)
|
||||
|
||||
## v2.30.0
|
||||
|
||||
* Update to Node 20. - [#369](https://github.com/ReactiveCircus/android-emulator-runner/pull/369)
|
||||
|
||||
## v2.29.0
|
||||
|
||||
* Fixed emulator download URL. - [#343](https://github.com/ReactiveCircus/android-emulator-runner/pull/343)
|
||||
* Upgrade to latest npm dependencies. - [#347](https://github.com/ReactiveCircus/android-emulator-runner/pull/347) [#355](https://github.com/ReactiveCircus/android-emulator-runner/pull/355)
|
||||
* Update SDK command-line tools to `11.0`. - [#356](https://github.com/ReactiveCircus/android-emulator-runner/pull/356)
|
||||
* Update SDK build tools to `34.0.0`. - [#356](https://github.com/ReactiveCircus/android-emulator-runner/pull/356)
|
||||
|
||||
## v2.28.0
|
||||
|
||||
* Add `emulator-boot-timeout` to support configuring maximum time waiting for emulator boot. - [#326](https://github.com/ReactiveCircus/android-emulator-runner/pull/326)
|
||||
* Support non-integer `api-level`. - [#317](https://github.com/ReactiveCircus/android-emulator-runner/pull/317)
|
||||
* Replace deprecated `ANDROID_SDK_ROOT` with `ANDROID_HOME`. - [304](https://github.com/ReactiveCircus/android-emulator-runner/pull/304)
|
||||
* Update SDK command-line tools to `9.0`. - [#331](https://github.com/ReactiveCircus/android-emulator-runner/pull/331)
|
||||
* Update SDK build tools to `33.0.2`. - [#331](https://github.com/ReactiveCircus/android-emulator-runner/pull/331)
|
||||
|
||||
## v2.27.0
|
||||
|
||||
* Added `pre-emulator-launch-script` to support running script after creating the AVD and before launching the emulator. - [#247](https://github.com/ReactiveCircus/android-emulator-runner/pull/247) @nilsreichardt.
|
||||
* Update to Node 16. - [#276](https://github.com/ReactiveCircus/android-emulator-runner/pull/276) @mattjohnsonpint.
|
||||
* Update NPM dependencies. - [#282](https://github.com/ReactiveCircus/android-emulator-runner/pull/282) @mattjohnsonpint.
|
||||
* Update README with more context on hardware acceleration on GitHub hosted runners. - [#279](https://github.com/ReactiveCircus/android-emulator-runner/pull/279) @mrk-han.
|
||||
|
||||
|
||||
## v2.26.0
|
||||
|
||||
* Support [github-actions-typing](https://github.com/krzema12/github-actions-typing). - [#257](https://github.com/ReactiveCircus/android-emulator-runner/pull/257) @LeoColman.
|
||||
|
||||
@@ -4,14 +4,33 @@
|
||||
<a href="https://github.com/ReactiveCircus/android-emulator-runner"><img alt="GitHub Actions status" src="https://github.com/ReactiveCircus/android-emulator-runner/workflows/Main%20workflow/badge.svg"></a>
|
||||
</p>
|
||||
|
||||
A GitHub Action for installing, configuring and running hardware-accelerated Android Emulators on macOS virtual machines.
|
||||
A GitHub Action for installing, configuring and running hardware-accelerated Android Emulators on Linux and macOS virtual machines.
|
||||
|
||||
The old ARM-based emulators were slow and are no longer supported by Google. The modern Intel Atom (x86 and x86_64) emulators require hardware acceleration (HAXM on Mac & Windows, QEMU on Linux) from the host to run fast. This presents a challenge on CI as to be able to run hardware accelerated emulators within a docker container, **KVM** must be supported by the host VM which isn't the case for cloud-based CI providers due to infrastructural limits. If you want to learn more about this, here's an article I wrote: [Running Android Instrumented Tests on CI](https://dev.to/ychescale9/running-android-emulators-on-ci-from-bitrise-io-to-github-actions-3j76).
|
||||
The 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.
|
||||
|
||||
The **macOS** VM provided by **GitHub Actions** has **HAXM** installed so we are able to create a new AVD instance, launch an emulator with hardware acceleration, and run our Android
|
||||
tests directly on the VM. You can also achieve this on a self-hosted Linux runner, but it will need to be on a compatible instance that allows you to enable KVM - for example AWS EC2 Bare Metal instances.
|
||||
This 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).
|
||||
|
||||
This action automates the process by doing the following:
|
||||
## Running hardware accelerated emulators on Linux runners
|
||||
|
||||
GitHub'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:
|
||||
|
||||
```
|
||||
- name: Enable KVM group perms
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
```
|
||||
|
||||
## A note on VM Acceleration and why we don't need HAXM anymore
|
||||
|
||||
According 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.**
|
||||
|
||||
**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.
|
||||
|
||||
## Purpose
|
||||
|
||||
This action helps automate and configure the process of setting up an emulator and running your tests by doing the following:
|
||||
|
||||
- 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).
|
||||
- Create a new instance of **AVD** with the provided [configurations](#configurations).
|
||||
@@ -20,20 +39,24 @@ This action automates the process by doing the following:
|
||||
- Run a custom script provided by user once the Emulator is up and running - e.g. `./gradlew connectedCheck`.
|
||||
- Kill the Emulator and finish the action.
|
||||
|
||||
## Usage
|
||||
|
||||
It is recommended to run this action on a **macOS** VM, e.g. `macos-latest`, `macos-10.15` or `macos-11` to take advantage of hardware acceleration support provided by **HAXM**.
|
||||
## Usage & Examples
|
||||
|
||||
A workflow that uses **android-emulator-runner** to run your instrumented tests on **API 29**:
|
||||
|
||||
```yml
|
||||
jobs:
|
||||
test:
|
||||
runs-on: macos-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Enable KVM
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: run tests
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
@@ -46,7 +69,7 @@ We can also leverage GitHub Actions's build matrix to test across multiple confi
|
||||
```yml
|
||||
jobs:
|
||||
test:
|
||||
runs-on: macos-latest
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
api-level: [21, 23, 29]
|
||||
@@ -55,6 +78,12 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Enable KVM
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: run tests
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
@@ -70,11 +99,17 @@ If you need specific versions of **NDK** and **CMake** installed:
|
||||
```yml
|
||||
jobs:
|
||||
test:
|
||||
runs-on: macos-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Enable KVM
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: run tests
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
@@ -94,7 +129,7 @@ We can significantly reduce emulator startup time by setting up AVD snapshot cac
|
||||
```yml
|
||||
jobs:
|
||||
test:
|
||||
runs-on: macos-latest
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
api-level: [21, 23, 29]
|
||||
@@ -102,6 +137,12 @@ jobs:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Enable KVM
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Gradle cache
|
||||
uses: gradle/gradle-build-action@v2
|
||||
|
||||
@@ -146,30 +187,25 @@ jobs:
|
||||
| `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` |
|
||||
| `heap-size` | Optional | N/A | Heap size to use for this AVD, in KB or MB, denoted with K or M. - e.g. `512M` |
|
||||
| `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`. |
|
||||
| `disk-size` | Optional | N/A | Disk size to use for this AVD. Either in bytes or KB, MB or GB, when denoted with K, M or G. - e.g. `2048M` |
|
||||
| `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` |
|
||||
| `avd-name` | Optional | `test` | Custom AVD name used for creating the Android Virtual Device. |
|
||||
| `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`. |
|
||||
| `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. |
|
||||
| `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`. |
|
||||
| `disable-animations` | Optional | `true` | Whether to disable animations - `true` or `false`. |
|
||||
| `disable-spellchecker` | Optional | `false` | Whether to disable spellchecker - `true` or `false`. |
|
||||
| `disable-linux-hw-accel` | Optional | `auto` | Whether to disable hardware acceleration on Linux machines - `true`, `false` or `auto`.|
|
||||
| `enable-hw-keyboard` | Optional | `false` | Whether to enable hardware keyboard - `true` or `false`. |
|
||||
| `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. |
|
||||
| `working-directory` | Optional | `./` | A custom working directory - e.g. `./android` if your root Gradle project is under the `./android` sub-directory within your repository. |
|
||||
| `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` & `pre-emulator-launch-script`. |
|
||||
| `ndk` | Optional | N/A | Version of NDK to install - e.g. `21.0.6113669` |
|
||||
| `cmake` | Optional | N/A | Version of CMake to install - e.g. `3.10.2.4988404` |
|
||||
| `channel` | Optional | stable | Channel to download the SDK components from - `stable`, `beta`, `dev`, `canary` |
|
||||
| `script` | Required | N/A | Custom script to run - e.g. to run Android instrumented tests on the emulator: `./gradlew connectedCheck` |
|
||||
| `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` |
|
||||
|
||||
Default `emulator-options`: `-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim`.
|
||||
|
||||
## Can I use this action on Linux VMs?
|
||||
|
||||
The short answer is yes but on Github-hosted Linux runners it's expected to be a much worse experience (on some newer API levels it might not work at all) than running it on macOS. You can get it running much faster on self-hosted Linux runners but only if the underlying instances support KVM (which most don't).
|
||||
|
||||
For a longer answer please refer to [this issue](https://github.com/ReactiveCircus/android-emulator-runner/issues/46).
|
||||
|
||||
|
||||
## Who is using Android Emulator Runner?
|
||||
|
||||
These are some of the open-source projects using (or used) **Android Emulator Runner**:
|
||||
@@ -203,5 +239,8 @@ These are some of the open-source projects using (or used) **Android Emulator Ru
|
||||
- [dotanuki-labs/norris](https://github.com/dotanuki-labs/norris/blob/master/.github/workflows/main.yml)
|
||||
- [tinylog-org/tinylog](https://github.com/tinylog-org/tinylog/blob/v3.0/.github/workflows/build.yaml)
|
||||
- [hzi-braunschweig/SORMAS-Project](https://github.com/hzi-braunschweig/SORMAS-Project/blob/development/.github/workflows/sormas_app_ci.yml)
|
||||
- [ACRA/acra](https://github.com/ACRA/acra/blob/master/.github/workflows/test.yml)
|
||||
- [bitfireAT/davx5-ose](https://github.com/bitfireAT/davx5-ose/blob/dev-ose/.github/workflows/test-dev.yml)
|
||||
- [robolectric/robolectric](https://github.com/robolectric/robolectric/blob/master/.github/workflows/tests.yml)
|
||||
|
||||
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to create an issue or open a pull request.
|
||||
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.
|
||||
|
||||
@@ -32,6 +32,14 @@ describe('api-level validator tests', () => {
|
||||
validator.checkApiLevel('29');
|
||||
};
|
||||
expect(func2).not.toThrow();
|
||||
const func3 = () => {
|
||||
validator.checkApiLevel('UpsideDownCake-ext5');
|
||||
};
|
||||
expect(func3).not.toThrow();
|
||||
const func4 = () => {
|
||||
validator.checkApiLevel('TiramisuPrivacySandbox');
|
||||
};
|
||||
expect(func4).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ inputs:
|
||||
type: string
|
||||
force-avd-creation:
|
||||
type: boolean
|
||||
emulator-boot-timeout:
|
||||
type: integer
|
||||
emulator-options:
|
||||
type: string
|
||||
disable-animations:
|
||||
@@ -62,3 +64,5 @@ inputs:
|
||||
- canary
|
||||
script:
|
||||
type: string
|
||||
pre-emulator-launch-script:
|
||||
type: string
|
||||
|
||||
+8
-3
@@ -1,5 +1,5 @@
|
||||
name: 'Android Emulator Runner'
|
||||
description: 'Installs, configures and starts an Android Emulator directly on macOS virtual machines.'
|
||||
description: 'Installs, configures and starts an Android Emulator directly on hardware-accelerated runners.'
|
||||
author: 'Reactive Circus'
|
||||
branding:
|
||||
icon: 'smartphone'
|
||||
@@ -33,6 +33,9 @@ inputs:
|
||||
force-avd-creation:
|
||||
description: 'whether to force create the AVD by overwriting an existing AVD with the same name as `avd-name` - `true` or `false`'
|
||||
default: 'true'
|
||||
emulator-boot-timeout:
|
||||
description: 'Emulator boot timeout in seconds. If it takes longer to boot, the action would fail - e.g. `300` for 5 minutes'
|
||||
default: '600'
|
||||
emulator-options:
|
||||
description: 'command-line options used when launching the emulator - e.g. `-no-window -no-snapshot -camera-back emulated`'
|
||||
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
|
||||
@@ -40,7 +43,7 @@ inputs:
|
||||
description: 'whether to disable animations - true or false'
|
||||
default: 'true'
|
||||
disable-spellchecker:
|
||||
description: 'whether to disable spellchecker - `true` or `false`'
|
||||
description: 'whether to disable the Android spell checker framework, a common source of flakiness in text fields - `true` or `false`'
|
||||
default: 'false'
|
||||
disable-linux-hw-accel:
|
||||
description: 'whether to disable hardware acceleration on Linux machines - `true` or `false` or `auto`'
|
||||
@@ -62,6 +65,8 @@ inputs:
|
||||
script:
|
||||
description: 'custom script to run - e.g. `./gradlew connectedCheck`'
|
||||
required: true
|
||||
pre-emulator-launch-script:
|
||||
description: 'custom script to run after creating the AVD and before launching the emulator - e.g. `./adjust-emulator-configs.sh`'
|
||||
runs:
|
||||
using: 'node12'
|
||||
using: 'node20'
|
||||
main: 'lib/main.js'
|
||||
|
||||
+19
-16
@@ -1,7 +1,11 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
@@ -14,7 +18,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
@@ -31,11 +35,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.killEmulator = exports.launchEmulator = void 0;
|
||||
const exec = __importStar(require("@actions/exec"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
||||
/**
|
||||
* Creates and launches a new AVD instance with the specified configurations.
|
||||
*/
|
||||
function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
|
||||
function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
try {
|
||||
console.log(`::group::Launch Emulator`);
|
||||
@@ -62,24 +65,24 @@ function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSiz
|
||||
if (diskSize) {
|
||||
yield exec.exec(`sh -c \\"printf 'disk.dataPartition.size=${diskSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
||||
}
|
||||
//turn off hardware acceleration on Linux
|
||||
// turn off hardware acceleration on Linux
|
||||
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
||||
console.log('Disabling Linux hardware acceleration.');
|
||||
emulatorOptions += ' -accel off';
|
||||
}
|
||||
// start emulator
|
||||
console.log('Starting emulator.');
|
||||
yield exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
yield exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
listeners: {
|
||||
stderr: (data) => {
|
||||
if (data.toString().includes('invalid command-line parameter')) {
|
||||
throw new Error(data.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
// wait for emulator to complete booting
|
||||
yield waitForDevice();
|
||||
yield waitForDevice(emulatorBootTimeout);
|
||||
yield exec.exec(`adb shell input keyevent 82`);
|
||||
if (disableAnimations) {
|
||||
console.log('Disabling animations.');
|
||||
@@ -110,7 +113,7 @@ function killEmulator() {
|
||||
yield exec.exec(`adb -s emulator-5554 emu kill`);
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error.message);
|
||||
console.log(error instanceof Error ? error.message : error);
|
||||
}
|
||||
finally {
|
||||
console.log(`::endgroup::`);
|
||||
@@ -121,12 +124,12 @@ exports.killEmulator = killEmulator;
|
||||
/**
|
||||
* Wait for emulator to boot.
|
||||
*/
|
||||
function waitForDevice() {
|
||||
function waitForDevice(emulatorBootTimeout) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let booted = false;
|
||||
let attempts = 0;
|
||||
const retryInterval = 2; // retry every 2 seconds
|
||||
const maxAttempts = EMULATOR_BOOT_TIMEOUT_SECONDS / 2;
|
||||
const maxAttempts = emulatorBootTimeout / 2;
|
||||
while (!booted) {
|
||||
try {
|
||||
let result = '';
|
||||
@@ -134,8 +137,8 @@ function waitForDevice() {
|
||||
listeners: {
|
||||
stdout: (data) => {
|
||||
result += data.toString();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
if (result.trim() === '1') {
|
||||
console.log('Emulator booted.');
|
||||
@@ -144,7 +147,7 @@ function waitForDevice() {
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.warn(error.message);
|
||||
console.warn(error instanceof Error ? error.message : error);
|
||||
}
|
||||
if (attempts < maxAttempts) {
|
||||
yield delay(retryInterval * 1000);
|
||||
@@ -157,5 +160,5 @@ function waitForDevice() {
|
||||
});
|
||||
}
|
||||
function delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ exports.VALID_TARGETS = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'go
|
||||
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
|
||||
exports.VALID_CHANNELS = ['stable', 'beta', 'dev', 'canary'];
|
||||
function checkApiLevel(apiLevel) {
|
||||
if (apiLevel.startsWith('UpsideDownCake') || apiLevel === 'TiramisuPrivacySandbox')
|
||||
return;
|
||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
||||
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
||||
}
|
||||
|
||||
+54
-24
@@ -1,7 +1,11 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
@@ -14,7 +18,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
@@ -45,7 +49,7 @@ function run() {
|
||||
if (process.platform !== 'darwin') {
|
||||
if (process.platform === 'linux') {
|
||||
try {
|
||||
fs_1.accessSync('/dev/kvm', fs_1.constants.R_OK | fs_1.constants.W_OK);
|
||||
(0, fs_1.accessSync)('/dev/kvm', fs_1.constants.R_OK | fs_1.constants.W_OK);
|
||||
linuxSupportKVM = true;
|
||||
}
|
||||
catch (_a) {
|
||||
@@ -57,18 +61,17 @@ function run() {
|
||||
}
|
||||
}
|
||||
// API level of the platform and system image
|
||||
const apiLevelInput = core.getInput('api-level', { required: true });
|
||||
input_validator_1.checkApiLevel(apiLevelInput);
|
||||
const apiLevel = Number(apiLevelInput);
|
||||
const apiLevel = core.getInput('api-level', { required: true });
|
||||
(0, input_validator_1.checkApiLevel)(apiLevel);
|
||||
console.log(`API level: ${apiLevel}`);
|
||||
// target of the system image
|
||||
const targetInput = core.getInput('target');
|
||||
const target = targetInput == 'playstore' ? 'google_apis_playstore' : targetInput;
|
||||
input_validator_1.checkTarget(target);
|
||||
(0, input_validator_1.checkTarget)(target);
|
||||
console.log(`target: ${target}`);
|
||||
// CPU architecture of the system image
|
||||
const arch = core.getInput('arch');
|
||||
input_validator_1.checkArch(arch);
|
||||
(0, input_validator_1.checkArch)(arch);
|
||||
console.log(`CPU architecture: ${arch}`);
|
||||
// Hardware profile used for creating the AVD
|
||||
const profile = core.getInput('profile');
|
||||
@@ -86,32 +89,35 @@ function run() {
|
||||
const sdcardPathOrSize = core.getInput('sdcard-path-or-size');
|
||||
console.log(`SD card path or size: ${sdcardPathOrSize}`);
|
||||
const diskSize = core.getInput('disk-size');
|
||||
input_validator_1.checkDiskSize(diskSize);
|
||||
(0, input_validator_1.checkDiskSize)(diskSize);
|
||||
console.log(`Disk size: ${diskSize}`);
|
||||
// custom name used for creating the AVD
|
||||
const avdName = core.getInput('avd-name');
|
||||
console.log(`AVD name: ${avdName}`);
|
||||
// force AVD creation
|
||||
const forceAvdCreationInput = core.getInput('force-avd-creation');
|
||||
input_validator_1.checkForceAvdCreation(forceAvdCreationInput);
|
||||
(0, input_validator_1.checkForceAvdCreation)(forceAvdCreationInput);
|
||||
const forceAvdCreation = forceAvdCreationInput === 'true';
|
||||
console.log(`force avd creation: ${forceAvdCreation}`);
|
||||
// Emulator boot timeout seconds
|
||||
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
||||
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
||||
// emulator options
|
||||
const emulatorOptions = core.getInput('emulator-options').trim();
|
||||
console.log(`emulator options: ${emulatorOptions}`);
|
||||
// disable animations
|
||||
const disableAnimationsInput = core.getInput('disable-animations');
|
||||
input_validator_1.checkDisableAnimations(disableAnimationsInput);
|
||||
(0, input_validator_1.checkDisableAnimations)(disableAnimationsInput);
|
||||
const disableAnimations = disableAnimationsInput === 'true';
|
||||
console.log(`disable animations: ${disableAnimations}`);
|
||||
// disable spellchecker
|
||||
const disableSpellcheckerInput = core.getInput('disable-spellchecker');
|
||||
input_validator_1.checkDisableSpellchecker(disableSpellcheckerInput);
|
||||
(0, input_validator_1.checkDisableSpellchecker)(disableSpellcheckerInput);
|
||||
const disableSpellchecker = disableSpellcheckerInput === 'true';
|
||||
console.log(`disable spellchecker: ${disableSpellchecker}`);
|
||||
// disable linux hardware acceleration
|
||||
let disableLinuxHardwareAccelerationInput = core.getInput('disable-linux-hw-accel');
|
||||
input_validator_1.checkDisableLinuxHardwareAcceleration(disableLinuxHardwareAccelerationInput);
|
||||
(0, input_validator_1.checkDisableLinuxHardwareAcceleration)(disableLinuxHardwareAccelerationInput);
|
||||
if (disableLinuxHardwareAccelerationInput === 'auto' && process.platform === 'linux') {
|
||||
disableLinuxHardwareAccelerationInput = linuxSupportKVM ? 'false' : 'true';
|
||||
}
|
||||
@@ -119,13 +125,13 @@ function run() {
|
||||
console.log(`disable Linux hardware acceleration: ${disableLinuxHardwareAcceleration}`);
|
||||
// enable hardware keyboard
|
||||
const enableHardwareKeyboardInput = core.getInput('enable-hw-keyboard');
|
||||
input_validator_1.checkEnableHardwareKeyboard(enableHardwareKeyboardInput);
|
||||
(0, input_validator_1.checkEnableHardwareKeyboard)(enableHardwareKeyboardInput);
|
||||
const enableHardwareKeyboard = enableHardwareKeyboardInput === 'true';
|
||||
console.log(`enable hardware keyboard: ${enableHardwareKeyboard}`);
|
||||
// emulator build
|
||||
const emulatorBuildInput = core.getInput('emulator-build');
|
||||
if (emulatorBuildInput) {
|
||||
input_validator_1.checkEmulatorBuild(emulatorBuildInput);
|
||||
(0, input_validator_1.checkEmulatorBuild)(emulatorBuildInput);
|
||||
console.log(`using emulator build: ${emulatorBuildInput}`);
|
||||
}
|
||||
const emulatorBuild = !emulatorBuildInput ? undefined : emulatorBuildInput;
|
||||
@@ -149,21 +155,45 @@ function run() {
|
||||
const cmakeVersion = !cmakeInput ? undefined : cmakeInput;
|
||||
// channelId (up to and including) to download the SDK packages from
|
||||
const channelName = core.getInput('channel');
|
||||
input_validator_1.checkChannel(channelName);
|
||||
const channelId = channel_id_mapper_1.getChannelId(channelName);
|
||||
(0, input_validator_1.checkChannel)(channelName);
|
||||
const channelId = (0, channel_id_mapper_1.getChannelId)(channelName);
|
||||
console.log(`Channel: ${channelId} (${channelName})`);
|
||||
// custom script to run
|
||||
const scriptInput = core.getInput('script', { required: true });
|
||||
const scripts = script_parser_1.parseScript(scriptInput);
|
||||
const scripts = (0, script_parser_1.parseScript)(scriptInput);
|
||||
console.log(`Script:`);
|
||||
scripts.forEach((script) => __awaiter(this, void 0, void 0, function* () {
|
||||
console.log(`${script}`);
|
||||
}));
|
||||
// custom pre emulator launch script
|
||||
const preEmulatorLaunchScriptInput = core.getInput('pre-emulator-launch-script');
|
||||
const preEmulatorLaunchScripts = !preEmulatorLaunchScriptInput ? undefined : (0, script_parser_1.parseScript)(preEmulatorLaunchScriptInput);
|
||||
console.log(`Pre emulator launch script:`);
|
||||
preEmulatorLaunchScripts === null || preEmulatorLaunchScripts === void 0 ? void 0 : preEmulatorLaunchScripts.forEach((script) => __awaiter(this, void 0, void 0, function* () {
|
||||
console.log(`${script}`);
|
||||
}));
|
||||
console.log(`::endgroup::`);
|
||||
// install SDK
|
||||
yield sdk_installer_1.installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
|
||||
yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
|
||||
// execute pre emulator launch script if set
|
||||
if (preEmulatorLaunchScripts !== undefined) {
|
||||
console.log(`::group::Run pre emulator launch script`);
|
||||
try {
|
||||
for (const preEmulatorLaunchScript of preEmulatorLaunchScripts) {
|
||||
// use array form to avoid various quote escaping problems
|
||||
// caused by exec(`sh -c "${preEmulatorLaunchScript}"`)
|
||||
yield exec.exec('sh', ['-c', preEmulatorLaunchScript], {
|
||||
cwd: workingDirectory,
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(error instanceof Error ? error.message : error);
|
||||
}
|
||||
console.log(`::endgroup::`);
|
||||
}
|
||||
// launch an emulator
|
||||
yield emulator_manager_1.launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
|
||||
yield (0, emulator_manager_1.launchEmulator)(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
|
||||
// execute the custom script
|
||||
try {
|
||||
// move to custom working directory if set
|
||||
@@ -177,15 +207,15 @@ function run() {
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
core.setFailed(error.message);
|
||||
core.setFailed(error instanceof Error ? error.message : error);
|
||||
}
|
||||
// finally kill the emulator
|
||||
yield emulator_manager_1.killEmulator();
|
||||
yield (0, emulator_manager_1.killEmulator)();
|
||||
}
|
||||
catch (error) {
|
||||
// kill the emulator so the action can exit
|
||||
yield emulator_manager_1.killEmulator();
|
||||
core.setFailed(error.message);
|
||||
yield (0, emulator_manager_1.killEmulator)();
|
||||
core.setFailed(error instanceof Error ? error.message : error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+32
-11
@@ -1,7 +1,11 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
@@ -14,7 +18,7 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
@@ -34,9 +38,10 @@ const exec = __importStar(require("@actions/exec"));
|
||||
const io = __importStar(require("@actions/io"));
|
||||
const tc = __importStar(require("@actions/tool-cache"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const BUILD_TOOLS_VERSION = '33.0.0';
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-8512546_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-8512546_latest.zip';
|
||||
const BUILD_TOOLS_VERSION = '34.0.0';
|
||||
// SDK command-line tools 11.0
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-10406996_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip';
|
||||
/**
|
||||
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
||||
* and the system image for the chosen API level, CPU arch, and target.
|
||||
@@ -46,10 +51,11 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
|
||||
try {
|
||||
console.log(`::group::Install Android SDK`);
|
||||
const isOnMac = process.platform === 'darwin';
|
||||
const isArm = process.arch === 'arm64';
|
||||
if (!isOnMac) {
|
||||
yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`);
|
||||
yield exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
||||
}
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`;
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||
console.log('Installing new cmdline-tools.');
|
||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||
@@ -58,21 +64,36 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
|
||||
yield io.mv(`${cmdlineToolsPath}/cmdline-tools`, `${cmdlineToolsPath}/latest`);
|
||||
}
|
||||
// add paths for commandline-tools and platform-tools
|
||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||
// set standard AVD path
|
||||
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
||||
// accept all Android SDK licenses
|
||||
yield exec.exec(`sh -c \\"yes | sdkmanager --licenses > /dev/null"`);
|
||||
console.log('Installing latest build tools, platform tools, and platform.');
|
||||
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`);
|
||||
yield exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools > /dev/null"`);
|
||||
console.log('Installing latest emulator.');
|
||||
yield exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
||||
if (emulatorBuild) {
|
||||
console.log(`Installing emulator build ${emulatorBuild}.`);
|
||||
// TODO find out the correct download URLs for all build ids
|
||||
const downloadUrlSuffix = Number(emulatorBuild.charAt(0)) > 6 ? `_x64-${emulatorBuild}` : `-${emulatorBuild}`;
|
||||
var downloadUrlSuffix;
|
||||
const majorBuildVersion = Number(emulatorBuild);
|
||||
if (majorBuildVersion >= 8000000) {
|
||||
if (isArm) {
|
||||
downloadUrlSuffix = `_aarch64-${emulatorBuild}`;
|
||||
}
|
||||
else {
|
||||
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||
}
|
||||
}
|
||||
else if (majorBuildVersion >= 7000000) {
|
||||
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||
}
|
||||
else {
|
||||
downloadUrlSuffix = `-${emulatorBuild}`;
|
||||
}
|
||||
yield exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
||||
yield exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
||||
yield exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
||||
yield io.rmRF('emulator.zip');
|
||||
}
|
||||
console.log('Installing system images.');
|
||||
|
||||
Generated
+4852
-13323
File diff suppressed because it is too large
Load Diff
+21
-18
@@ -2,7 +2,7 @@
|
||||
"name": "android-emulator-runner",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "A GitHub Action for installing, configuring and running Android Emulators on macOS virtual machines.",
|
||||
"description": "A GitHub Action for installing, configuring and running Android Emulators on hardware-accelerated runners.",
|
||||
"main": "lib/main.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
@@ -18,28 +18,31 @@
|
||||
"node",
|
||||
"setup"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"author": "Reactive Circus",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.9.1",
|
||||
"@actions/exec": "^1.1.0",
|
||||
"@actions/tool-cache": "^1.7.1",
|
||||
"minimist": "^1.2.6",
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/tool-cache": "^2.0.1",
|
||||
"minimist": "^1.2.7",
|
||||
"set-value": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.0.3",
|
||||
"@types/node": "^12.20.34",
|
||||
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
||||
"@typescript-eslint/parser": "^5.4.0",
|
||||
"eslint": "^8.3.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-plugin-import": "^2.25.2",
|
||||
"eslint-plugin-prettier": "^3.4.1",
|
||||
"jest": "^26.6.3",
|
||||
"jest-circus": "^27.3.1",
|
||||
"prettier": "^1.19.1",
|
||||
"ts-jest": "^26.5.6",
|
||||
"typescript": "^3.9.10"
|
||||
"@types/jest": "^29.2.0",
|
||||
"@types/node": "^20.11.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
||||
"@typescript-eslint/parser": "^5.41.0",
|
||||
"eslint": "^8.26.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"jest": "^29.2.2",
|
||||
"jest-circus": "^29.2.2",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
||||
+14
-15
@@ -1,13 +1,11 @@
|
||||
import * as exec from '@actions/exec';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const EMULATOR_BOOT_TIMEOUT_SECONDS = 600;
|
||||
|
||||
/**
|
||||
* Creates and launches a new AVD instance with the specified configurations.
|
||||
*/
|
||||
export async function launchEmulator(
|
||||
apiLevel: number,
|
||||
apiLevel: string,
|
||||
target: string,
|
||||
arch: string,
|
||||
profile: string,
|
||||
@@ -18,6 +16,7 @@ export async function launchEmulator(
|
||||
diskSize: string,
|
||||
avdName: string,
|
||||
forceAvdCreation: boolean,
|
||||
emulatorBootTimeout: number,
|
||||
emulatorOptions: string,
|
||||
disableAnimations: boolean,
|
||||
disableSpellChecker: boolean,
|
||||
@@ -57,7 +56,7 @@ export async function launchEmulator(
|
||||
await exec.exec(`sh -c \\"printf 'disk.dataPartition.size=${diskSize}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
|
||||
}
|
||||
|
||||
//turn off hardware acceleration on Linux
|
||||
// turn off hardware acceleration on Linux
|
||||
if (process.platform === 'linux' && disableLinuxHardwareAcceleration) {
|
||||
console.log('Disabling Linux hardware acceleration.');
|
||||
emulatorOptions += ' -accel off';
|
||||
@@ -66,18 +65,18 @@ export async function launchEmulator(
|
||||
// start emulator
|
||||
console.log('Starting emulator.');
|
||||
|
||||
await exec.exec(`sh -c \\"${process.env.ANDROID_SDK_ROOT}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
await exec.exec(`sh -c \\"${process.env.ANDROID_HOME}/emulator/emulator -avd "${avdName}" ${emulatorOptions} &"`, [], {
|
||||
listeners: {
|
||||
stderr: (data: Buffer) => {
|
||||
if (data.toString().includes('invalid command-line parameter')) {
|
||||
throw new Error(data.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// wait for emulator to complete booting
|
||||
await waitForDevice();
|
||||
await waitForDevice(emulatorBootTimeout);
|
||||
await exec.exec(`adb shell input keyevent 82`);
|
||||
|
||||
if (disableAnimations) {
|
||||
@@ -105,7 +104,7 @@ export async function killEmulator(): Promise<void> {
|
||||
console.log(`::group::Terminate Emulator`);
|
||||
await exec.exec(`adb -s emulator-5554 emu kill`);
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
console.log(error instanceof Error ? error.message : error);
|
||||
} finally {
|
||||
console.log(`::endgroup::`);
|
||||
}
|
||||
@@ -114,11 +113,11 @@ export async function killEmulator(): Promise<void> {
|
||||
/**
|
||||
* Wait for emulator to boot.
|
||||
*/
|
||||
async function waitForDevice(): Promise<void> {
|
||||
async function waitForDevice(emulatorBootTimeout: number): Promise<void> {
|
||||
let booted = false;
|
||||
let attempts = 0;
|
||||
const retryInterval = 2; // retry every 2 seconds
|
||||
const maxAttempts = EMULATOR_BOOT_TIMEOUT_SECONDS / 2;
|
||||
const maxAttempts = emulatorBootTimeout / 2;
|
||||
while (!booted) {
|
||||
try {
|
||||
let result = '';
|
||||
@@ -126,8 +125,8 @@ async function waitForDevice(): Promise<void> {
|
||||
listeners: {
|
||||
stdout: (data: Buffer) => {
|
||||
result += data.toString();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
if (result.trim() === '1') {
|
||||
console.log('Emulator booted.');
|
||||
@@ -135,7 +134,7 @@ async function waitForDevice(): Promise<void> {
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(error.message);
|
||||
console.warn(error instanceof Error ? error.message : error);
|
||||
}
|
||||
|
||||
if (attempts < maxAttempts) {
|
||||
@@ -148,5 +147,5 @@ async function waitForDevice(): Promise<void> {
|
||||
}
|
||||
|
||||
function delay(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ export const VALID_ARCHS: Array<string> = ['x86', 'x86_64', 'arm64-v8a'];
|
||||
export const VALID_CHANNELS: Array<string> = ['stable', 'beta', 'dev', 'canary'];
|
||||
|
||||
export function checkApiLevel(apiLevel: string): void {
|
||||
if (apiLevel.startsWith('UpsideDownCake') || apiLevel === 'TiramisuPrivacySandbox') return;
|
||||
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
|
||||
throw new Error(`Unexpected API level: '${apiLevel}'.`);
|
||||
}
|
||||
|
||||
+35
-6
@@ -11,7 +11,7 @@ import {
|
||||
checkForceAvdCreation,
|
||||
checkChannel,
|
||||
checkEnableHardwareKeyboard,
|
||||
checkDiskSize
|
||||
checkDiskSize,
|
||||
} from './input-validator';
|
||||
import { launchEmulator, killEmulator } from './emulator-manager';
|
||||
import * as exec from '@actions/exec';
|
||||
@@ -40,9 +40,8 @@ async function run() {
|
||||
}
|
||||
|
||||
// API level of the platform and system image
|
||||
const apiLevelInput = core.getInput('api-level', { required: true });
|
||||
checkApiLevel(apiLevelInput);
|
||||
const apiLevel = Number(apiLevelInput);
|
||||
const apiLevel = core.getInput('api-level', { required: true });
|
||||
checkApiLevel(apiLevel);
|
||||
console.log(`API level: ${apiLevel}`);
|
||||
|
||||
// target of the system image
|
||||
@@ -90,6 +89,10 @@ async function run() {
|
||||
const forceAvdCreation = forceAvdCreationInput === 'true';
|
||||
console.log(`force avd creation: ${forceAvdCreation}`);
|
||||
|
||||
// Emulator boot timeout seconds
|
||||
const emulatorBootTimeout = parseInt(core.getInput('emulator-boot-timeout'), 10);
|
||||
console.log(`Emulator boot timeout: ${emulatorBootTimeout}`);
|
||||
|
||||
// emulator options
|
||||
const emulatorOptions = core.getInput('emulator-options').trim();
|
||||
console.log(`emulator options: ${emulatorOptions}`);
|
||||
@@ -163,11 +166,36 @@ async function run() {
|
||||
scripts.forEach(async (script: string) => {
|
||||
console.log(`${script}`);
|
||||
});
|
||||
|
||||
// custom pre emulator launch script
|
||||
const preEmulatorLaunchScriptInput = core.getInput('pre-emulator-launch-script');
|
||||
const preEmulatorLaunchScripts = !preEmulatorLaunchScriptInput ? undefined : parseScript(preEmulatorLaunchScriptInput);
|
||||
console.log(`Pre emulator launch script:`);
|
||||
preEmulatorLaunchScripts?.forEach(async (script: string) => {
|
||||
console.log(`${script}`);
|
||||
});
|
||||
console.log(`::endgroup::`);
|
||||
|
||||
// install SDK
|
||||
await installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
|
||||
|
||||
// execute pre emulator launch script if set
|
||||
if (preEmulatorLaunchScripts !== undefined) {
|
||||
console.log(`::group::Run pre emulator launch script`);
|
||||
try {
|
||||
for (const preEmulatorLaunchScript of preEmulatorLaunchScripts) {
|
||||
// use array form to avoid various quote escaping problems
|
||||
// caused by exec(`sh -c "${preEmulatorLaunchScript}"`)
|
||||
await exec.exec('sh', ['-c', preEmulatorLaunchScript], {
|
||||
cwd: workingDirectory,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error instanceof Error ? error.message : (error as string));
|
||||
}
|
||||
console.log(`::endgroup::`);
|
||||
}
|
||||
|
||||
// launch an emulator
|
||||
await launchEmulator(
|
||||
apiLevel,
|
||||
@@ -181,6 +209,7 @@ async function run() {
|
||||
diskSize,
|
||||
avdName,
|
||||
forceAvdCreation,
|
||||
emulatorBootTimeout,
|
||||
emulatorOptions,
|
||||
disableAnimations,
|
||||
disableSpellchecker,
|
||||
@@ -200,7 +229,7 @@ async function run() {
|
||||
await exec.exec('sh', ['-c', script]);
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
core.setFailed(error instanceof Error ? error.message : (error as string));
|
||||
}
|
||||
|
||||
// finally kill the emulator
|
||||
@@ -208,7 +237,7 @@ async function run() {
|
||||
} catch (error) {
|
||||
// kill the emulator so the action can exit
|
||||
await killEmulator();
|
||||
core.setFailed(error.message);
|
||||
core.setFailed(error instanceof Error ? error.message : (error as string));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+24
-10
@@ -4,24 +4,26 @@ import * as io from '@actions/io';
|
||||
import * as tc from '@actions/tool-cache';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const BUILD_TOOLS_VERSION = '33.0.0';
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-8512546_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-8512546_latest.zip';
|
||||
const BUILD_TOOLS_VERSION = '34.0.0';
|
||||
// SDK command-line tools 11.0
|
||||
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-10406996_latest.zip';
|
||||
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip';
|
||||
|
||||
/**
|
||||
* Installs & updates the Android SDK for the macOS platform, including SDK platform for the chosen API level, latest build tools, platform tools, Android Emulator,
|
||||
* and the system image for the chosen API level, CPU arch, and target.
|
||||
*/
|
||||
export async function installAndroidSdk(apiLevel: number, target: string, arch: string, channelId: number, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise<void> {
|
||||
export async function installAndroidSdk(apiLevel: string, target: string, arch: string, channelId: number, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise<void> {
|
||||
try {
|
||||
console.log(`::group::Install Android SDK`);
|
||||
const isOnMac = process.platform === 'darwin';
|
||||
const isArm = process.arch === 'arm64';
|
||||
|
||||
if (!isOnMac) {
|
||||
await exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_SDK_ROOT} -R`);
|
||||
await exec.exec(`sh -c \\"sudo chown $USER:$USER ${process.env.ANDROID_HOME} -R`);
|
||||
}
|
||||
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_SDK_ROOT}/cmdline-tools`;
|
||||
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
|
||||
if (!fs.existsSync(cmdlineToolsPath)) {
|
||||
console.log('Installing new cmdline-tools.');
|
||||
const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
|
||||
@@ -31,7 +33,7 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
||||
}
|
||||
|
||||
// add paths for commandline-tools and platform-tools
|
||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_SDK_ROOT}/platform-tools`);
|
||||
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
|
||||
|
||||
// set standard AVD path
|
||||
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
|
||||
@@ -41,7 +43,7 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
||||
|
||||
console.log('Installing latest build tools, platform tools, and platform.');
|
||||
|
||||
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools 'platforms;android-${apiLevel}' > /dev/null"`);
|
||||
await exec.exec(`sh -c \\"sdkmanager --install 'build-tools;${BUILD_TOOLS_VERSION}' platform-tools > /dev/null"`);
|
||||
|
||||
console.log('Installing latest emulator.');
|
||||
await exec.exec(`sh -c \\"sdkmanager --install emulator --channel=${channelId} > /dev/null"`);
|
||||
@@ -49,9 +51,21 @@ export async function installAndroidSdk(apiLevel: number, target: string, arch:
|
||||
if (emulatorBuild) {
|
||||
console.log(`Installing emulator build ${emulatorBuild}.`);
|
||||
// TODO find out the correct download URLs for all build ids
|
||||
const downloadUrlSuffix = Number(emulatorBuild.charAt(0)) > 6 ? `_x64-${emulatorBuild}` : `-${emulatorBuild}`;
|
||||
var downloadUrlSuffix: string;
|
||||
const majorBuildVersion = Number(emulatorBuild);
|
||||
if (majorBuildVersion >= 8000000) {
|
||||
if (isArm) {
|
||||
downloadUrlSuffix = `_aarch64-${emulatorBuild}`;
|
||||
} else {
|
||||
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||
}
|
||||
} else if (majorBuildVersion >= 7000000) {
|
||||
downloadUrlSuffix = `_x64-${emulatorBuild}`;
|
||||
} else {
|
||||
downloadUrlSuffix = `-${emulatorBuild}`;
|
||||
}
|
||||
await exec.exec(`curl -fo emulator.zip https://dl.google.com/android/repository/emulator-${isOnMac ? 'darwin' : 'linux'}${downloadUrlSuffix}.zip`);
|
||||
await exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_SDK_ROOT}`);
|
||||
await exec.exec(`unzip -o -q emulator.zip -d ${process.env.ANDROID_HOME}`);
|
||||
await io.rmRF('emulator.zip');
|
||||
}
|
||||
console.log('Installing system images.');
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.gradle
|
||||
build/
|
||||
target/
|
||||
out/
|
||||
local.properties
|
||||
.idea/
|
||||
*.iml
|
||||
*.DS_Store
|
||||
@@ -2,31 +2,36 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
buildToolsVersion "33.0.0"
|
||||
namespace = "com.example.testapp"
|
||||
|
||||
compileSdkVersion 34
|
||||
buildToolsVersion "34.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.example.testapp"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 33
|
||||
targetSdkVersion 34
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
compilerOptions {
|
||||
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.6.1'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
}
|
||||
|
||||
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.testapp">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.0'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath 'com.android.tools.build:gradle:8.2.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
||||
@@ -2,26 +2,8 @@ org.gradle.parallel=true
|
||||
org.gradle.configureondemand=true
|
||||
org.gradle.caching=true
|
||||
|
||||
# Enable Kotlin incremental compilation
|
||||
kotlin.incremental=true
|
||||
|
||||
# Enable parallel tasks execution for Kotlin Gradle plugin
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
|
||||
# Kotlin code style
|
||||
kotlin.code.style=official
|
||||
|
||||
# Run kapt directly using Gradle workers
|
||||
kapt.use.worker.api=true
|
||||
|
||||
# Enable incremental annotation processor for KAPT
|
||||
kapt.incremental.apt=true
|
||||
|
||||
# Turn off AP discovery in compile path to enable compile avoidance
|
||||
kapt.include.compile.classpath=false
|
||||
|
||||
# Use R8 instead of ProGuard for code shrinking.
|
||||
android.enableR8.fullMode=true
|
||||
|
||||
# Enable AndroidX
|
||||
android.useAndroidX=true
|
||||
|
||||
BIN
Binary file not shown.
+3
-2
@@ -1,6 +1,7 @@
|
||||
#Tue Nov 26 18:34:05 AEDT 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
|
||||
Vendored
+193
-116
@@ -1,78 +1,127 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -81,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
Vendored
+32
-24
@@ -1,4 +1,20 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -9,19 +25,23 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -35,7 +55,7 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
@@ -45,38 +65,26 @@ echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
Reference in New Issue
Block a user