Improve error handling for iOSDevices

Summary:
Adding context everywhere as naked messages are hard to track down
and making common errors like missing Xcode license agreements
a warning + error popup instead.

Changelog: Reduce spamminess of iOS connection warnings

Reviewed By: mweststrate

Differential Revision: D26370235

fbshipit-source-id: b283d297479c2bf76a11b5a3f96a59fad70a4a67
This commit is contained in:
Pascal Hartig
2021-02-11 05:06:28 -08:00
committed by Facebook GitHub Bot
parent 8d5f136a34
commit 92f3ab8ff4
2 changed files with 23 additions and 10 deletions

View File

@@ -94,7 +94,7 @@ if (typeof window !== 'undefined') {
async function queryDevices(store: Store, logger: Logger): Promise<any> { async function queryDevices(store: Store, logger: Logger): Promise<any> {
return Promise.all([ return Promise.all([
checkXcodeVersionMismatch(store), checkXcodeVersionMismatch(store),
getSimulators(true).then((devices) => { getSimulators(store, true).then((devices) => {
processDevices(store, logger, devices, 'emulator'); processDevices(store, logger, devices, 'emulator');
}), }),
getActiveDevices(store.getState().settingsState.idbPath).then( getActiveDevices(store.getState().settingsState.idbPath).then(
@@ -163,6 +163,7 @@ function getDeviceSetPath() {
} }
export function getSimulators( export function getSimulators(
store: Store,
bootedOnly: boolean, bootedOnly: boolean,
): Promise<Array<IOSDeviceParams>> { ): Promise<Array<IOSDeviceParams>> {
return promisify(execFile)( return promisify(execFile)(
@@ -188,8 +189,16 @@ export function getSimulators(
} as IOSDeviceParams; } as IOSDeviceParams;
}); });
}) })
.catch((e) => { .catch((e: Error) => {
console.error(e); console.warn('Failed to query simulators:', e);
if (e.message.includes('Xcode license agreements')) {
store.dispatch(
addErrorNotification(
'Xcode license requires approval',
'The Xcode license agreement has changed. You need to either open Xcode and agree to the terms or run `sudo xcodebuild -license` in a Terminal to allow simulators to work with Flipper.',
),
);
}
return Promise.resolve([]); return Promise.resolve([]);
}); });
} }
@@ -205,7 +214,7 @@ export async function launchSimulator(udid: string): Promise<any> {
function getActiveDevices(idbPath: string): Promise<Array<IOSDeviceParams>> { function getActiveDevices(idbPath: string): Promise<Array<IOSDeviceParams>> {
return iosUtil.targets(idbPath).catch((e) => { return iosUtil.targets(idbPath).catch((e) => {
console.error(e.message); console.error('Failed to get active iOS devices:', e.message);
return []; return [];
}); });
} }
@@ -218,7 +227,7 @@ function queryDevicesForever(store: Store, logger: Logger) {
setTimeout(() => queryDevicesForever(store, logger), 3000); setTimeout(() => queryDevicesForever(store, logger), 3000);
}) })
.catch((err) => { .catch((err) => {
console.error(err); console.warn('Failed to continuously query devices:', err);
}); });
} }
@@ -246,7 +255,7 @@ async function checkXcodeVersionMismatch(store: Store) {
} }
} }
} catch (e) { } catch (e) {
console.error(e); console.error('Failed to determine Xcode version:', e);
} }
} }
async function isXcodeDetected(): Promise<boolean> { async function isXcodeDetected(): Promise<boolean> {
@@ -259,7 +268,7 @@ export async function getActiveDevicesAndSimulators(
store: Store, store: Store,
): Promise<Array<IOSDevice>> { ): Promise<Array<IOSDevice>> {
const activeDevices: Array<Array<IOSDeviceParams>> = await Promise.all([ const activeDevices: Array<Array<IOSDeviceParams>> = await Promise.all([
getSimulators(true), getSimulators(store, true),
getActiveDevices(store.getState().settingsState.idbPath), getActiveDevices(store.getState().settingsState.idbPath),
]); ]);
const allDevices = activeDevices[0].concat(activeDevices[1]); const allDevices = activeDevices[0].concat(activeDevices[1]);

View File

@@ -33,7 +33,10 @@ const COLD_BOOT = 'cold-boot';
export function showEmulatorLauncher(store: Store) { export function showEmulatorLauncher(store: Store) {
renderReactRoot((unmount) => ( renderReactRoot((unmount) => (
<Provider store={store}> <Provider store={store}>
<LaunchEmulatorDialog onClose={unmount} getSimulators={getSimulators} /> <LaunchEmulatorDialog
onClose={unmount}
getSimulators={getSimulators.bind(store)}
/>
</Provider> </Provider>
)); ));
} }
@@ -56,11 +59,12 @@ export const LaunchEmulatorDialog = withTrackingScope(
); );
const [iosEmulators, setIosEmulators] = useState<IOSDeviceParams[]>([]); const [iosEmulators, setIosEmulators] = useState<IOSDeviceParams[]>([]);
const store = useStore();
useEffect(() => { useEffect(() => {
if (!iosEnabled) { if (!iosEnabled) {
return; return;
} }
getSimulators(false).then((emulators) => { getSimulators(store, false).then((emulators) => {
setIosEmulators( setIosEmulators(
emulators.filter( emulators.filter(
(device) => (device) =>
@@ -69,7 +73,7 @@ export const LaunchEmulatorDialog = withTrackingScope(
), ),
); );
}); });
}, [iosEnabled, getSimulators]); }, [iosEnabled, getSimulators, store]);
const items = [ const items = [
...(androidEmulators.length > 0 ? [<AndroidOutlined />] : []), ...(androidEmulators.length > 0 ? [<AndroidOutlined />] : []),