android - react-native 更新导致“属性'resValues'的值无法进一步更改
问题描述
尝试将 React Native 从 0.63.2 升级到 0.65.2 遇到了许多问题,我发现自己在玩 android build wack-a-mole。我试图规避的最新构建错误是:
有一篇现有文章(属性 'resValues' 的值不能再更改。在将 gradle 从 4.1.3 升级到 4.2.1 之后)但是它表明要删除或更新我的项目没有的“heapanalytics”插件.
我试图卸载/重新安装 npm 库“expo-constants”,这似乎是问题发生的地方。
有没有人遇到过类似的问题?或者谁能更好地解释可能导致此问题的原因或解决的潜在步骤?任何帮助或建议表示赞赏!
关于环境的一些附加信息:android > build.gradle
buildscript {
ext {
googlePlayServicesVersion = "15.0.1"
buildToolsVersion = "30.0.2"
minSdkVersion = 23
compileSdkVersion = 30
targetSdkVersion = 30
ndkVersion = "20.1.5948944"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath('com.android.tools.build:gradle:4.2.1')
classpath('com.google.gms:google-services:4.3.3')
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenCentral()
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
maven { url 'https://www.jitpack.io' }
google()
}
}
另外 android > app > build.gradle
apply plugin: "com.android.application"
import com.android.build.OutputFile
project.ext.react = [
enableHermes: false, // clean and rebuild if changing
]
apply from: '../../node_modules/react-native-unimodules/gradle.groovy' // expo unimodules
apply from: "./env.gradle"
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
def enableSeparateBuildPerCPUArchitecture = false
def enableProguardInReleaseBuilds = false
def jscFlavor = 'org.webkit:android-jsc:+'
def enableHermes = project.ext.react.get("enableHermes", false);
android {
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion
signingConfigs { // must come before defaultConfig since defaultConfig references it.
release {
keyAlias = 'totally'
storePassword 'real'
keyPassword 'secret'
storeFile file('stuff.keystore')
}
debug {
keyAlias = 'more'
storePassword 'super'
keyPassword 'secret'
storeFile file('stuff.keystore')
}
}
defaultConfig {
applicationId "com.redacted.someid"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 6
versionName "1.3.0"
signingConfig signingConfigs.release
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
signingConfig signingConfigs.release
}
debug {
signingConfig signingConfigs.debug
}
}
packagingOptions {
pickFirst "lib/armeabi-v7a/libc++_shared.so"
pickFirst "lib/arm64-v8a/libc++_shared.so"
pickFirst "lib/x86/libc++_shared.so"
pickFirst "lib/x86_64/libc++_shared.so"
}
// 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 =
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
}
}
}
dexOptions {
javaMaxHeapSize "4g"
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
implementation 'androidx.appcompat:appcompat:1.1.0'
addUnimodulesDependencies() // expo unimodules
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.implementation
into 'libs'
}
project.ext.vectoricons = [
iconFontNames: [ 'MaterialIcons.ttf' ] // Name of the font files you want to copy
]
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply plugin: 'com.google.gms.google-services'
当然还有 package.json
{
"name": "redacted",
"version": "0.0.1",
"private": true,
"scripts": {
"postinstall": "patch-package && npx jetify",
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"typescriptcheck": "tsc --noEmit --skipLibCheck"
},
"engines": {
"npm": "^6.14.12"
},
"dependencies": {
"@react-native-async-storage/async-storage": "^1.15.8",
"@react-native-community/async-storage": "^1.12.1",
"@react-native-community/datetimepicker": "^3.0.4",
"@react-native-community/masked-view": "0.1.11",
"@react-native-community/progress-bar-android": "^1.0.3",
"@react-native-community/progress-view": "^1.2.2",
"@react-native-community/push-notification-ios": "1.8.0",
"@react-native-firebase/app": "10.4.0",
"@react-native-firebase/messaging": "10.4.0",
"@react-navigation/core": "5.15.3",
"@react-navigation/drawer": "5.12.5",
"@react-navigation/native": "5.9.4",
"@react-navigation/routers": "5.7.2",
"@react-navigation/stack": "5.14.5",
"@types/react-native-app-link": "^1.0.0",
"autolinker": "^3.11.1",
"crypto-js": "^3.1.9-1",
"expo-constants": "^11.0.2",
"expo-screen-capture": "^3.2.0",
"jail-monkey": "^2.3.3",
"jetifier": "^1.6.5",
"moment": "^2.24.0",
"moment-timezone": "^0.5.27",
"patch-package": "^6.2.2",
"react": "17.0.2",
"react-native": "0.65.1",
"react-native-android-open-settings": "^1.3.0",
"react-native-app-link": "^1.0.0",
"react-native-autoheight-webview": "^1.5.4",
"react-native-bootsplash": "^3.1.5",
"react-native-custom-tabs": "^0.1.7",
"react-native-device-info": "^8.0.2",
"react-native-fingerprint-scanner": "^5.0.0",
"react-native-gesture-handler": "1.10.3",
"react-native-keychain": "^4.0.5",
"react-native-localize": "^2.0.2",
"react-native-modal-datetime-picker": "^9.0.0",
"react-native-pdf": "6.2.0",
"react-native-phone-call": "^1.0.9",
"react-native-picker-select": "^6.4.0",
"react-native-reanimated": "1.13.3",
"react-native-safari-view": "^2.1.0",
"react-native-safe-area-context": "3.2.0",
"react-native-screens": "3.4.0",
"react-native-svg": "^12.1.0",
"react-native-unimodules": "^0.14.8",
"react-native-vector-icons": "^7.0.0",
"react-native-webview": "^10.9.2",
"react-redux": "^7.2.0",
"redux": "^4.0.5",
"rn-fetch-blob": "0.12.0",
"rxjs": "^6.5.4",
"tslint": "^5.12.1",
"typescript": "^4.2.2",
"unimodules-barcode-scanner-interface": "^6.1.0",
"unimodules-camera-interface": "^6.1.0",
"unimodules-constants-interface": "^6.1.0",
"unimodules-face-detector-interface": "^6.1.0",
"unimodules-file-system-interface": "^6.1.0",
"unimodules-font-interface": "^6.1.0",
"unimodules-image-loader-interface": "^6.1.0",
"unimodules-permissions-interface": "^6.1.0",
"unimodules-sensors-interface": "^6.1.0",
"uuid": "^3.3.3"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/plugin-transform-strict-mode": "^7.10.4",
"@babel/runtime": "^7.12.5",
"@types/crypto-js": "^3.1.43",
"@types/jest": "25.1.0",
"@types/moment-timezone": "^0.5.12",
"@types/react": "^16.9.43",
"@types/react-native": "^0.63.2",
"@types/react-native-custom-tabs": "^0.1.1",
"@types/react-native-safari-view": "^2.0.4",
"@types/react-native-vector-icons": "^6.4.5",
"@types/react-redux": "^7.1.9",
"@types/react-test-renderer": "^16.9.2",
"@types/remote-redux-devtools": "^0.5.3",
"@types/source-map": "^0.5.7",
"@types/uuid": "^3.4.6",
"babel-jest": "^26.6.3",
"babel-plugin-module-resolver": "^3.2.0",
"jest": "^26.6.3",
"jest-transform-stub": "^2.0.0",
"metro-react-native-babel-preset": "^0.66.0",
"react-native-codegen": "^0.0.7",
"react-native-dotenv": "^0.2.0",
"react-native-typescript-transformer": "^1.2.13",
"react-test-renderer": "17.0.2",
"remote-redux-devtools": "^0.5.16",
"source-map": "^0.7.3",
"ts-jest": "25.1.0"
},
"optionalDependencies": {
"fbjs": "1.0.0",
"fsevents": "1.2.9"
},
"jest": {
"verbose": true,
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(js)$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
"^.+\\.(ts|tsx)$": "ts-jest"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/",
"<rootDir>/ios/",
"<rootDir>/.history/"
],
"cacheDirectory": ".jest/cache",
"moduleNameMapper": {
"^.+.(png)$": "jest-transform-stub"
},
"setupFiles": [
"<rootDir>/jest.setup.js"
]
},
"react-native-unimodules": {
"android": {
"exclude": [
"expo-file-system",
"expo-image-loader",
"expo-permissions"
]
},
"ios": {
"exclude": [
"expo-file-system",
"expo-image-loader",
"expo-permissions"
]
}
}
}
*********** 更新 **********
该问题与处理 .env 和 .env.production 文件有关。虽然下面的代码在以前的迭代中很好,但它在这个版本的 gradle 中抛出了 resValue 错误。(参见循环处理变体,它尝试设置variant.resValue)
安卓 > 应用程序 > env.gradle
dependencies {
implementation 'org.apache.commons:commons-text:1.6'
}
tasks.whenTaskAdded { task ->
if (task.name == 'preDebugBuild') {
task.doFirst {
buildResourceValues('debug')
}
} else if (task.name == 'preReleaseBuild') {
task.doFirst {
buildResourceValues('release')
}
}
}
def buildResourceValues(buildVariant) {
def env = readEnvFile(buildVariant)
android.applicationVariants.all { variant ->
if (variant.name.indexOf(buildVariant) > -1) {
env.each { key, val ->
variant.resValue 'string', key, escapeResourceValue(val)
variant.buildConfigField 'String', key, "\"${groovy.json.StringEscapeUtils.escapeJava(val)}\""
}
}
}
}
def readEnvFile(buildVariant) {
def env = [:]
def envFile = '.env'
if (buildVariant != 'debug') {
envFile = '.env.production'
}
File file = new File("$project.rootDir/../$envFile")
if (file.exists()) {
file.eachLine { line ->
if (line[0] != '#' && line.indexOf('=') > -1) {
def split = line.indexOf('=')
def key = line.substring(0, split)
def val = line.substring(split + 1, line.length())
env.put(key, val)
}
}
}
return env
}
def static escapeResourceValue(str) {
// & and < are automatically escaped, but other chars need to be manually escaped
def escapes = [
"@": "\\@",
"?": "\\?",
"%": "%%",
"\'": "\\'",
"\"": "\\\"",
"\\": "\\\\"
]
def retString = str.replaceAll(/[@?%'"\\]/) {match ->
return escapes[match[0]]
}
return retString
}
解决方案
推荐阅读
- javascript - 获取用户位置并显示数据
- java - 当小部件大小更改时,SWT GridLayout 列不会调整大小
- c# - gRPC 和域驱动设计 - 在哪里放置 proto 文件(域层与其他地方)?
- javascript - 我需要构建一个 onScroll 函数来检测屏幕上最大的 html 元素。基于数组中的 IDS
- java - Spring Security @PreAuthorize 或 @PreFilter
- python - 如何使用 tqdm 在 python 中添加进度条
- visual-studio-code - 没有 Git 的 Visual Studio Code 中的差异突出显示
- django - 为我的 Django (Elastic Beanstalk) 后端 API 配置 SSL (HTTPS)
- typo3 - TypoScriptFrontendController 必须使用有效的 SiteLanguage 对象或当前请求中的已解析站点作为后备来构造。没有给出
- java - 给字段赋值和在构造函数中初始化字段值的区别