Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ async function buildAndRun(args: Flags, androidProject: AndroidProject) {
}
}

function runOnSpecificDevice(
async function runOnSpecificDevice(
args: Flags,
adbPath: string,
androidProject: AndroidProject,
Expand Down Expand Up @@ -265,7 +265,7 @@ function runOnSpecificDevice(
build(gradleArgs, androidProject.sourceDir);
}

installAndLaunchOnDevice(
await installAndLaunchOnDevice(
args,
device,
adbPath,
Expand All @@ -283,7 +283,7 @@ function runOnSpecificDevice(
}
}

function installAndLaunchOnDevice(
async function installAndLaunchOnDevice(
args: Flags,
selectedDevice: string,
adbPath: string,
Expand All @@ -292,7 +292,7 @@ function installAndLaunchOnDevice(
) {
tryRunAdbReverse(args.port, selectedDevice);

tryInstallAppOnDevice(
await tryInstallAppOnDevice(
args,
adbPath,
selectedDevice,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,13 @@ async function runOnAllDevices(
throw createInstallError(error as any);
}

(devices.length > 0 ? devices : [undefined]).forEach(
(device: string | void) => {
tryRunAdbReverse(args.port, device);
if (args.binaryPath && device) {
tryInstallAppOnDevice(args, adbPath, device, androidProject);
}
tryLaunchAppOnDevice(device, androidProject, adbPath, args);
},
);
for (const device of devices.length > 0 ? devices : [undefined]) {
tryRunAdbReverse(args.port, device);
if (args.binaryPath && device) {
await tryInstallAppOnDevice(args, adbPath, device, androidProject);
}
tryLaunchAppOnDevice(device, androidProject, adbPath, args);
}
}

function createInstallError(error: Error & {stderr: string}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import execa from 'execa';
import fs from 'fs';
import {logger, CLIError} from '@react-native-community/cli-tools';
import {logger, CLIError, prompt} from '@react-native-community/cli-tools';

import adb from './adb';
import type {AndroidProject, Flags} from './';

function tryInstallAppOnDevice(
async function tryInstallAppOnDevice(
args: Flags,
adbPath: string,
device: string,
Expand Down Expand Up @@ -34,7 +34,7 @@ function tryInstallAppOnDevice(
const variantAppName =
variantFromSelectedTask?.join('-')?.toLowerCase() ?? defaultVariant;

let pathToApk;
let pathToApk: string;
if (!args.binaryPath) {
const buildDirectory = `${sourceDir}/${appName}/build/outputs/apk/${variantPath}`;
const apkFile = getInstallApkName(
Expand All @@ -49,14 +49,33 @@ function tryInstallAppOnDevice(
pathToApk = args.binaryPath;
}

const installArgs = ['-s', device, 'install', '-r', '-d'];
if (args.user !== undefined) {
installArgs.push('--user', `${args.user}`);
const install = () => {
const installArgs = ['-s', device, 'install', '-r', '-d'];
if (args.user !== undefined) {
installArgs.push('--user', `${args.user}`);
}
const adbArgs = [...installArgs, pathToApk];
logger.info(`Installing the app on the device "${device}"...`);
logger.debug(`Running command "cd android && adb ${adbArgs.join(' ')}"`);
execa.sync(adbPath, adbArgs, {stdio: ['inherit', 'inherit', 'pipe']});
};

try {
install();
} catch (error) {
const stderr = ((error as any).stderr || '').toString();
logger.log(stderr);
if (!stderr.includes('INSTALL_FAILED_VERSION_DOWNGRADE')) {
throw error;
}
await handleVersionDowngrade(
args,
adbPath,
device,
androidProject,
install,
);
}
const adbArgs = [...installArgs, pathToApk];
logger.info(`Installing the app on the device "${device}"...`);
logger.debug(`Running command "cd android && adb ${adbArgs.join(' ')}"`);
execa.sync(adbPath, adbArgs, {stdio: 'inherit'});
} catch (error) {
throw new CLIError(
'Failed to install the app on the device.',
Expand All @@ -65,6 +84,42 @@ function tryInstallAppOnDevice(
}
}

async function handleVersionDowngrade(
args: Flags,
adbPath: string,
device: string,
androidProject: AndroidProject,
install: () => void,
) {
const {reinstall}: {reinstall: boolean} = await prompt({
type: 'confirm',
name: 'reinstall',
message:
'The app installed on the device has a newer version than the one being installed. Do you want to uninstall the existing app and install again?',
initial: false,
});

if (!reinstall) {
throw new Error('Installation cancelled: INSTALL_FAILED_VERSION_DOWNGRADE');
}

const applicationId = [
args.appId || androidProject.applicationId,
args.appIdSuffix,
]
.filter(Boolean)
.join('.');
const uninstallArgs = ['-s', device, 'uninstall'];
if (args.user !== undefined) {
uninstallArgs.push('--user', `${args.user}`);
}
uninstallArgs.push(applicationId);
logger.info(`Uninstalling "${applicationId}" from the device "${device}"...`);
logger.debug(`Running command "adb ${uninstallArgs.join(' ')}"`);
execa.sync(adbPath, uninstallArgs, {stdio: 'inherit'});
install();
}

function getInstallApkName(
appName: string,
adbPath: string,
Expand Down
Loading