Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android device management revamp #1262

Merged
merged 14 commits into from
Dec 6, 2023
Merged
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
3 changes: 1 addition & 2 deletions packages/app-harness/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,14 @@
},
"devDependencies": {
"@flexn/assets-renative-outline": "0.3.2",
"@flexn/graybox": "0.21.1",
"@rnv/core": "1.0.0-rc.1",
"@rnv/engine-lightning": "1.0.0-rc.1",
"@rnv/engine-rn": "1.0.0-rc.1",
"@rnv/engine-rn-electron": "1.0.0-rc.1",
"@rnv/engine-rn-next": "1.0.0-rc.1",
"@rnv/engine-rn-tvos": "1.0.0-rc.1",
"@rnv/engine-rn-web": "1.0.0-rc.1",
"@rnv/template-starter": "1.0.0-rc.1",
"@rnv/template-starter": "^1.0.0-rc.1",
"@types/react": "18.2.22",
"@types/react-dom": "18.2.7",
"@types/react-native": "0.72.2",
Expand Down
12 changes: 7 additions & 5 deletions packages/engine-rn-tvos/src/tasks/task.rnv.run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
executeOrSkipTask,
shouldSkipTask,
} from '@rnv/core';
import { packageAndroid, runAndroid } from '@rnv/sdk-android';
import { runXcodeProject, getDeviceToRunOn } from '@rnv/sdk-apple';
import { packageAndroid, runAndroid, getAndroidDeviceToRunOn } from '@rnv/sdk-android';
import { runXcodeProject, getIosDeviceToRunOn } from '@rnv/sdk-apple';
import { startBundlerIfRequired, waitForBundlerIfRequired } from '@rnv/sdk-react-native';

