首页 > 解决方案 > react-native 更新导致“属性'resValues'的值无法进一步更改

问题描述

尝试将 React Native 从 0.63.2 升级到 0.65.2 遇到了许多问题,我发现自己在玩 android build wack-a-mole。我试图规避的最新构建错误是:

无法进一步更改属性“resValues”的值

有一篇现有文章(属性 '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
}

标签: androidreact-nativegradlecompiler-errors

解决方案


推荐阅读