1import * as osascript from '@expo/osascript'; 2import { execFileSync } from 'child_process'; 3 4import * as Log from '../../../log'; 5import { Device } from './adb'; 6 7function getUnixPID(port: number | string): string { 8 // Runs like `lsof -i:8081 -P -t -sTCP:LISTEN` 9 const args = [`-i:${port}`, '-P', '-t', '-sTCP:LISTEN']; 10 Log.debug('lsof ' + args.join(' ')); 11 return execFileSync('lsof', args, { 12 encoding: 'utf8', 13 stdio: ['pipe', 'pipe', 'ignore'], 14 }) 15 .split('\n')[0] 16 ?.trim?.(); 17} 18 19/** Activate the Emulator window on macOS. */ 20export async function activateWindowAsync(device: Pick<Device, 'type' | 'pid'>): Promise<boolean> { 21 Log.debug(`Activating window for device (pid: ${device.pid}, type: ${device.type})`); 22 if ( 23 // only mac is supported for now. 24 process.platform !== 'darwin' || 25 // can only focus emulators 26 device.type !== 'emulator' 27 ) { 28 return false; 29 } 30 31 // Google Emulator ID: `emulator-5554` -> `5554` 32 const androidPid = device.pid!.match(/-(\d+)/)?.[1]; 33 if (!androidPid) { 34 return false; 35 } 36 // Unix PID 37 const pid = getUnixPID(androidPid); 38 39 if (!pid) { 40 return false; 41 } 42 Log.debug(`Activate window for pid:`, pid); 43 try { 44 await osascript.execAsync(` 45 tell application "System Events" 46 set frontmost of the first process whose unix id is ${pid} to true 47 end tell`); 48 return true; 49 } catch { 50 // noop -- this feature is very specific and subject to failure. 51 return false; 52 } 53} 54