export const taskRnvRun: RnvTaskFn = async (c, parentTask, originTask) => {
Expand All @@ -34,21 +34,23 @@ export const taskRnvRun: RnvTaskFn = async (c, parentTask, originTask) => {
switch (platform) {
case ANDROID_TV:
case FIRE_TV:
// eslint-disable-next-line no-case-declarations
const runDevice = await getAndroidDeviceToRunOn(c);
if (!c.program.only) {
await startBundlerIfRequired(c, TASK_RUN, originTask);
if (bundleAssets) {
await packageAndroid(c);
}
await runAndroid(c);
await runAndroid(c, runDevice!);
if (!bundleAssets) {
logSummary('BUNDLER STARTED');
}
return waitForBundlerIfRequired(c);
}
return runAndroid(c);
return runAndroid(c, runDevice!);
case TVOS:
// eslint-disable-next-line no-case-declarations
const runDeviceArgs = await getDeviceToRunOn(c);
const runDeviceArgs = await getIosDeviceToRunOn(c);
if (!c.program.only) {
await startBundlerIfRequired(c, TASK_RUN, originTask);
await runXcodeProject(c, runDeviceArgs);
Expand Down
12 changes: 7 additions & 5 deletions packages/engine-rn/src/tasks/task.rnv.run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
getConfigProp,
logSummary,
} from '@rnv/core';
import { packageAndroid, runAndroid } from '@rnv/sdk-android';
import { runXcodeProject, getDeviceToRunOn } from '@rnv/sdk-apple';
import { packageAndroid, runAndroid, getAndroidDeviceToRunOn } from '@rnv/sdk-android';
import { runXcodeProject, getIosDeviceToRunOn } from '@rnv/sdk-apple';
import { startBundlerIfRequired, waitForBundlerIfRequired } from '@rnv/sdk-react-native';

export const taskRnvRun: RnvTaskFn = async (c, parentTask, originTask) => {
Expand All @@ -37,7 +37,7 @@ export const taskRnvRun: RnvTaskFn = async (c, parentTask, originTask) => {
case IOS:
case MACOS:
// eslint-disable-next-line no-case-declarations
const runDeviceArgs = await getDeviceToRunOn(c);
const runDeviceArgs = await getIosDeviceToRunOn(c);
if (!c.program.only) {
await startBundlerIfRequired(c, TASK_RUN, originTask);
await runXcodeProject(c, runDeviceArgs);
Expand All @@ -51,18 +51,20 @@ export const taskRnvRun: RnvTaskFn = async (c, parentTask, originTask) => {
case ANDROID_TV:
case FIRE_TV:
case ANDROID_WEAR:
// eslint-disable-next-line no-case-declarations
const runDevice = await getAndroidDeviceToRunOn(c);
if (!c.program.only) {
await startBundlerIfRequired(c, TASK_RUN, originTask);
if (bundleAssets || platform === ANDROID_WEAR) {
await packageAndroid(c);
}
await runAndroid(c);
await runAndroid(c, runDevice!);
if (!bundleAssets) {
logSummary('BUNDLER STARTED');
}
return waitForBundlerIfRequired(c);
}
return runAndroid(c);
return runAndroid(c, runDevice!);
default:
return logErrorPlatform(c);
}
Expand Down
28 changes: 21 additions & 7 deletions packages/sdk-android/src/deviceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const launchAndroidSimulator = async (
if (isIndependentThread) {
execCLI(c, CLI_ANDROID_EMULATOR, `-avd "${actualTarget}"`, {
detached: isIndependentThread,
silent: true,
}).catch((err) => {
if (err.includes && err.includes('WHPX')) {
logWarning(err);
Expand All @@ -95,6 +96,7 @@ export const launchAndroidSimulator = async (
}
return execCLI(c, CLI_ANDROID_EMULATOR, `-avd "${actualTarget}"`, {
detached: isIndependentThread,
silent: true,
});
}
return Promise.reject('No simulator -t target name specified!');
Expand Down Expand Up @@ -467,7 +469,7 @@ const _parseDevicesResult = async (
}
}

if (avdsString) {
if (avdsString && !deviceOnly) {
const avdLines = avdsString.trim().split(/\r?\n/);
logDebug('_parseDevicesResult 7', { avdLines });

Expand Down Expand Up @@ -507,7 +509,11 @@ const _parseDevicesResult = async (
}

if (avdDetails) {
devices.push(device);
// exclude duplicate sims (running ones + avdconfig)
const potentialDuplicate = devices.find((v) => v.name === device.name);
if (!potentialDuplicate || potentialDuplicate.isDevice) {
devices.push(device);
}
}
})
);
Expand Down Expand Up @@ -618,7 +624,7 @@ const waitForEmulatorToBeReady = (c: RnvContext, emulator: string) =>
return res;
});

export const checkForActiveEmulator = (c: RnvContext) =>
export const checkForActiveEmulator = (c: RnvContext, emulatorName?: string) =>
new Promise<AndroidDevice | undefined>((resolve, reject) => {
logTask('checkForActiveEmulator');
const { platform } = c;
Expand All @@ -637,11 +643,19 @@ export const checkForActiveEmulator = (c: RnvContext) =>
running = true;
getAndroidTargets(c, false, true, false)
.then(async (v) => {
logDebug('Available devices after filtering', v);
if (v.length > 0) {
logSuccess(`Found active emulator! ${chalk().white(v[0].udid)}. Will use it`);
const simsOnly = v.filter((device) => !device.isDevice);
logDebug('Available devices after filtering', simsOnly);
if (emulatorName) {
const found = simsOnly.find((v) => v.name === emulatorName);
if (found) {
logSuccess(`Found active emulator! ${chalk().white(found.udid)}. Will use it`);
clearInterval(poll);
resolve(found);
}
} else if (simsOnly.length > 0) {
logSuccess(`Found active emulator! ${chalk().white(simsOnly[0].udid)}. Will use it`);
clearInterval(poll);
resolve(v[0]);
resolve(simsOnly[0]);
} else {
logRaw(`looking for active emulators: attempt ${attempts}/${maxAttempts}`);
attempts++;
Expand Down
104 changes: 52 additions & 52 deletions packages/sdk-android/src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
logTask,
logWarning,
logDebug,
logInfo,
logSuccess,
logRaw,
logError,
Expand Down Expand Up @@ -54,7 +53,7 @@ import {
import { parseGradleWrapperSync } from './gradleWrapperParser';
import { parseValuesStringsSync, injectPluginXmlValuesSync, parseValuesColorsSync } from './xmlValuesParser';
import { ejectGradleProject } from './ejector';
import { Context } from './types';
import { AndroidDevice, Context } from './types';
import {
resetAdb,
getAndroidTargets,
Expand All @@ -75,63 +74,59 @@ export const packageAndroid = async (_c: Context) => {
return true;
};

export const runAndroid = async (c: Context) => {
const { target } = c.program;
const { platform } = c;
export const getAndroidDeviceToRunOn = async (c: Context) => {
const defaultTarget = c.runtime.target;
logTask('runAndroid', `target:${target} default:${defaultTarget}`);
logTask('getAndroidDeviceToRunOn', `default:${defaultTarget}`);

if (!platform) return;
if (!c.platform) return;

const { target, device } = c.program;
const { platform } = c;

await resetAdb(c);

if (target && net.isIP(target.split(':')[0])) {
if (target && typeof target === 'string' && net.isIP(target.split(':')[0])) {
await connectToWifiDevice(c, target);
}

let devicesAndEmulators;
try {
devicesAndEmulators = await getAndroidTargets(c, false, false, c.program.device !== undefined);
} catch (e) {
return Promise.reject(e);
}
const devicesAndEmulators = await getAndroidTargets(c, false, false, !!device);

const activeDevices = devicesAndEmulators.filter((d) => d.isActive);
const inactiveDevices = devicesAndEmulators.filter((d) => !d.isActive);

const askWhereToRun = async () => {
if (activeDevices.length === 0 && inactiveDevices.length > 0) {
// No device active, but there are emulators created
const devicesString = composeDevicesArray(inactiveDevices);
const choices = devicesString;
const response = await inquirerPrompt({
name: 'chosenEmulator',
type: 'list',
message: 'What emulator would you like to start?',
choices,
});
if (response.chosenEmulator) {
await launchAndroidSimulator(c, response.chosenEmulator, true);
const devices = await checkForActiveEmulator(c);
await runReactNativeAndroid(c, platform, devices);
if (activeDevices.length || inactiveDevices.length) {
// No device active and device param is passed, exiting
if (c.program.device && !activeDevices.length) {
return logError('No active devices found, please connect one or remove the device argument', true);
}
} else if (activeDevices.length > 1) {
const devicesString = composeDevicesArray(activeDevices);
const choices = devicesString;

const activeString = composeDevicesArray(activeDevices);
const inactiveString = composeDevicesArray(inactiveDevices);

const choices = [...activeString, ...inactiveString];
const response = await inquirerPrompt({
name: 'chosenEmulator',
type: 'list',
message: 'Where would you like to run your app?',
message: 'What emulator would you like to start?',
choices,
});

if (response.chosenEmulator) {
const dev = activeDevices.find((d) => d.name === response.chosenEmulator);
await runReactNativeAndroid(c, platform, dev);
if (dev) return dev;

await launchAndroidSimulator(c, response.chosenEmulator, true);
const device = await checkForActiveEmulator(c, response.chosenEmulator);
return device;
}
} else {
if (c.program.device) {
return logError('No active devices found, please connect one or remove the device argument', true);
}
await askForNewEmulator(c, platform);
const devices = await checkForActiveEmulator(c);
await runReactNativeAndroid(c, platform, devices);
const device = await checkForActiveEmulator(c);
return device;
}
};

Expand All @@ -141,41 +136,46 @@ export const runAndroid = async (c: Context) => {
const foundDevice = devicesAndEmulators.find((d) => d.udid.includes(target) || d.name.includes(target));
if (foundDevice) {
if (foundDevice.isActive) {
await runReactNativeAndroid(c, platform, foundDevice);
} else {
await launchAndroidSimulator(c, foundDevice, true);
const device = await checkForActiveEmulator(c);
await runReactNativeAndroid(c, platform, device);
return foundDevice;
}
} else {
await askWhereToRun();
await launchAndroidSimulator(c, foundDevice, true);
const device = await checkForActiveEmulator(c, foundDevice.name);
return device;
}
} else if (activeDevices.length === 1) {
// Only one that is active, running on that one
const dv = activeDevices[0];
logInfo(`Found device ${dv.name}:${dv.udid}!`);
await runReactNativeAndroid(c, platform, dv);
logDebug('Target not found, asking where to run');
return askWhereToRun();
} else if (defaultTarget) {
// neither a target nor an active device is found, revert to default target if available
logDebug('Default target used', defaultTarget);
const foundDevice = devicesAndEmulators.find(
(d) => d.udid.includes(defaultTarget) || d.name.includes(defaultTarget)
);

if (!foundDevice) {
logDebug('Target not provided, asking where to run');
await askWhereToRun();
} else {
return askWhereToRun();
} else if (!foundDevice.isActive) {
await launchAndroidSimulator(c, foundDevice, true);
const device = await checkForActiveEmulator(c);
await runReactNativeAndroid(c, platform, device);
const device = await checkForActiveEmulator(c, foundDevice.name);
return device;
}
return foundDevice;
} else {
// we don't know what to do, ask the user
logDebug('Target not provided, asking where to run');
await askWhereToRun();
return askWhereToRun();
}
};

export const runAndroid = async (c: Context, device: AndroidDevice) => {
logTask('runAndroid', `target:${device.udid}`);
const { platform } = c;

if (!platform) return;

await runReactNativeAndroid(c, platform, device);
};

const _checkSigningCerts = async (c: Context) => {
logTask('_checkSigningCerts');
const signingConfig = getConfigProp(c, c.platform, 'signingConfig', 'Debug');
Expand Down
10 changes: 5 additions & 5 deletions packages/sdk-apple/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createRnvApi, createRnvContext } from '@rnv/core';
import type { PromptParams } from "@rnv/core";
import { getDeviceToRunOn } from '../runner';
import { getIosDeviceToRunOn } from '../runner';
import { simctlSimJson, xctraceDevices } from '../__mocks__/data';

beforeEach(() => {
Expand All @@ -14,7 +14,7 @@ afterEach(() => {
jest.clearAllMocks();
});

describe('getDeviceToRunOn', () => {
describe('getIosDeviceToRunOn', () => {
it('should return a device to run on with pick', async () => {
const ctx = getContext();

Expand All @@ -39,7 +39,7 @@ describe('getDeviceToRunOn', () => {
}
});

const deviceArgs = await getDeviceToRunOn(ctx);
const deviceArgs = await getIosDeviceToRunOn(ctx);
expect(executeAsync).toHaveBeenCalledTimes(2);
expect(deviceArgs).toBe('--simulator iPhone\\ 14');
});
Expand All @@ -65,7 +65,7 @@ describe('getDeviceToRunOn', () => {
}
});

const deviceArgs = await getDeviceToRunOn(ctx);
const deviceArgs = await getIosDeviceToRunOn(ctx);
expect(executeAsync).toHaveBeenCalledTimes(2);
expect(deviceArgs).toBe('--simulator iPhone\\ SE\\ (3rd\\ generation)');
});
Expand All @@ -80,7 +80,7 @@ describe('getDeviceToRunOn', () => {
.mockReturnValueOnce(Promise.resolve(xctraceDevices))
.mockReturnValueOnce(Promise.resolve(JSON.stringify(simctlSimJson)));

const deviceArgs = await getDeviceToRunOn(ctx);
const deviceArgs = await getIosDeviceToRunOn(ctx);
expect(executeAsync).toHaveBeenCalledTimes(2);
expect(deviceArgs).toContain('--simulator');
// expect(deviceArgs).toBe('--simulator iPhone\\ 14\\ Plus'); // FIXME: This is failing
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk-apple/src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ const copyAppleAssets = (c: Context, platform: RnvPlatform, appFolderName: strin
resolve();
});

export const getDeviceToRunOn = async (c: Context) => {
logTask('getDeviceToRunOn');
export const getIosDeviceToRunOn = async (c: Context) => {
logTask('getIosDeviceToRunOn');

if (!c.platform) return;

Expand Down
Loading