Compare commits

..

13 Commits

Author SHA1 Message Date
Yang 1dcd009011 Merge branch 'main' into release/v2
* main:
  Prepare for release 2.34.0.
  Update README.md and CHANGELOG.md.
  Support API levels for SDK extensions and add missing targets for automotive and desktop. (#428)
  Add `Baklava` support (#424)
2025-03-29 01:51:10 +11:00
Yang 2548f9f3fc Prepare for release 2.34.0. 2025-03-29 01:48:44 +11:00
Yang 595a4563df Update README.md and CHANGELOG.md. 2025-03-29 01:33:05 +11:00
Timothy a173d65200 Support API levels for SDK extensions and add missing targets for automotive and desktop. (#428) 2025-03-29 01:04:02 +11:00
LoveSy 50d5b10c01 Add Baklava support (#424)
* Add `Baklava` support

* Fix typo of `ubuntu-latest` to fix CI
2025-01-24 22:46:33 +11:00
Yang 62dbb605bb Merge branch 'main' into release/v2
* main:
  Prepare for release 2.33.0.
  Fix avd path on ubuntu-24.04 - attempt 2 (#415)
  Revert creating avd directory. (#414)
  Fix SDK path issues with ubuntu-24.04 (#409)
  SDK build tools 35.0.0, command-line tools 16.0. (#408)
  Avoid changing the owner of unnecessary files (#406)
  Update npm packages. (#401)
2024-10-12 17:43:32 +11:00
Yang c77bfe7c0b Prepare for release 2.33.0. 2024-10-12 17:42:24 +11:00
Yang ead704cc5a Fix avd path on ubuntu-24.04 - attempt 2 (#415) 2024-10-12 17:26:36 +11:00
Yang e800ffffe6 Revert creating avd directory. (#414) 2024-10-11 13:55:44 +11:00
Yang 8c07710601 Fix SDK path issues with ubuntu-24.04 (#409) 2024-10-11 11:55:47 +11:00
Yang 3a18f50216 SDK build tools 35.0.0, command-line tools 16.0. (#408) 2024-10-07 00:50:35 +11:00
Justin Brooks 1b985f4c7a Avoid changing the owner of unnecessary files (#406)
* Avoid changing the owner of unnecessary files

Source files shouldn't matter for the purposes of this tool.
% ls -R $ANDROID_HOME/sources/android-34 | wc -l
   17750

* Remove non-existant directory

* Avoid another unnecessary chown

* Push js
2024-10-05 12:53:35 +10:00
Yang a3dcdb348b Update npm packages. (#401) 2024-07-09 16:23:18 +10:00
19 changed files with 199 additions and 166 deletions
+22 -25
View File
@@ -18,42 +18,37 @@ jobs:
timeout-minutes: 15
strategy:
matrix:
os: [ubuntu-latest]
api-level: [23, 29]
target: [default, google_apis]
arch: [x86]
exclude:
- target: google_apis
api-level: 16
- target: google_apis
api-level: 23
- target: google_apis
api-level: 29
include:
- os: ubuntu-latest
- os: ubuntu-22.04
api-level: 23
target: default
arch: x86
- os: ubuntu-24.04
api-level: 24
target: playstore
arch: x86
- os: ubuntu-latest
api-level: 30
target: aosp_atd
arch: x86
- os: macos-latest
- os: macos-13
api-level: 31
target: google_apis
target: default
arch: x86_64
- os: ubuntu-latest
- os: ubuntu-24.04
api-level: 34
target: aosp_atd
arch: x86_64
- os: ubuntu-latest
api-level: 35
target: google_apis
arch: x86_64
- os: ubuntu-latest
api-level: 34-ext10
target: android-automotive
arch: x86_64
system-image-api-level: 34-ext9
steps:
- name: checkout
uses: actions/checkout@v4
- name: validate gradle wrapper
uses: gradle/wrapper-validation-action@v2
- name: build, test and lint
run: |
npm install
@@ -64,7 +59,7 @@ jobs:
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 21
java-version: 23
- uses: actions/cache@v4
id: avd-cache
@@ -73,9 +68,9 @@ jobs:
~/.android/avd/*
~/.android/adb*
~/.android/debug.keystore
key: avd-${{ matrix.api-level }}-${{ matrix.os }}-${{ matrix.target }}
key: avd-${{ matrix.api-level }}-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.arch }}
- uses: gradle/actions/setup-gradle@v3
- uses: gradle/actions/setup-gradle@v4
- name: assemble tests
working-directory: test-fixture
@@ -95,6 +90,7 @@ jobs:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: ${{ matrix.arch }}
system-image-api-level: ${{ matrix.system-image-api-level }}
profile: Galaxy Nexus
cores: 2
sdcard-path-or-size: 100M
@@ -112,6 +108,7 @@ jobs:
api-level: ${{ matrix.api-level }}
target: ${{ matrix.target }}
arch: ${{ matrix.arch }}
system-image-api-level: ${{ matrix.system-image-api-level }}
profile: Galaxy Nexus
cores: 2
ram-size: 2048M
+9 -11
View File
@@ -7,16 +7,18 @@ on:
required: true
default: 'ubuntu-latest'
api-level:
description: 'API level of the platform and system image'
description: 'API level of the platform and system image (if not overridden with system-image-api-level input) - e.g. 33, 35-ext15, Baklava'
required: true
default: '30'
default: '34'
system-image-api-level:
description: 'API level of the system image - e.g. 34-ext10, 35-ext15'
target:
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv or google-tv'
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv, google-tv, android-automotive, android-automotive-playstore or android-desktop'
required: true
default: 'default'
arch:
description: 'CPU architecture of the system image - x86, x86_64 or arm64-v8a'
default: 'x86'
default: 'x86_64'
emulator-options:
description: 'command-line options used when launching the emulator'
default: '-no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim'
@@ -41,9 +43,6 @@ jobs:
- name: checkout
uses: actions/checkout@v4
- name: validate gradle wrapper
uses: gradle/wrapper-validation-action@v2
- name: build, test and lint
run: |
npm install
@@ -54,11 +53,9 @@ jobs:
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 21
java-version: 23
- uses: gradle/actions/setup-gradle@v3
with:
gradle-home-cache-cleanup: true
- uses: gradle/actions/setup-gradle@v4
- name: enable KVM for linux runners
if: runner.os == 'Linux'
@@ -73,6 +70,7 @@ jobs:
api-level: ${{ github.event.inputs.api-level }}
target: ${{ github.event.inputs.target }}
arch: ${{ github.event.inputs.arch }}
system-image-api-level: ${{ github.event.inputs.system-image-api-level }}
profile: Galaxy Nexus
emulator-options: ${{ github.event.inputs.emulator-options }}
emulator-build: ${{ github.event.inputs.emulator-build }}
+17
View File
@@ -1,5 +1,22 @@
# Change Log
## Unreleased
No changes yet.
## v2.34.0
* Allow arbitrary value for `api-level` such as `Baklava` and `35-ext15`. - [428](https://github.com/ReactiveCircus/android-emulator-runner/pull/428)
* Add option to specify `system-image-api-level` to use a system image with a different API level than the platform. - [428](https://github.com/ReactiveCircus/android-emulator-runner/pull/428)
* Support automotive and desktop targets: `android-automotive`, `android-automotive-playstore`, `android-desktop`. - [428](https://github.com/ReactiveCircus/android-emulator-runner/pull/428)
## v2.33.0
* Fix missing AVD directory in `ubuntu-24.04` runner. - [415](https://github.com/ReactiveCircus/android-emulator-runner/pull/415)
* Update SDK build tools to `35.0.0`, update SDK command-line tools to `16.0`. - [#356](https://github.com/ReactiveCircus/android-emulator-runner/pull/356)
* Stop changing owner of the SDK directory. - [406](https://github.com/ReactiveCircus/android-emulator-runner/pull/406) [#409](https://github.com/ReactiveCircus/android-emulator-runner/pull/409)
* Upgrade to latest npm dependencies. - [#401](https://github.com/ReactiveCircus/android-emulator-runner/pull/401)
## v2.32.0
* Add `port` parameter for customizing the emulator port to use. - [#383](https://github.com/ReactiveCircus/android-emulator-runner/pull/383)
+30 -3
View File
@@ -119,9 +119,34 @@ jobs:
script: ./gradlew connectedCheck
```
If you need a specific [SDK Extensions](https://developer.android.com/guide/sdk-extensions) for the system image but not the platform:
```yml
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
- 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:
api-level: 34
system-image-api-level: 34-ext9
target: android-automotive
script: ./gradlew connectedCheck
```
We can significantly reduce emulator startup time by setting up AVD snapshot caching:
1. add a `gradle/actions/setup-gradle@v3` step for caching Gradle, more details see [#229](https://github.com/ReactiveCircus/android-emulator-runner/issues/229)
1. add a `gradle/actions/setup-gradle@v4` step for caching Gradle, more details see [#229](https://github.com/ReactiveCircus/android-emulator-runner/issues/229)
2. add an `actions/cache@v4` step for caching the `avd`
3. add a `reactivecircus/android-emulator-runner@v2` step to generate a clean snapshot - specify `emulator-options` without `no-snapshot`
4. add another `reactivecircus/android-emulator-runner@v2` step to run your tests using existing AVD / snapshot - specify `emulator-options` with `no-snapshot-save`
@@ -179,8 +204,9 @@ jobs:
| **Input** | **Required** | **Default** | **Description** |
|-|-|-|-|
| `api-level` | Required | N/A | API level of the platform system image - e.g. 23 for Android Marshmallow, 29 for Android 10. **Minimum API level supported is 15**. |
| `target` | Optional | `default` | Target of the system image - `default`, `google_apis`, `playstore`, `android-wear`, `android-wear-cn`, `android-tv`, `google-tv`, `aosp_atd` or `google_atd`. Note that `aosp_atd` and `google_atd` currently require the following: `api-level: 30`, `arch: x86` or `arch: arm64-v8` and `channel: canary`. |
| `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**. |
| `system-image-api-level` | Optional | same as `api-level` | API level of the system image - e.g. `34-ext10`, `35-ext15`. |
| `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`. |
| `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). |
| `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`. |
| `cores` | Optional | 2 | Number of cores to use for the emulator (`hw.cpu.ncore` in config.ini). |
@@ -243,5 +269,6 @@ These are some of the open-source projects using (or used) **Android Emulator Ru
- [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)
- [home-assistant/android](https://github.com/home-assistant/android/blob/master/.github/workflows/pr.yml)
If you are using **Android Emulator Runner** and want your project included in the list, please feel free to open a pull request.
+15 -43
View File
@@ -1,49 +1,6 @@
import * as validator from '../src/input-validator';
import { MAX_PORT, MIN_PORT } from '../src/input-validator';
describe('api-level validator tests', () => {
it('Throws if api-level is not a number', () => {
const func = () => {
validator.checkApiLevel('api');
};
expect(func).toThrowError(`Unexpected API level: 'api'.`);
});
it('Throws if api-level is not an integer', () => {
const func = () => {
validator.checkApiLevel('29.1');
};
expect(func).toThrowError(`Unexpected API level: '29.1'.`);
});
it('Throws if api-level is lower than min API supported', () => {
const func = () => {
validator.checkApiLevel('14');
};
expect(func).toThrowError(`Minimum API level supported is ${validator.MIN_API_LEVEL}.`);
});
it('Validates successfully with valid api-level', () => {
const func1 = () => {
validator.checkApiLevel('15');
};
expect(func1).not.toThrow();
const func2 = () => {
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();
});
});
describe('target validator tests', () => {
it('Throws if target is unknown', () => {
const func = () => {
@@ -97,6 +54,21 @@ describe('target validator tests', () => {
validator.checkTarget('google-tv');
};
expect(func9).not.toThrow();
const func10 = () => {
validator.checkTarget('android-automotive');
};
expect(func10).not.toThrow();
const func11 = () => {
validator.checkTarget('android-automotive-playstore');
};
expect(func11).not.toThrow();
const func12 = () => {
validator.checkTarget('android-desktop');
};
expect(func12).not.toThrow();
});
});
+6 -1
View File
@@ -1,6 +1,8 @@
inputs:
api-level:
type: integer
type: string
system-image-api-level:
type: string
target:
type: enum
allowed-values:
@@ -13,6 +15,9 @@ inputs:
- android-wear-cn
- android-tv
- google-tv
- android-automotive
- android-automotive-playstore
- android-desktop
arch:
type: enum
allowed-values:
+5 -2
View File
@@ -6,10 +6,13 @@ branding:
color: 'green'
inputs:
api-level:
description: 'API level of the platform and system image - e.g. 23 for Android Marshmallow, 29 for Android 10'
description: 'API level of the platform and system image - e.g. 23, 33, 35-ext15, Baklava'
required: true
system-image-api-level:
description: 'API level of the system image - e.g. 34-ext10, 35-ext15. If not set the `api-level` input will be used.'
required: false
target:
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv or google-tv'
description: 'target of the system image - default, google_apis, google_apis_playstore, aosp_atd, google_atd, android-wear, android-wear-cn, android-tv, google-tv, android-automotive, android-automotive-playstore or android-desktop'
default: 'default'
arch:
description: 'CPU architecture of the system image - x86, x86_64 or arm64-v8a'
+2 -2
View File
@@ -38,7 +38,7 @@ const fs = __importStar(require("fs"));
/**
* Creates and launches a new AVD instance with the specified configurations.
*/
function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
function launchEmulator(systemImageApiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellChecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard) {
return __awaiter(this, void 0, void 0, function* () {
try {
console.log(`::group::Launch Emulator`);
@@ -48,7 +48,7 @@ function launchEmulator(apiLevel, target, arch, profile, cores, ramSize, heapSiz
const profileOption = profile.trim() !== '' ? `--device '${profile}'` : '';
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
console.log(`Creating AVD.`);
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`);
yield exec.exec(`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${systemImageApiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`);
}
if (cores) {
yield exec.exec(`sh -c \\"printf 'hw.cpu.ncore=${cores}\n' >> ${process.env.ANDROID_AVD_HOME}/"${avdName}".avd"/config.ini`);
+15 -14
View File
@@ -1,24 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkDiskSize = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkPort = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.checkApiLevel = exports.PREVIEW_API_LEVELS = exports.MAX_PORT = exports.MIN_PORT = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
exports.checkDiskSize = exports.checkEmulatorBuild = exports.checkEnableHardwareKeyboard = exports.checkDisableLinuxHardwareAcceleration = exports.checkDisableSpellchecker = exports.checkDisableAnimations = exports.checkPort = exports.checkForceAvdCreation = exports.checkChannel = exports.checkArch = exports.checkTarget = exports.MAX_PORT = exports.MIN_PORT = exports.VALID_CHANNELS = exports.VALID_ARCHS = exports.VALID_TARGETS = exports.MIN_API_LEVEL = void 0;
exports.MIN_API_LEVEL = 15;
exports.VALID_TARGETS = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'google_apis_playstore', 'android-wear', 'android-wear-cn', 'android-tv', 'google-tv'];
exports.VALID_TARGETS = [
'default',
'google_apis',
'aosp_atd',
'google_atd',
'google_apis_playstore',
'android-wear',
'android-wear-cn',
'android-tv',
'google-tv',
'android-automotive',
'android-automotive-playstore',
'android-desktop',
];
exports.VALID_ARCHS = ['x86', 'x86_64', 'arm64-v8a'];
exports.VALID_CHANNELS = ['stable', 'beta', 'dev', 'canary'];
exports.MIN_PORT = 5554;
exports.MAX_PORT = 5584;
exports.PREVIEW_API_LEVELS = ['Tiramisu', 'UpsideDownCake', 'VanillaIceCream'];
function checkApiLevel(apiLevel) {
if (exports.PREVIEW_API_LEVELS.some((previewLevel) => apiLevel.startsWith(previewLevel)))
return;
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
throw new Error(`Unexpected API level: '${apiLevel}'.`);
}
if (Number(apiLevel) < exports.MIN_API_LEVEL) {
throw new Error(`Minimum API level supported is ${exports.MIN_API_LEVEL}.`);
}
}
exports.checkApiLevel = checkApiLevel;
function checkTarget(target) {
if (!exports.VALID_TARGETS.includes(target)) {
throw new Error(`Value for input.target '${target}' is unknown. Supported options: ${exports.VALID_TARGETS}.`);
+7 -3
View File
@@ -63,8 +63,12 @@ function run() {
}
// API level of the platform and system image
const apiLevel = core.getInput('api-level', { required: true });
(0, input_validator_1.checkApiLevel)(apiLevel);
console.log(`API level: ${apiLevel}`);
let systemImageApiLevel = core.getInput('system-image-api-level');
if (!systemImageApiLevel) {
systemImageApiLevel = apiLevel;
}
console.log(`System image API level: ${systemImageApiLevel}`);
// target of the system image
const targetInput = core.getInput('target');
const target = targetInput == 'playstore' ? 'google_apis_playstore' : targetInput;
@@ -179,7 +183,7 @@ function run() {
}));
console.log(`::endgroup::`);
// install SDK
yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
yield (0, sdk_installer_1.installAndroidSdk)(apiLevel, systemImageApiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
// execute pre emulator launch script if set
if (preEmulatorLaunchScripts !== undefined) {
console.log(`::group::Run pre emulator launch script`);
@@ -198,7 +202,7 @@ function run() {
console.log(`::endgroup::`);
}
// launch an emulator
yield (0, emulator_manager_1.launchEmulator)(apiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
yield (0, emulator_manager_1.launchEmulator)(systemImageApiLevel, target, arch, profile, cores, ramSize, heapSize, sdcardPathOrSize, diskSize, avdName, forceAvdCreation, emulatorBootTimeout, port, emulatorOptions, disableAnimations, disableSpellchecker, disableLinuxHardwareAcceleration, enableHardwareKeyboard);
// execute the custom script
try {
// move to custom working directory if set
+7 -9
View File
@@ -38,23 +38,20 @@ 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 = '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';
const BUILD_TOOLS_VERSION = '35.0.0';
// SDK command-line tools 16.0
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-12266719_latest.zip';
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-12266719_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.
*/
function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) {
function installAndroidSdk(apiLevel, systemImageApiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion) {
return __awaiter(this, void 0, void 0, function* () {
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_HOME} -R`);
}
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
if (!fs.existsSync(cmdlineToolsPath)) {
console.log('Installing new cmdline-tools.');
@@ -66,6 +63,7 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
// add paths for commandline-tools and platform-tools
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
// set standard AVD path
yield io.mkdirP(`${process.env.HOME}/.android/avd`);
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"`);
@@ -97,7 +95,7 @@ function installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndk
yield io.rmRF('emulator.zip');
}
console.log('Installing system images.');
yield exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
yield exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${systemImageApiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
if (ndkVersion) {
console.log(`Installing NDK ${ndkVersion}.`);
yield exec.exec(`sh -c \\"sdkmanager --install 'ndk;${ndkVersion}' --channel=${channelId} > /dev/null"`);
+14 -14
View File
@@ -2105,12 +2105,12 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@@ -3053,9 +3053,9 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
@@ -7802,12 +7802,12 @@
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
}
},
"browserslist": {
@@ -8505,9 +8505,9 @@
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
+2 -2
View File
@@ -5,7 +5,7 @@ import * as fs from 'fs';
* Creates and launches a new AVD instance with the specified configurations.
*/
export async function launchEmulator(
apiLevel: string,
systemImageApiLevel: string,
target: string,
arch: string,
profile: string,
@@ -33,7 +33,7 @@ export async function launchEmulator(
const sdcardPathOrSizeOption = sdcardPathOrSize.trim() !== '' ? `--sdcard '${sdcardPathOrSize}'` : '';
console.log(`Creating AVD.`);
await exec.exec(
`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${apiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`
`sh -c \\"echo no | avdmanager create avd --force -n "${avdName}" --abi '${target}/${arch}' --package 'system-images;android-${systemImageApiLevel};${target};${arch}' ${profileOption} ${sdcardPathOrSizeOption}"`
);
}
+14 -12
View File
@@ -1,20 +1,22 @@
export const MIN_API_LEVEL = 15;
export const VALID_TARGETS: Array<string> = ['default', 'google_apis', 'aosp_atd', 'google_atd', 'google_apis_playstore', 'android-wear', 'android-wear-cn', 'android-tv', 'google-tv'];
export const VALID_TARGETS: Array<string> = [
'default',
'google_apis',
'aosp_atd',
'google_atd',
'google_apis_playstore',
'android-wear',
'android-wear-cn',
'android-tv',
'google-tv',
'android-automotive',
'android-automotive-playstore',
'android-desktop',
];
export const VALID_ARCHS: Array<string> = ['x86', 'x86_64', 'arm64-v8a'];
export const VALID_CHANNELS: Array<string> = ['stable', 'beta', 'dev', 'canary'];
export const MIN_PORT = 5554;
export const MAX_PORT = 5584;
export const PREVIEW_API_LEVELS: Array<string> = ['Tiramisu', 'UpsideDownCake', 'VanillaIceCream'];
export function checkApiLevel(apiLevel: string): void {
if (PREVIEW_API_LEVELS.some((previewLevel) => apiLevel.startsWith(previewLevel))) return;
if (isNaN(Number(apiLevel)) || !Number.isInteger(Number(apiLevel))) {
throw new Error(`Unexpected API level: '${apiLevel}'.`);
}
if (Number(apiLevel) < MIN_API_LEVEL) {
throw new Error(`Minimum API level supported is ${MIN_API_LEVEL}.`);
}
}
export function checkTarget(target: string): void {
if (!VALID_TARGETS.includes(target)) {
+8 -4
View File
@@ -1,7 +1,6 @@
import * as core from '@actions/core';
import { installAndroidSdk } from './sdk-installer';
import {
checkApiLevel,
checkTarget,
checkArch,
checkDisableAnimations,
@@ -44,9 +43,14 @@ async function run() {
// API level of the platform and system image
const apiLevel = core.getInput('api-level', { required: true });
checkApiLevel(apiLevel);
console.log(`API level: ${apiLevel}`);
let systemImageApiLevel = core.getInput('system-image-api-level');
if (!systemImageApiLevel) {
systemImageApiLevel = apiLevel;
}
console.log(`System image API level: ${systemImageApiLevel}`);
// target of the system image
const targetInput = core.getInput('target');
const target = targetInput == 'playstore' ? 'google_apis_playstore' : targetInput;
@@ -185,7 +189,7 @@ async function run() {
console.log(`::endgroup::`);
// install SDK
await installAndroidSdk(apiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
await installAndroidSdk(apiLevel, systemImageApiLevel, target, arch, channelId, emulatorBuild, ndkVersion, cmakeVersion);
// execute pre emulator launch script if set
if (preEmulatorLaunchScripts !== undefined) {
@@ -206,7 +210,7 @@ async function run() {
// launch an emulator
await launchEmulator(
apiLevel,
systemImageApiLevel,
target,
arch,
profile,
+16 -10
View File
@@ -4,25 +4,30 @@ import * as io from '@actions/io';
import * as tc from '@actions/tool-cache';
import * as fs from 'fs';
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';
const BUILD_TOOLS_VERSION = '35.0.0';
// SDK command-line tools 16.0
const CMDLINE_TOOLS_URL_MAC = 'https://dl.google.com/android/repository/commandlinetools-mac-12266719_latest.zip';
const CMDLINE_TOOLS_URL_LINUX = 'https://dl.google.com/android/repository/commandlinetools-linux-12266719_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: string, target: string, arch: string, channelId: number, emulatorBuild?: string, ndkVersion?: string, cmakeVersion?: string): Promise<void> {
export async function installAndroidSdk(
apiLevel: string,
systemImageApiLevel: 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_HOME} -R`);
}
const cmdlineToolsPath = `${process.env.ANDROID_HOME}/cmdline-tools`;
if (!fs.existsSync(cmdlineToolsPath)) {
console.log('Installing new cmdline-tools.');
@@ -36,6 +41,7 @@ export async function installAndroidSdk(apiLevel: string, target: string, arch:
core.addPath(`${cmdlineToolsPath}/latest:${cmdlineToolsPath}/latest/bin:${process.env.ANDROID_HOME}/platform-tools`);
// set standard AVD path
await io.mkdirP(`${process.env.HOME}/.android/avd`);
core.exportVariable('ANDROID_AVD_HOME', `${process.env.HOME}/.android/avd`);
// accept all Android SDK licenses
@@ -69,7 +75,7 @@ export async function installAndroidSdk(apiLevel: string, target: string, arch:
await io.rmRF('emulator.zip');
}
console.log('Installing system images.');
await exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${apiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
await exec.exec(`sh -c \\"sdkmanager --install 'system-images;android-${systemImageApiLevel};${target};${arch}' --channel=${channelId} > /dev/null"`);
if (ndkVersion) {
console.log(`Installing NDK ${ndkVersion}.`);
+7 -8
View File
@@ -4,13 +4,13 @@ apply plugin: 'kotlin-android'
android {
namespace = "com.example.testapp"
compileSdkVersion 34
buildToolsVersion "34.0.0"
compileSdkVersion 35
buildToolsVersion "35.0.0"
defaultConfig {
applicationId "com.example.testapp"
minSdkVersion 15
targetSdkVersion 34
minSdkVersion 21
targetSdkVersion 35
versionCode 1
versionName "1.0"
@@ -30,8 +30,7 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.6.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'androidx.appcompat:appcompat:1.7.0'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
}
+2 -2
View File
@@ -6,8 +6,8 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21"
classpath 'com.android.tools.build:gradle:8.7.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.20"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME