Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native build error: Text must not be null or empty

My Jenkins build has given me the following error:

13:18:22 FAILURE: Build failed with an exception.
13:18:22 
13:18:22 * Where:
13:18:22 Script '/Users/abcd/Jenkins/Jenkins-Workspaces/ABCD/ABCDL/node_modules/@react-native-community/cli-platform-android/native_modules.gradle' line: 190
13:18:22 
13:18:22 * What went wrong:
13:18:22 A problem occurred evaluating settings 'AppName'.
13:18:22 > Text must not be null or empty
13:18:22 

It seems the problem is with the @react-native-community/cli-platform node module, but reading over this closed issue: https://github.com/facebook/react-native/issues/25479

its unclear to me what exactly is the proposed and final solution to this.

There is a recommendation on a fix that is more straightforward in this react-native issue: https://github.com/facebook/react-native/issues/25822

but my error is not complaining about that line.

As far as installing @react-native-community/cli I believe I already have it inside my package-lock.json file:

"react-native": {
      "version": "0.60.4",
      "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.60.4.tgz",
      "integrity": "sha512-WE41lbGQjnzM9srIFtMDtMJkQAvk95iZwuFvAxl68s80bkYa7Ou9sGFHpeYIV6cY8yHtheCSo5q6YMxhdfkdOw==",
      "requires": {
        "@babel/runtime": "^7.0.0",
        "@react-native-community/cli": "^2.0.1",
        "@react-native-community/cli-platform-android": "^2.0.1",
        "@react-native-community/cli-platform-ios": "^2.0.1",

Others mentioned something about app/build.gradle, here is the relevant part of mine:

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.compile
    into 'libs'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

Mention was also made of android/settings.gradle, this one is mine:

rootProject.name = 'NFIBEngage'
include ':react-native-device-info'
project(':react-native-device-info').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-device-info/android')
include ':appcenter-crashes'
project(':appcenter-crashes').projectDir = new File(rootProject.projectDir, '../node_modules/appcenter-crashes/android')
include ':appcenter-analytics'
project(':appcenter-analytics').projectDir = new File(rootProject.projectDir, '../node_modules/appcenter-analytics/android')
include ':appcenter'
project(':appcenter').projectDir = new File(rootProject.projectDir, '../node_modules/appcenter/android')
include ':react-native-webview'
project(':react-native-webview').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-webview/android')
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

From what I have gathered here:

https://react-native-community.github.io/upgrade-helper/?from=0.53.3&to=0.60.4

The above files are correct.

So what exactly is wrong here and how do I fix it?

In terms of node_modules/@react-native-community/cli-platform-android/native_modules.gradle line 190 is this one:

def json = new JsonSlurper().parseText(reactNativeConfigOutput)

Could the problem be with how I wrote index.js file:

/**
 * @format
 */

import { AppRegistry } from "react-native";
// old config code
import KeyboardManager from "react-native-keyboard-manager";
// old config code ^^^
import NFIBEngage from "./App";
import { name as appName } from "./app.json";

// old config code
import { Sentry } from "react-native-sentry";

Sentry.config(
  "https://[email protected]/123456677"
).install();

KeyboardManager.setToolbarPreviousNextButtonEnable(true);
// old config code ^^^

AppRegistry.registerComponent("NFIBEngage", () => NFIBEngage);

Is AppRegistry.registerComponent() written correctly?

I ran the Jenkins script locally, which I believe is this script right here:

import fs from "fs-extra";
import eachSeries from "async/eachSeries";
import { exec } from "child_process";
import { androidDirectory } from "../../app.json";
import { resolveFromRoot, distDir, createLogger } from "../build";

const logger = createLogger("android");

const APK_PATTERN = /release\.apk$/i;

function copyArtifactsToDist() {
  logger.logHeader("Copying APK to Dist", { repeatChar: "=" });
  const baseDir = `${androidDirectory}/app/build/outputs/apk`;

  const allFlavs = ["dev", "qa", "ua", "prod"];
  const branchName = process.env.GitVersion_BranchName || "";
  const buildFlavour = branchName.startsWith("release/") ? allFlavs : ["dev"];
  const envs = {
    dev: "INT",
    qa: "QA",
    ua: "UA",
    prod: ""
  };

  buildFlavour
    .map(env => {
      const apkOutputDir = resolveFromRoot(`${baseDir}/${env}/release`);
      return {
        apkOutputDir,
        env
      };
    })
    .forEach(({ apkOutputDir, env }) => {
      const src = `${apkOutputDir}/app-${env}-release.apk`;
      //prettier-ignore
      const binaryName = env === 'prod' ? 'ENGAL.apk' : `ENGAL-${envs[env]}.apk`;
      const dest = `${distDir}/${binaryName}`;
      fs.copy(src, dest, (err: Error) => {
        if (err) {
          logger.error(err);
        }
      });
    });
}

function run() {
  logger.logHeader("Starting Android Builds", { repeatChar: "#" });
  const flavours = [
    {
      endpoint: "dv",
      flavour: "Dev",
      appcenterKey: "<hashKeys>"
    },
    {
      endpoint: "qa",
      flavour: "Qa",
      appcenterKey: "<hashKeys>"
    },
    {
      endpoint: "ua",
      flavour: "Ua",
      appcenterKey: "<hashKeys>"
    },
    {
      endpoint: "prod",
      flavour: "Prod",
      appcenterKey: "<hashKeys>"
    }
  ];

  const versionCode = process.env.Build || 1;
  const release = process.env.GitVersion_MajorMinorPatch || "1.0.0";
  const fullAppVersion = `${release}-${versionCode}`;

  const devFlav = flavours.find(f => f.flavour.toLocaleLowerCase() === "dev");

  const branchName = process.env.GitVersion_BranchName || "";
  const buildFlavour = branchName.startsWith("release/") ? flavours : [devFlav];

  eachSeries(
    buildFlavour,
    (f, callback) => {
      //prettier-ignore
      logger.logHeader(
        `starting gradle assemble${f.flavour}Release with flag - versionName=${fullAppVersion} -PversionCode=${versionCode}`,
        {repeatChar: '-'}
      );

      const engaInfo = `ENGAGE_VERSION=${fullAppVersion}`;
      const engaEndpoint = `ENGAGE_ENDPOINT=${f.endpoint}`;
      const engaCenter = `APPCENTER_KEY=${f.appcenterKey}`;
      const engaPlatform = "APPCENTER_PLATFORM=android";
      //prettier-ignore
      const prepare = `${engaEndpoint} ${engaCenter} ${engaInfo} ${engaPlatform} npm run setup`;
      const cd = `cd ${androidDirectory}`;
      //prettier-ignore
      const releaseCmd = `./gradlew assemble${f.flavour}Release -PversionName=${fullAppVersion} -PversionCode=${versionCode} && cd ..`;

      exec(`${prepare} && ${cd} && ${releaseCmd}`, err => {
        if (err) {
          return callback(err);
        }

        logger.logHeader(`${f.flavour} Android Build Successful!`, {
          repeatChar: "#"
        });
        logger.close();
        callback(null);
      });
    },
    error => {
      if (error) {
        logger.logHeader("Android Builds Failed!", {
          repeatChar: "#"
        });
        logger.error(error);
        logger.close();
      }
      copyArtifactsToDist();
    }
  );
}

run();

via npm run build and locally I got this error:

FAILURE: Build failed with an exception.

* What went wrong:
Task 'assembleDevRelease' not found in root project 'AppName'. Some candidates are: 'assembleRelease'.

Are these related errors? Anyone experienced with React Native builds?

As suggested, I looked into my android/app/build.gradle file for productFlavors and noticed that indeed they were missing between here:

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.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // https://developer.android.com/studio/build/configure-apk-splits.html
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 123456 + defaultConfig.versionCode
            }

        }
    }

