我的 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"]
}
}
不幸的是,我在詹金斯中继续遇到同样的错误。