diff --git a/.eslintrc.json b/.eslintrc.json
index befe3fc..90ec3d5 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -20,6 +20,7 @@
"linebreak-style": ["error", "unix"],
"quotes": ["error", "single"],
"semi": ["error", "always"],
- "@typescript-eslint/ban-types": "off"
+ "@typescript-eslint/ban-types": "off",
+ "@typescript-eslint/prefer-nullish-coalescing": "off"
}
}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4c6c0a2..c7a2ac2 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -31,7 +31,7 @@ jobs:
# runs-on: macos-latest
Test:
- runs-on: windows-latest
+ runs-on: ubuntu-latest
needs: Lint
strategy:
matrix:
@@ -66,5 +66,16 @@ jobs:
- name: Setup Android SDK
uses: amyu/setup-android@v3.1
+ - name: Run some command
+ run: |
+ ls "$ANDROID_HOME"
+ ls "$ANDROID_HOME"/emulator
+
+ - 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
+
- name: Run tests 👩🏽💻
run: npm run test
diff --git a/README-ZH_CN.md b/README-ZH_CN.md
index 6be6188..a92e168 100644
--- a/README-ZH_CN.md
+++ b/README-ZH_CN.md
@@ -134,17 +134,16 @@ android
});
```
-| field | type | required | default | note |
-| ------- | ------- | -------- | ------- | --------------------------------------------------------------------------------------- |
-| sdcard | string | false | - | 共享 SD 卡镜像的路径,或者为新模拟器选择一个新的 SD 卡大小。 |
-| tag | string | false | - | 用于模拟器的 sys-img 标签。默认情况下,如果平台只有一个标签用于其系统镜像,则自动选择。 |
-| path | string | false | - | 新的模拟器将创建在哪个目录位置。 |
-| package | string | true | - | 此模拟器的系统镜像的路径(例如 'system-images;android-19;google_apis;x86')。 |
-| name | string | false | - | 新模拟器的名称。 |
-| skin | string | false | - | 此设备可选择使用的皮肤名称。 |
-| force | boolean | false | - | 创建虚拟设备(覆盖现有的模拟器)。 |
-| abi | string | false | - | 如果平台的系统镜像只有一个 ABI,则默认为自动选择 ABI 来使用模拟器。 |
-| device | string | false | - | 可选的要使用的设备定义。可以是设备索引或 id。 |
+| field | type | required | default | note |
+| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- | ----------------------------------------------------------------------------------- |
+| apiLevel | number | false | - | 平台系统镜像的API级别 - 例如,Android Marshmallow的级别为23,Android 10的级别为29。 |
+| target | 'default'
'google_apis'
'playstore'
'android-wear'
'android-wear-cn'
'android-tv'
'google-tv'
'aosp_atd '
'google_atd' | false | 'default' | 系统镜像的目标。 |
+| arch | 'x86_64'
'x86'
'arm64-v8a'
'armeabi-v7a' | false | 'x86_64' | 系统镜像的CPU架构 |
+| package | string | true | - | 此模拟器的系统镜像的路径(例如 'system-images;android-19;google_apis;x86')。 |
+| name | string | false | - | 新模拟器的名称。 |
+| force | boolean | false | - | 创建虚拟设备(覆盖现有的模拟器)。 |
+
+- 如果你传了`package`,则参数`apiLevel`,`target`,`arch`将被会略。如果你没有传参`package`,则`apiLevel`参数是必须的。
### hasAVD
diff --git a/README.md b/README.md
index d0c3d8a..1be71c5 100644
--- a/README.md
+++ b/README.md
@@ -134,17 +134,16 @@ android
});
```
-| field | type | required | default | note |
-| ------- | ------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
-| sdcard | string | false | - | Path to a shared SD card image, or size of a new sdcard for the new AVD. |
-| tag | string | false | - | The sys-img tag to use for the AVD. The default is to auto-select if the platform has only one tag for its system images. |
-| path | string | false | - | Directory where the new AVD will be created. |
-| package | string | true | - | Package path of the system image for this AVD (e.g. 'system-images;android-19;google_apis;x86'). |
-| name | string | false | - | Name of the new AVD. |
-| skin | string | false | - | The optional name of a skin to use with this device. |
-| force | boolean | false | - | Forces creation (overwrites an existing AVD) |
-| abi | string | false | - | The ABI to use for the AVD. The default is to auto-select the ABI if the platform has only one ABI for its system images. |
-| device | string | false | - | The optional device definition to use. Can be a device index or id. |
+| field | type | required | default | note |
+| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- | ------------------------------------------------------------------------------------------------ |
+| apiLevel | number | false | - | API level of the platform system image - e.g. 23 for Android Marshmallow, 29 for Android 10. |
+| target | 'default'
'google_apis'
'playstore'
'android-wear'
'android-wear-cn'
'android-tv'
'google-tv'
'aosp_atd '
'google_atd' | false | 'default' | Target of the system image . |
+| arch | 'x86_64'
'x86'
'arm64-v8a'
'armeabi-v7a' | false | 'x86_64' | CPU architecture of the system image |
+| package | string | false | - | Package path of the system image for this AVD (e.g. 'system-images;android-19;google_apis;x86'). |
+| name | string | false | - | Name of the new AVD. |
+| force | boolean | false | - | Forces creation (overwrites an existing AVD) |
+
+- If you pass a `package`, the parameters `apiLevel`, `target`, and `arch` will be ignored. If you don't pass a `package`, the `apiLevel` parameter is required.
### hasAVD
diff --git a/spec/afterStart.test.ts b/spec/afterStart.test.ts
index 313748d..d0a5b87 100644
--- a/spec/afterStart.test.ts
+++ b/spec/afterStart.test.ts
@@ -1,5 +1,6 @@
import path from 'path';
import Android from '../src/index.js';
+import { EmulatorGpu } from '../src/emulator.js';
const android = new Android();
@@ -11,8 +12,7 @@ beforeAll(async () => {
avdName = `TestCreate_${Math.random().toString().substring(2)}`;
const images = (await android.listImages()).filter((item) => item.vendor === 'default' && item.arch === 'x86_64');
if (images.length === 0) return;
- const image = images[images.length - 1].name;
- await android.createAVD({ name: avdName, package: image, force: false });
+ await android.createAVD({ name: avdName, apiLevel: 31, force: false });
} else {
avdName = avds[0].Name;
}
@@ -22,7 +22,9 @@ beforeAll(async () => {
noaudio: true,
noBootAnim: true,
noSnapshot: true,
- noWindow: true
+ noSnapshotSave: true,
+ noWindow: true,
+ gpu: EmulatorGpu.SWIFTSHADER_INDIRECT
});
emulatorId = res.id;
if (emulatorId) {
diff --git a/src/emulator.ts b/src/emulator.ts
index 2d04c1d..0bbe84d 100644
--- a/src/emulator.ts
+++ b/src/emulator.ts
@@ -41,6 +41,27 @@ export interface EmulatorOptions {
wipeData?: boolean;
/** disable passive gps updates */
noPassiveGps?: boolean;
+ /** Disables acceleration entirely. Mostly useful for debugging. */
+ noAccel?: boolean;
+}
+
+export enum SystemImageTarget {
+ DEFAULT = 'default',
+ GOOGLE_APIS = 'google_apis',
+ PLAYSTORE = 'playstore',
+ ANDROID_WEAR = 'android-wear',
+ android_wear_cn = 'android-wear-cn',
+ android_tv = 'android-tv',
+ google_tv = 'google-tv',
+ AOSP_ATD = 'aosp_atd',
+ GOOGLE_ATD = 'google_atd'
+}
+
+export enum Arch {
+ X86 = 'x86',
+ X86_64 = 'x86_64',
+ ARM64_V8A = 'arm64-v8a',
+ ARMEABI_V7A = 'armeabi-v7a'
}
/**
diff --git a/src/index.ts b/src/index.ts
index b1d8dc5..f1ecc8f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -7,7 +7,7 @@ import {
spawnExec,
spawnWaitFor
} from './util.js';
-import { EmulatorOptions } from './emulator.js';
+import { Arch, EmulatorOptions, SystemImageTarget } from './emulator.js';
export interface AndroidOptions {
/** The location of the `adb` executable file relative to `ANDROID_HOME` */
@@ -23,43 +23,18 @@ export interface AndroidOptions {
export type AndroidExecBin = 'adbBin' | 'avdmanagerBin' | 'sdkmanagerBin' | 'emulatorBin';
export interface CreateAVDOptions {
- /** Path to a shared SD card image, or size of a new sdcard for the new AVD. */
- sdcard?: string;
- /**
- * The sys-img tag to use for the AVD. The default is to
- * auto-select if the platform has only one tag for its system
- * images.
- */
- tag?: string;
- /** Directory where the new AVD will be created. */
- path?: string;
- /**
- * Package path of the system image for this AVD (e.g.
- * 'system-images;android-19;google_apis;x86').
- */
- package: string;
- /**
- * Name of the new AVD. [required]
- */
+ /** API level of the platform system image */
+ apiLevel?: number;
+ /** Target of the system image */
+ target?: SystemImageTarget;
+ /** CPU architecture of the system image */
+ arch?: Arch;
+ /** Name of AVD */
name: string;
- /**
- * The optional name of a skin to use with this device.
- */
- skin?: string;
- /**
- * Forces creation (overwrites an existing AVD)
- */
+ /** Forces creation (overwrites an existing AVD) */
force?: boolean;
- /**
- * The ABI to use for the AVD. The default is to auto-select the
- * ABI if the platform has only one ABI for its system images.
- */
- abi?: string;
- /**
- * The optional device definition to use. Can be a device index
- * or id.
- */
- device?: string;
+ /** Package path of the system image for this AVD (e.g. 'system-images;android-19;google_apis;x86'). */
+ package?: string;
}
export interface Device {
@@ -240,18 +215,18 @@ class Android {
* @param name name of AVD
*/
async createAVD(options: CreateAVDOptions) {
- if (options.package) {
- // Downloading the SDK takes a lot of time, so it's best to download it in advance.
- await this.sdkmanager(`--install ${options.package}`, 600000);
- }
- const cmdParams = Object.keys(options).reduce((prev, curr) => {
- const val = options[curr as keyof CreateAVDOptions];
- if (typeof val === 'boolean') {
- if (val) return `${prev} --${curr}`;
- else return prev;
- }
- return `${prev} --${curr} ${val}`;
- }, '');
+ if (!options.name) return Promise.reject(Error('Missing name parameter.'));
+ if (!options.package && !options.apiLevel)
+ return Promise.reject(Error('Either the parameter "package" or "apiLevel" must be present.'));
+ const systemImage =
+ options.package ||
+ `system-images;android-${options.apiLevel};${options.target || SystemImageTarget.DEFAULT};${
+ options.arch || Arch.X86_64
+ }`;
+ // Downloading the SDK takes a lot of time, so it's best to download it in advance.
+ await this.sdkmanager(`--install ${systemImage}`, 600000);
+ let cmdParams = `-n ${options.name} -k ${systemImage}`;
+ if (options.force) cmdParams += ' -f';
return await this.avdmanager(`-s create avd ${cmdParams}`);
}