11import { type AndroidAppLaunchOptions } from '@react-native-harness/platforms' ;
22import { spawn , SubprocessError } from '@react-native-harness/tools' ;
3+ import { access } from 'node:fs/promises' ;
34import {
45 getAdbBinaryPath ,
56 getAvdManagerBinaryPath ,
@@ -22,6 +23,19 @@ const getAvdConfigPath = (name: string): string =>
2223 process . env . ANDROID_AVD_HOME ?? `${ process . env . HOME } /.android/avd`
2324 } /${ name } .avd/config.ini`;
2425
26+ const ensureEmulatorInstalled = async ( ) : Promise < string > => {
27+ const emulatorBinaryPath = getEmulatorBinaryPath ( ) ;
28+
29+ try {
30+ await access ( emulatorBinaryPath ) ;
31+ return emulatorBinaryPath ;
32+ } catch {
33+ await spawn ( getSdkManagerBinaryPath ( ) , [ 'emulator' ] ) ;
34+ await access ( emulatorBinaryPath ) ;
35+ return emulatorBinaryPath ;
36+ }
37+ } ;
38+
2539export type CreateAvdOptions = {
2640 name : string ;
2741 apiLevel : number ;
@@ -222,8 +236,10 @@ export const createAvd = async ({
222236} ;
223237
224238export const startEmulator = async ( name : string ) : Promise < void > => {
239+ const emulatorBinaryPath = await ensureEmulatorInstalled ( ) ;
240+
225241 void spawn (
226- getEmulatorBinaryPath ( ) ,
242+ emulatorBinaryPath ,
227243 [
228244 `@${ name } ` ,
229245 '-no-snapshot-save' ,
@@ -364,7 +380,8 @@ export const getLogcatTimestamp = async (adbId: string): Promise<string> => {
364380
365381export const getAvds = async ( ) : Promise < string [ ] > => {
366382 try {
367- const { stdout } = await spawn ( getEmulatorBinaryPath ( ) , [ '-list-avds' ] ) ;
383+ const emulatorBinaryPath = await ensureEmulatorInstalled ( ) ;
384+ const { stdout } = await spawn ( emulatorBinaryPath , [ '-list-avds' ] ) ;
368385 return stdout
369386 . split ( '\n' )
370387 . map ( ( line ) => line . trim ( ) )
0 commit comments