React Native 构建错误:文本不能为 null 或为空

2024-07-04

我的 Jenkins 构建给了我以下错误:

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 

看来问题出在@react-native-community/cli-platform节点模块,但阅读这个已关闭的问题:https://github.com/facebook/react-native/issues/25479 https://github.com/facebook/react-native/issues/25479

我不清楚这个问题的提议和最终解决方案到底是什么。

在这个反应原生问题中,有一个更直接的修复建议:https://github.com/facebook/react-native/issues/25822 https://github.com/facebook/react-native/issues/25822

但我的错误不是抱怨那条线。

就安装而言@react-native-community/cli我相信我已经拥有它了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",

其他人提到了一些关于app/build.gradle,这是我的相关部分:

// 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)

还提到了android/settings.gradle,这是我的:

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'

根据我在这里收集到的信息:

上述文件是正确的。

那么这里到底出了什么问题以及如何解决它?

按照node_modules/@react-native-community/cli-platform-android/native_modules.gradle line 190是这个吗:

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

问题可能出在我编写index.js 文件的方式上:

/**
 * @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] /cdn-cgi/l/email-protection/123456677"
).install();

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

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

Is AppRegistry.registerComponent()写对了吗?

我在本地运行了 Jenkins 脚本,我相信这个脚本就在这里:

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在本地我得到了这个错误:

FAILURE: Build failed with an exception.

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

这些是相关错误吗?有人对 React Native 构建有经验吗?

按照建议,我查看了我的android/app/build.gradle归档productFlavors并注意到他们确实在这里失踪了:

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
            }

        }
    }

所以我像这样添加了它:

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看起来与原来的遗产有点不同buildTypes所以我不确定这是否可以,但无论如何我然后跑了npm run build再次本地并出现此错误:

* 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.

我能够通过添加缺少的方法来解决本地错误,如下所示:

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"]
      }
    }

不幸的是,我在詹金斯中继续遇到同样的错误。


来自评论的一些使构建工作的更改:

从你的 package.json 中,你的 cli 版本位于^2.0.1 and 2.0.1确实是存在您从 github.com/facebook/react-native/issues/25479 链接到的问题的 cli 版本,您是否已验证该行类似于def command = "../node_modules/.bin/react-native config"(来自 github.com/facebook/react-native/issues/...)在你的node_modules/@react-native-community/cli-platform-android/native_modules.gradle是正确的?您还应该确保您安装的 cli 版本 >=2.0.2.

确保您的buildTypes and productFlavors中的定义android/app/build.gradle设置为包含您尝试在詹金斯工作中构建的所有不同变体。看起来你有以下口味dev, qa, ua and prod。查看 gradle 文档developer.android.com/studio/build/build-variants#build-types 了解更多信息。

看起来您缺少一个getAppName功能在你的build.gradle。就像是ext.getAppName = {suffix = '' -> 'MyAppName' + suffix}。快速扫描您的build.gradle看起来你需要另一个叫getLauncher它会为您使用的任何内容返回适当的字符串link_launcher for.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React Native 构建错误:文本不能为 null 或为空 的相关文章

随机推荐