react-native-community / cli

The React Native Community CLI - command line tools to help you build RN apps
MIT License
2.4k stars 904 forks source link

run-android on real device using custom flavors #1373

Closed dmitryn closed 1 year ago

dmitryn commented 3 years ago

Ask your Question

Hello,

I didn't open a bug for this as this is more like a question i think.

Running run-android --deviceId=a28385e5 results in ./gradlew build -x lint which is not the command i expect to be running when i have multiple flavors.

For instance, let's assume app has flavors: "dev" and "prod". Then i expect ./gradlew installDevDebug command to be running, but not ./gradlew build -x lint which builds app for every flavor (including "prod" which we don't need).

Here is the custom patch i'm using:

diff --git a/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/index.js b/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/index.js
index 59b7aef..befc5f9 100644
--- a/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/index.js
+++ b/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/index.js
@@ -159,7 +159,7 @@ function runOnSpecificDevice(args, gradlew, packageName, adbPath, androidProject

   if (devices.length > 0 && deviceId) {
     if (devices.indexOf(deviceId) !== -1) {
-      buildApk(gradlew, androidProject.sourceDir);
+      buildApk(gradlew, androidProject.sourceDir, args, androidProject);
       installAndLaunchOnDevice(args, deviceId, packageName, adbPath, androidProject);
     } else {
       _cliTools().logger.error(`Could not find device with the id: "${deviceId}". Please choose one of the following:`, ...devices);
@@ -169,10 +169,31 @@ function runOnSpecificDevice(args, gradlew, packageName, adbPath, androidProject
   }
 }

-function buildApk(gradlew, sourceDir) {
+function getTaskNames(appName, commands) {
+  return appName ? commands.map(command => `${appName}:${command}`) : commands;
+}
+
+function toPascalCase(value) {
+  return value !== '' ? value[0].toUpperCase() + value.slice(1) : value;
+}
+
+function buildApk(gradlew, sourceDir, args, androidProject) {
   try {
-    // using '-x lint' in order to ignore linting errors while building the apk
-    const gradleArgs = ['build', '-x', 'lint'];
+
+    let installTask = "install";
+    const buildType = toPascalCase(args.type) || "Debug";
+
+    if (args.flavor) {
+      installTask += toPascalCase(args.flavor);
+    }
+    installTask += buildType;
+
+    const tasks = args.tasks || [installTask];
+    const gradleArgs = getTaskNames(args.appFolder || androidProject.appName, tasks);
+
+    if (args.port != null) {
+      gradleArgs.push('-PreactNativeDevServerPort=' + args.port);
+    }

     _cliTools().logger.info('Building the app...');

@@ -194,14 +215,18 @@ function tryInstallAppOnDevice(args, adbPath, device, androidProject) {
       appName,
       sourceDir
     } = androidProject;
-    const {
-      appFolder
-    } = args;
-    const variant = args.variant.toLowerCase();
-    const buildDirectory = `${sourceDir}/${appName}/build/outputs/apk/${variant}`;
-    const apkFile = getInstallApkName(appFolder || appName, // TODO: remove appFolder
-    adbPath, variant, device, buildDirectory);
-    const pathToApk = `${buildDirectory}/${apkFile}`;
+    const buildType = args.type || "debug"
+    let buildDirectory = `${sourceDir}/${appName}/build/outputs/apk`;
+    if (args.flavor) {
+      buildDirectory += `/${args.flavor}`;
+    }
+    buildDirectory += `/${buildType}`;
+    let apkFileName = "app";
+    if (args.flavor) {
+      apkFileName += `-${args.flavor}`;
+    }
+    apkFileName += `-${buildType}.apk`
+    const pathToApk = `${buildDirectory}/${apkFileName}`;
     const adbArgs = ['-s', device, 'install', '-r', '-d', pathToApk];

     _cliTools().logger.info(`Installing the app on the device "${device}"...`);
@@ -216,28 +241,6 @@ function tryInstallAppOnDevice(args, adbPath, device, androidProject) {
   }
 }

-function getInstallApkName(appName, adbPath, variant, device, buildDirectory) {
-  const availableCPUs = _adb.default.getAvailableCPUs(adbPath, device); // check if there is an apk file like app-armeabi-v7a-debug.apk
-
-
-  for (const availableCPU of availableCPUs.concat('universal')) {
-    const apkName = `${appName}-${availableCPU}-${variant}.apk`;
-
-    if (_fs().default.existsSync(`${buildDirectory}/${apkName}`)) {
-      return apkName;
-    }
-  } // check if there is a default file like app-debug.apk
-
-
-  const apkName = `${appName}-${variant}.apk`;
-
-  if (_fs().default.existsSync(`${buildDirectory}/${apkName}`)) {
-    return apkName;
-  }
-
-  throw new (_cliTools().CLIError)('Could not find the correct install APK file.');
-}
-
 function installAndLaunchOnDevice(args, selectedDevice, packageName, adbPath, androidProject) {
   (0, _tryRunAdbReverse.default)(args.port, selectedDevice);
   tryInstallAppOnDevice(args, adbPath, selectedDevice, androidProject);
@@ -320,8 +323,11 @@ var _default = {
     description: '[DEPRECATED - root is discovered automatically] Override the root directory for the android build (which contains the android directory)',
     default: ''
   }, {
-    name: '--variant [string]',
-    description: "Specify your app's build variant",
+    name: '--flavor [string]',
+    description: "Specify your app's build flavor"
+  }, {
+    name: '--type [string]',
+    description: "Specify your app's build type",
     default: 'debug'
   }, {
     name: '--appFolder [string]',
diff --git a/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/runOnAllDevices.js b/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/runOnAllDevices.js
index c12c4bb..b91fed3 100644
--- a/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/runOnAllDevices.js
+++ b/node_modules/@react-native-community/cli-platform-android/build/commands/runAndroid/runOnAllDevices.js
@@ -80,7 +80,15 @@ async function runOnAllDevices(args, cmd, packageName, adbPath, androidProject)
   }

   try {
-    const tasks = args.tasks || ['install' + toPascalCase(args.variant)];
+    let installTask = "install";
+    const buildType = toPascalCase(args.type) || "Debug";
+
+    if (args.flavor) {
+      installTask += toPascalCase(args.flavor);
+    }
+    installTask += buildType;
+
+    const tasks = args.tasks || [installTask];
     const gradleArgs = getTaskNames(args.appFolder || androidProject.appName, tasks);

     if (args.port != null) {

The command i'm using with this patch is run-android --deviceId=a28385e5 --flavor=dev which results in this gradle command: ./gradlew app:installDevDebug

I also renamed variant to flavor and added type argument when you want different build type (not "debug" which is default). I think of "variant" more like combination of build flavor and build type so having them separate makes more sense imo https://developer.android.com/studio/build/build-variants?authuser=1

Feel free to use it or modify for your needs.

thymikee commented 3 years ago

Hey, thanks for rising that. We have a PR open that touches similar issues: https://github.com/react-native-community/cli/pull/1055 Would you like to have a look at see how we can get it merged? :)

dmitryn commented 3 years ago

@thymikee thanks for linking the #1055, it looks like it would solve the issue. Not sure how can i help with getting it merged though.

thymikee commented 3 years ago

You could check out the branch locally, rebase to the latest master, and test if building and running android works will all different variants and flavors. You could then report feedback to the original PR so we could improve it. This would be great!

driiftkiing commented 3 years ago

@dmitryn: thanks for you script i have changed the installTask to assemble instead of install. This is more a build task then a install task and consumes less time.

driiftkiing commented 3 years ago

@thymikee: why is the pr #1055 not merged already?

thymikee commented 3 years ago

@driiftkiing it's not rebased, also missing a more thorough review and testing. Help appreciated :)

github-actions[bot] commented 1 year ago

There hasn't been any activity on this issue in the past 3 months, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days.