So I added it like so:

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.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

    productFlavors {
      dev {
        resValue "string", "app_name", getAppName("INT")
        resValue "string", "link_launcher", getLauncher("dv")
        applicationIdSuffix ".dv"
        manifestPlaceholders = [onesignal_app_id: "<hash_id>",
                                onesignal_google_project_number: "123456789"]
      }
      qa {
        resValue "string", "app_name", getAppName("QA")
        resValue "string", "link_launcher", getLauncher("qa")
        applicationIdSuffix ".qa"
        manifestPlaceholders = [onesignal_app_id: "<hash_id>",
                                onesignal_google_project_number: "123456789"]
      }
      ua {
        resValue "string", "app_name", getAppName("UA")
        resValue "string", "link_launcher", getLauncher("ua")
        applicationIdSuffix ".ua"
        manifestPlaceholders = [onesignal_app_id: "<hash_id>",
                                onesignal_google_project_number: "123456789"]
      }
      prod {
        resValue "string", "app_name", getAppName()
        resValue "string", "link_launcher", getLauncher()
        manifestPlaceholders = [onesignal_app_id: "<hash_id>",
                                onesignal_google_project_number: "601125149914"]
      }
    }

    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // https://developer.android.com/studio/build/configure-apk-splits.html
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
            }

        }
    }

The buildTypes is looking a bit different than the original legacy buildTypes so I am not sure if that's okay, but at any rate I then ran npm run build again locally and got this error:

* Where:
Build file '/Users/danale/Projects/NFIBEngage/android/app/build.gradle' line: 168

* What went wrong:
A problem occurred evaluating project ':app'.
> Could not find method getAppName() for arguments [INT] on ProductFlavor_Decorated{name=dev, dimension=null, minSdkVersion=null, targetSdkVersion=null, renderscriptTargetApi=null, renderscriptSupportModeEnabled=null, renderscriptSupportModeBlasEnabled=null, renderscriptNdkModeEnabled=null, versionCode=null, versionName=null, applicationId=null, testApplicationId=null, testInstrumentationRunner=null, testInstrumentationRunnerArguments={}, testHandleProfiling=null, testFunctionalTest=null, signingConfig=null, resConfig=null, mBuildConfigFields={}, mResValues={}, mProguardFiles=[], mConsumerProguardFiles=[], mManifestPlaceholders={}, mWearAppUnbundled=null} of type com.android.build.gradle.internal.dsl.ProductFlavor.

I was able to resolve the local error by adding the missing methods like so:

def appName = "Engage";

/**
 * Get the version name from command line param
 *
 * @return int If the param -PversionName is present then return int value or -1
 */
def getAppName = { env ->
  return (env ? appName + " ("+ env + ")" : appName);
}

/**
 * Get the version name from command line param
 *
 * @return int If the param -PversionName is present then return int value or -1
 */
def getLauncher = { env ->
    return (env ? "engage-" + env + ".nfib.org" : "engage.nfib.org");
}

android {
    compileSdkVersion rootProject.ext.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    flavorDimensions "default"

    defaultConfig {
        applicationId "com.nfib.engage"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    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.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

    productFlavors {
      dev {
        dimension 'default'
        resValue "string", "app_name", getAppName("INT")
        resValue "string", "link_launcher", getLauncher("dv")
        applicationIdSuffix ".dv"
        manifestPlaceholders = [onesignal_app_id: "b78285eb-f1ec-46f3-9ad0-c7efe691a401",
                                onesignal_google_project_number: "584236827312"]
      }
      qa {
        dimension 'default'
        resValue "string", "app_name", getAppName("QA")
        resValue "string", "link_launcher", getLauncher("qa")
        applicationIdSuffix ".qa"
        manifestPlaceholders = [onesignal_app_id: "e4280f5e-62ec-41a4-bd86-f5b94e471a36",
                                onesignal_google_project_number: "162802054510"]
      }
      ua {
        dimension 'default'
        resValue "string", "app_name", getAppName("UA")
        resValue "string", "link_launcher", getLauncher("ua")
        applicationIdSuffix ".ua"
        manifestPlaceholders = [onesignal_app_id: "2ffd8dc0-9c6b-4035-999d-fc694194725a",
                                onesignal_google_project_number: "594905904045"]
      }
      prod {
        dimension 'default'
        resValue "string", "app_name", getAppName()
        resValue "string", "link_launcher", getLauncher()
        manifestPlaceholders = [onesignal_app_id: "82dcb42f-1d35-4b79-bc28-2d1d02dbda36",
                                onesignal_google_project_number: "601125149914"]
      }
    }

Unfortunately, I continue to get the same error in Jenkins.

like image 944
Daniel Avatar asked Jul 31 '19 19:07

Daniel


1 Answers

Some of the changes to get the build working, from comments:

From your package.json, your cli version is at ^2.0.1 and 2.0.1 is indeed the version of the cli that had the issue you linked to from github.com/facebook/react-native/issues/25479 Have you verified that the line similar to def command = "../node_modules/.bin/react-native config" (from github.com/facebook/react-native/issues/…) in your node_modules/@react-native-community/cli-platform-android/native_modules.gradle is correct? You should also ensure your installed version of the cli is >= 2.0.2.

Make sure your buildTypes and productFlavors definitions in android/app/build.gradle are set up to include all the different variants you are trying to build in your jenkins job. Looks like you have flavors for dev, qa, ua and prod. Check out the gradle docs developer.android.com/studio/build/build-variants#build-types for more info.

Looks like you're missing a getAppName function in your build.gradle. Something like ext.getAppName = {suffix = '' -> 'MyAppName' + suffix}. A quick scan of your build.gradle looks like you need another called getLauncher which returns an appropriate string for whatever you use link_launcher for.

like image 65
azundo Avatar answered Nov 01 '22 01:11

azundo