Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/common/definitions/mobile.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,11 @@ declare global {
shouldReturnImmediateResult: boolean;
platform: string;
fullDiscovery?: boolean;
/**
* Ends the wait for physical devices once the device requested on the
* command line has been found by any discovery.
*/
isRequestedDeviceFound?: () => boolean;
}

interface IAndroidDeviceHashService {
Expand Down
35 changes: 25 additions & 10 deletions lib/common/mobile/ios/device/ios-device-operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ import {
} from "../../../declarations";
import { injector } from "../../../yok";

// Other devices can still be arriving by then, and device indexes follow the
// order they were discovered in.
const MIN_DISCOVERY_WAIT_MS = 2000;

export function isDeviceDiscoveryDone(
foundDevice: boolean,
waitedMs: number,
options?: Mobile.IDeviceLookingOptions,
): boolean {
if (options?.isRequestedDeviceFound) {
return options.isRequestedDeviceFound();
}

return foundDevice && !options?.fullDiscovery && waitedMs >= MIN_DISCOVERY_WAIT_MS;
}

export class IOSDeviceOperations
extends EventEmitter
implements IIOSDeviceOperations, IDisposable, IShouldDispose
Expand Down Expand Up @@ -86,21 +102,20 @@ export class IOSDeviceOperations

// We need this because we need to make sure that we have devices.
await new Promise<void>((resolve, reject) => {
let iterationsCount = 0;
const maxIterationsCount = 3;
const pollInterval = 100;
Comment thread
rigor789 marked this conversation as resolved.
Resolved
const maxWait = 6000;
let waited = 0;

const intervalHandle: NodeJS.Timer = setInterval(() => {
if (foundDevice && !options.fullDiscovery) {
resolve();
return clearInterval(intervalHandle as unknown as number);
}

iterationsCount++;
if (iterationsCount >= maxIterationsCount) {
waited += pollInterval;
if (
waited >= maxWait ||
isDeviceDiscoveryDone(foundDevice, waited, options)
) {
clearInterval(intervalHandle as unknown as number);
return resolve();
}
}, 2000);
}, pollInterval);
});
}
}
Expand Down
51 changes: 34 additions & 17 deletions lib/common/mobile/mobile-core/devices-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,13 +415,23 @@ export class DevicesService
deviceInitOpts?: Mobile.IDeviceLookingOptions,
): Promise<void> {
const options = this.getDeviceLookingOptions(deviceInitOpts);

for (const deviceDiscovery of this._allDeviceDiscoveries) {
const startLooking = async (deviceDiscovery: Mobile.IDeviceDiscovery) => {
try {
await deviceDiscovery.startLookingForDevices(options);
} catch (err) {
this.$logger.trace("Error while checking for devices.", err);
}
};

// Concurrently, so a requested simulator ends the wait for physical
// devices. Otherwise in order, as device indexes follow discovery order.
if (options.isRequestedDeviceFound) {
await Promise.all(this._allDeviceDiscoveries.map(startLooking));
return;
}

for (const deviceDiscovery of this._allDeviceDiscoveries) {
await startLooking(deviceDiscovery);
}
}

Expand Down Expand Up @@ -516,6 +526,18 @@ export class DevicesService
* The identifier is expected to be the same as the running device declares it (emulator-5554 for android or GUID for ios).
* @param identifier running emulator or device identifier
*/
private findDevice(deviceOption: string): Mobile.IDevice {
return _.find(
this.getDeviceInstances(),
(d) =>
(d.deviceInfo.identifier && d.deviceInfo.identifier === deviceOption) ||
(d.deviceInfo.displayName &&
d.deviceInfo.displayName === deviceOption) ||
(d.deviceInfo.imageIdentifier &&
d.deviceInfo.imageIdentifier === deviceOption),
);
}

public getDeviceByIdentifier(identifier: string): Mobile.IDevice {
const searchedDevice = _.find(
this.getDeviceInstances(),
Expand Down Expand Up @@ -581,20 +603,7 @@ export class DevicesService
* @param deviceOption parameter passed by the user to --device flag. Can be name, identifier or imageIdentifier.
*/
public async getDevice(deviceOption: string): Promise<Mobile.IDevice> {
let device: Mobile.IDevice = null;

if (!device) {
device = _.find(
this.getDeviceInstances(),
(d) =>
(d.deviceInfo.identifier &&
d.deviceInfo.identifier === deviceOption) ||
(d.deviceInfo.displayName &&
d.deviceInfo.displayName === deviceOption) ||
(d.deviceInfo.imageIdentifier &&
d.deviceInfo.imageIdentifier === deviceOption),
);
}
let device = this.findDevice(deviceOption);

if (!device && helpers.isNumberWithoutExponent(deviceOption)) {
device = this.getDeviceByIndex(parseInt(deviceOption, 10));
Expand Down Expand Up @@ -907,6 +916,13 @@ export class DevicesService
}

deviceInitOpts = deviceInitOpts || {};
const deviceOption = deviceInitOpts.deviceId;
if (deviceOption && !helpers.isNumberWithoutExponent(deviceOption)) {
deviceInitOpts = {
...deviceInitOpts,
isRequestedDeviceFound: () => !!this.findDevice(deviceOption),
};
}
this._data = deviceInitOpts;

if (!deviceInitOpts.skipEmulatorStart) {
Expand All @@ -915,13 +931,13 @@ export class DevicesService
}

const platform = deviceInitOpts.platform;
const deviceOption = deviceInitOpts.deviceId;
const deviceLookingOptions: Mobile.IDeviceLookingOptions = {
emulator: deviceInitOpts.emulator,
platform: deviceInitOpts.platform,
shouldReturnImmediateResult: deviceInitOpts.shouldReturnImmediateResult,
detectionInterval: deviceInitOpts.detectionInterval,
fullDiscovery: deviceInitOpts.fullDiscovery,
isRequestedDeviceFound: deviceInitOpts.isRequestedDeviceFound,
};

if (platform && deviceOption) {
Expand Down Expand Up @@ -1198,6 +1214,7 @@ export class DevicesService
shouldReturnImmediateResult: !!shouldReturnImmediateResult,
emulator: !!emulator,
fullDiscovery: deviceInitOpts.fullDiscovery,
isRequestedDeviceFound: deviceInitOpts.isRequestedDeviceFound,
};
}

Expand Down
33 changes: 33 additions & 0 deletions lib/common/test/unit-tests/mobile/devices-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,39 @@ describe("devicesService", () => {
);
});

it("stops waiting for physical devices once the requested simulator is found", async () => {
let waitedForRequestedDevice = false;
(<any>iOSDeviceDiscovery).startLookingForDevices = (
options: Mobile.IDeviceLookingOptions,
) =>
new Promise<void>((resolve) => {
const poll = setInterval(() => {
if (options.isRequestedDeviceFound?.()) {
waitedForRequestedDevice = true;
clearInterval(poll);
resolve();
}
}, 5);
});
(<any>iOSSimulatorDiscovery).startLookingForDevices = async () => {
iOSSimulatorDiscovery.emit(
DeviceDiscoveryEventNames.DEVICE_FOUND,
iOSSimulator,
);
};

await devicesService.initialize({
platform: "ios",
deviceId: iOSSimulator.deviceInfo.identifier,
skipEmulatorStart: true,
});

assert.isTrue(waitedForRequestedDevice);
assert.deepStrictEqual(devicesService.getDeviceInstances(), <any>[
iOSSimulator,
]);
});

describe("when only deviceIdentifier is passed", () => {
const assertAllMethodsResults = async (deviceId: string) => {
assert.isFalse(
Expand Down
39 changes: 39 additions & 0 deletions lib/common/test/unit-tests/mobile/ios-device-operations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { assert } from "chai";
import { isDeviceDiscoveryDone } from "../../../mobile/ios/device/ios-device-operations";

describe("isDeviceDiscoveryDone", () => {
const options = (extra: object = {}) => <any>{ ...extra };

it("ends as soon as the requested device is found", () => {
const isRequestedDeviceFound = () => true;
assert.isTrue(
isDeviceDiscoveryDone(false, 100, options({ isRequestedDeviceFound })),
);
});

it("keeps waiting for the requested device when another one shows up", () => {
const isRequestedDeviceFound = () => false;
assert.isFalse(
isDeviceDiscoveryDone(true, 5000, options({ isRequestedDeviceFound })),
);
});

it("gives other devices time to arrive when none was requested", () => {
assert.isFalse(isDeviceDiscoveryDone(true, 100, options()));
assert.isTrue(isDeviceDiscoveryDone(true, 2000, options()));
});

it("keeps waiting while no device was found", () => {
assert.isFalse(isDeviceDiscoveryDone(false, 5000, options()));
});

it("doesn't end early on a full discovery", () => {
assert.isFalse(
isDeviceDiscoveryDone(true, 5000, options({ fullDiscovery: true })),
);
});

it("works without options", () => {
assert.isTrue(isDeviceDiscoveryDone(true, 2000));
});
});
3 changes: 3 additions & 0 deletions lib/definitions/ios.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ declare global {
platformData: IPlatformData,
projectData: IProjectData,
): string[];
shouldArchiveDeviceBuild(
buildConfig: IBuildConfig & { buildForAppStore?: boolean },
): boolean;
}

interface IXcodebuildCommandService {
Expand Down
6 changes: 6 additions & 0 deletions lib/definitions/project.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,12 @@ interface ICocoaPodsService {
platformData: IPlatformData,
): Promise<void>;

applyPodfileBuildSettings(
projectData: IProjectData,
platformData: IPlatformData,
buildSettings: Record<string, string> | null,
): Promise<void>;

applyPodfileFromExtensions(
projectData: IProjectData,
platformData: IPlatformData,
Expand Down
Loading
Loading