diff --git a/desktop/flipper-server-core/src/devices/ios/IOSBridge.tsx b/desktop/flipper-server-core/src/devices/ios/IOSBridge.tsx index df4e7f816..f5fded5c6 100644 --- a/desktop/flipper-server-core/src/devices/ios/IOSBridge.tsx +++ b/desktop/flipper-server-core/src/devices/ios/IOSBridge.tsx @@ -8,6 +8,8 @@ */ import fs from 'fs-extra'; +import iosUtil from './iOSContainerUtility'; + import child_process from 'child_process'; import type {IOSDeviceParams} from 'flipper-common'; import {DeviceType} from 'flipper-common'; @@ -42,10 +44,22 @@ export interface IOSBridge { serial: string, outputFile: string, ) => child_process.ChildProcess; + getActiveDevices: (bootedOnly: boolean) => Promise>; } -class IDBBridge implements IOSBridge { - constructor(private idbPath: string) {} +export class IDBBridge implements IOSBridge { + constructor( + private idbPath: string, + private enablePhysicalDevices: boolean, + ) {} + async getActiveDevices(_bootedOnly: boolean): Promise { + return iosUtil + .targets(this.idbPath, this.enablePhysicalDevices) + .catch((e) => { + console.error('Failed to get active iOS devices:', e.message); + return []; + }); + } async navigate(serial: string, location: string): Promise { this._execIdb(`open --udid ${serial} "${location}"`); @@ -216,11 +230,12 @@ export function getDeviceSetPath() { export async function makeIOSBridge( idbPath: string, isXcodeDetected: boolean, + enablePhysicalDevices: boolean, isAvailableFn: (idbPath: string) => Promise = isAvailable, ): Promise { // prefer idb if (await isAvailableFn(idbPath)) { - return new IDBBridge(idbPath); + return new IDBBridge(idbPath, enablePhysicalDevices); } // no idb, if it's a simulator and xcode is available, we can use xcrun diff --git a/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx b/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx index fa386921c..1635abed8 100644 --- a/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx +++ b/desktop/flipper-server-core/src/devices/ios/__tests__/IOSBridge.node.tsx @@ -26,7 +26,7 @@ afterEach(() => { }); test('uses xcrun with no idb when xcode is detected', async () => { - const ib = await makeIOSBridge('', true); + const ib = await makeIOSBridge('', true, false); ib.startLogListener('deadbeef', 'emulator'); @@ -50,7 +50,12 @@ test('uses xcrun with no idb when xcode is detected', async () => { }); test('uses idb when present and xcode detected', async () => { - const ib = await makeIOSBridge('/usr/local/bin/idb', true, async (_) => true); + const ib = await makeIOSBridge( + '/usr/local/bin/idb', + true, + true, + async (_) => true, + ); ib.startLogListener('deadbeef', 'emulator'); @@ -77,7 +82,12 @@ test('uses idb when present and xcode detected', async () => { }); test('uses idb when present and xcode detected and physical device connected', async () => { - const ib = await makeIOSBridge('/usr/local/bin/idb', true, async (_) => true); + const ib = await makeIOSBridge( + '/usr/local/bin/idb', + true, + true, + async (_) => true, + ); ib.startLogListener('deadbeef', 'physical'); @@ -99,12 +109,12 @@ test('uses idb when present and xcode detected and physical device connected', a }); test("without idb physical devices can't log", async () => { - const ib = await makeIOSBridge('', true); + const ib = await makeIOSBridge('', true, false); expect(ib.startLogListener).toBeDefined(); // since we have xcode }); test('throws if no iOS support', async () => { - await expect(makeIOSBridge('', false)).rejects.toThrow( + await expect(makeIOSBridge('', false, false)).rejects.toThrow( 'Neither Xcode nor idb available. Cannot provide iOS device functionality.', ); }); @@ -112,7 +122,7 @@ test('throws if no iOS support', async () => { test.unix( 'uses xcrun to take screenshots with no idb when xcode is detected', async () => { - const ib = await makeIOSBridge('', true); + const ib = await makeIOSBridge('', true, false); await expect(() => ib.screenshot('deadbeef')).rejects.toThrow(); @@ -123,7 +133,12 @@ test.unix( ); test.unix('uses idb to take screenshots when available', async () => { - const ib = await makeIOSBridge('/usr/local/bin/idb', true, async (_) => true); + const ib = await makeIOSBridge( + '/usr/local/bin/idb', + true, + true, + async (_) => true, + ); await expect(() => ib.screenshot('deadbeef')).rejects.toThrow(); @@ -133,7 +148,7 @@ test.unix('uses idb to take screenshots when available', async () => { }); test('uses xcrun to navigate with no idb when xcode is detected', async () => { - const ib = await makeIOSBridge('', true); + const ib = await makeIOSBridge('', true, false); await ib.navigate('deadbeef', 'fb://dummy'); @@ -143,7 +158,12 @@ test('uses xcrun to navigate with no idb when xcode is detected', async () => { }); test('uses idb to navigate when available', async () => { - const ib = await makeIOSBridge('/usr/local/bin/idb', true, async (_) => true); + const ib = await makeIOSBridge( + '/usr/local/bin/idb', + true, + true, + async (_) => true, + ); await ib.navigate('deadbeef', 'fb://dummy'); @@ -153,7 +173,7 @@ test('uses idb to navigate when available', async () => { }); test('uses xcrun to record with no idb when xcode is detected', async () => { - const ib = await makeIOSBridge('', true); + const ib = await makeIOSBridge('', true, false); ib.recordVideo('deadbeef', '/tmp/video.mp4'); @@ -163,7 +183,12 @@ test('uses xcrun to record with no idb when xcode is detected', async () => { }); test('uses idb to record when available', async () => { - const ib = await makeIOSBridge('/usr/local/bin/idb', true, async (_) => true); + const ib = await makeIOSBridge( + '/usr/local/bin/idb', + true, + true, + async (_) => true, + ); ib.recordVideo('deadbeef', '/tmo/video.mp4'); diff --git a/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx b/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx index 099105641..354bd60b1 100644 --- a/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx +++ b/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx @@ -17,6 +17,7 @@ import IOSDevice from './IOSDevice'; import { ERR_NO_IDB_OR_XCODE_AVAILABLE, IOSBridge, + IDBBridge, makeIOSBridge, SimctlBridge, } from './IOSBridge'; @@ -174,7 +175,11 @@ export class IOSDeviceManager { } try { // Awaiting the promise here to trigger immediate error handling. - this.iosBridge = await makeIOSBridge(settings.idbPath, isDetected); + this.iosBridge = await makeIOSBridge( + settings.idbPath, + isDetected, + settings.enablePhysicalIOS, + ); this.queryDevicesForever(); } catch (err) { // This case is expected if both Xcode and idb are missing. @@ -252,10 +257,7 @@ function getActiveDevices( idbPath: string, isPhysicalDeviceEnabled: boolean, ): Promise> { - return iosUtil.targets(idbPath, isPhysicalDeviceEnabled).catch((e) => { - console.error('Failed to get active iOS devices:', e.message); - return []; - }); + return new IDBBridge(idbPath, isPhysicalDeviceEnabled).getActiveDevices(true); } export function parseXcodeFromCoreSimPath(