cli
cli copied to clipboard
react-native run-android: Failed to install the app on the device. Error: Could not find the correct install APK file.
Environment
System:
OS: macOS 14.3.1
CPU: (10) arm64 Apple M1 Pro
Memory: 114.36 MB / 32.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 18.19.0
path: /private/var/folders/08/rddrn4196_bdkhcgpttbsqlm0000gn/T/xfs-a2802977/node
Yarn:
version: 3.4.1
path: /private/var/folders/08/rddrn4196_bdkhcgpttbsqlm0000gn/T/xfs-a2802977/yarn
npm:
version: 10.4.0
path: ~/.nvm/versions/node/v18.19.0/bin/npm
Watchman:
version: 2024.01.22.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.15.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 23.4
- iOS 17.4
- macOS 14.4
- tvOS 17.4
- visionOS 1.1
- watchOS 10.4
Android SDK:
API Levels:
- "30"
- "33"
- "34"
Build Tools:
- 30.0.3
- 33.0.0
- 33.0.1
- 34.0.0
System Images:
- android-33 | Google APIs ARM 64 v8a
- android-34 | Google APIs ARM 64 v8a
Android NDK: Not Found
IDEs:
Android Studio: 2023.2 AI-232.10227.8.2321.11479570
Xcode:
version: 15.3/15E204a
path: /usr/bin/xcodebuild
Languages:
Java:
version: 21.0.1
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.73.5
wanted: ^0.73.5
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: false
iOS:
hermesEnabled: true
newArchEnabled: false
Description
Issue is same as reported earlier in #921, but marked PR did not fix the issue.
npx react-native run-android fails with Failed to install the app on the device. Error: Could not find the correct install APK file. when using flavors.
productFlavors {
pro {
dimension = 'version'
applicationId = 'com.ezmonic'
applicationIdSuffix = 'pro'
resValue "string", "app_name", "Ezmonic"
}
free {
dimension = 'version'
applicationId = 'com.ezmonic'
resValue "string", "app_name", "Ezmonic Free"
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://facebook.github.io/react-native/docs/signed-apk-android.
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
$ yarn react-native run-android --deviceId=emulator-5554 --mode=freeDebug --appIdSuffix=free
info A dev server is already running for this project on port 8081.
info Building the app...
> Configure project :app
Reading env from: .env.development
Reading from .env
...
> Task :app:installFreeDebug
Installing APK 'app-free-debug.apk' on 'Pixel_7_Pro_API_34(AVD) - 14' for :app:free-debug
Installed on 1 device.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to https://docs.gradle.org/8.3/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
BUILD SUCCESSFUL in 13s
465 actionable tasks: 18 executed, 447 up-to-date
info Connecting to the development server...
8081
error Failed to install the app on the device.
Error: Could not find the correct install APK file.
Reproducible Demo
Error is coming from the following lines in
Issue lies in tryInstallAppOnDevice() function. Use case is when build is triggered using non-interactive manner, via Terminal command, yarn react-native run-android --deviceId=emulator-5554 --mode=freeDebug --appIdSuffix=free. As per code, split is done only for selectedTask, which is populated in case of interactive mode, but not for args.mode, which is one of the input during manual build.
function tryInstallAppOnDevice(
args: Flags,
adbPath: string,
device: string,
androidProject: AndroidProject,
selectedTask?: string,
) {
try {
// "app" is usually the default value for Android apps with only 1 app
const {appName, sourceDir} = androidProject;
const defaultVariant = (args.mode || 'debug').toLowerCase();
// handle if selected task from interactive mode includes build flavour as well, eg. installProductionDebug should create ['production','debug'] array
const variantFromSelectedTask = selectedTask
?.replace('install', '')
.split(/(?=[A-Z])/);
// create path to output file, eg. `production/debug`
const variantPath =
variantFromSelectedTask?.join('/')?.toLowerCase() ?? defaultVariant;
// create output file name, eg. `production-debug`
const variantAppName =
variantFromSelectedTask?.join('-')?.toLowerCase() ?? defaultVariant;
let pathToApk;
if (!args.binaryPath) {
const buildDirectory = `${sourceDir}/${appName}/build/outputs/apk/${variantPath}`;
const apkFile = getInstallApkName(
appName,
adbPath,
variantAppName,
device,
buildDirectory,
);
pathToApk = `${buildDirectory}/${apkFile}`;
} else {
pathToApk = args.binaryPath;
}
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'});
} catch (error) {
throw new CLIError(
'Failed to install the app on the device.',
error as any,
);
}
}