web-dev-qa-db-ja.com

React Native:Error:Duplicate resources-Android

Android=からリリースapkファイルを作成しようとしましたが、PNG画像でリリースapkを作成するとDuplicate Resourceエラーが発生します。最初にこれは、既存のプロジェクトの間違いですが、単一のImageコンポーネント自体で新しいプロジェクトを作成したときに、Duplicate Resourceエラーが発生します。

  1. アプリを作成-react-native init demo
  2. プロジェクトのルートフォルダーにアセットフォルダーを作成します。
  3. アセットフォルダ内にPNG画像を追加します。
  4. 次に、上記のImageイメージを使用してPNGコンポーネントを実装します。
  5. 次に、cmdを使用してバンドルします

    react-native bundle --platform Android --dev false --entry-file index.js --bundle-output Android/app/src/main/assets/index.Android.bundle --assets-dest Android/app/src/main/res/

  6. 次に、Generate Signed APKからAndroid Studioを使用してリリースAPKを生成します。

これにより、次のエラーがスローされます。

[drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/Android/app/src/main/res/drawable-mdpi/assets_mario.png [drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/Android/app/build/generated/res/react/release/drawable-mdpi-v4/assets_mario.png: Error: Duplicate resources
:app:mergeReleaseResources FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:mergeReleaseResources'.
> [drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/Android/app/src/main/res/drawable-mdpi/assets_mario.png   [drawable-mdpi-v4/assets_mario] /Users/jeffreyrajan/Tutorials/RN/errorCheck/Android/app/build/generated/res/react/release/drawable-mdpi-v4/assets_mario.png: Error: Duplicate resources

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 22s

注:PNG画像なしでrelease apkを生成しても、エラーは発生せず、release apkが作成されます。

ここに他のファイルコードがあります。

App.js

import React, {Component} from 'react';
import {Platform, StyleSheet, Image, View} from 'react-native';

export default class App extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Image source={require('./assets/mario.png')} />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

package.json

{
  "name": "errorCheck",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "test": "jest"
  },
  "dependencies": {
    "react": "16.6.0-alpha.8af6728",
    "react-native": "0.57.4"
  },
  "devDependencies": {
    "babel-jest": "23.6.0",
    "jest": "23.6.0",
    "metro-react-native-babel-preset": "0.49.0",
    "react-test-renderer": "16.6.0-alpha.8af6728"
  },
  "jest": {
    "preset": "react-native"
  }
}

これに対する解決策はありますか?

更新:

その他の詳細はこちら

classpath 'com.Android.tools.build:gradle:3.1.4'

ext {
        buildToolsVersion = "27.0.3"
        minSdkVersion = 16
        compileSdkVersion = 27
        targetSdkVersion = 26
        supportLibVersion = "27.1.1"
    }

distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.Zip

Android Studio 3.0, 3.0.1, 3.1, 3.1.4 & 3.2で試しました

18
Jeffrey Rajan

多くの解決策を試した後、2つの解決策のみが機能していることがわかりました。どうぞ

ソリューション1:

バンドルした後、drawableフォルダをAndroid Studioから削除します。これはAndroid/app/src/main/res/drawableで見つけることができます

ソリューション2:

元の作成者の提案に従って、ソリューション#2を使用しないでください!node_modulesの下のすべてのパッケージが生成されます。 react-nativeパッケージを再インストール/アップグレードすると失われます。

このソリューションでは、ドローアブルフォルダーを削除する必要はありません。 react.gradleファイルにnode_modules/react-native/react.gradleパスの下にある次のコードを追加するだけです

doLast {
    def moveFunc = { resSuffix ->
        File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
        if (originalDir.exists()) {
            File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
            ant.move(file: originalDir, tofile: destDir);
        }
    }
    moveFunc.curry("ldpi").call()
    moveFunc.curry("mdpi").call()
    moveFunc.curry("hdpi").call()
    moveFunc.curry("xhdpi").call()
    moveFunc.curry("xxhdpi").call()
    moveFunc.curry("xxxhdpi").call()
}

参考のために、ここに完全なreact.gradleファイルコードを追加します

import org.Apache.tools.ant.taskdefs.condition.Os

def config = project.hasProperty("react") ? project.react : [];

def cliPath = config.cliPath ?: "node_modules/react-native/local-cli/cli.js"
def bundleAssetName = config.bundleAssetName ?: "index.Android.bundle"
def entryFile = config.entryFile ?: "index.Android.js"
def bundleCommand = config.bundleCommand ?: "bundle"
def reactRoot = file(config.root ?: "../../")
def inputExcludes = config.inputExcludes ?: ["Android/**", "ios/**"]
def bundleConfig = config.bundleConfig ? "${reactRoot}/${config.bundleConfig}" : null ;


afterEvaluate {
    Android.applicationVariants.all { def variant ->
        // Create variant and target names
        def targetName = variant.name.capitalize()
        def targetPath = variant.dirName

        // React js bundle directories
        def jsBundleDir = file("$buildDir/generated/assets/react/${targetPath}")
        def resourcesDir = file("$buildDir/generated/res/react/${targetPath}")

        def jsBundleFile = file("$jsBundleDir/$bundleAssetName")

        // Additional node and packager commandline arguments
        def nodeExecutableAndArgs = config.nodeExecutableAndArgs ?: ["node"]
        def extraPackagerArgs = config.extraPackagerArgs ?: []

        def currentBundleTask = tasks.create(
            name: "bundle${targetName}JsAndAssets",
            type: Exec) {
            group = "react"
            description = "bundle JS and assets for ${targetName}."

            // Create dirs if they are not there (e.g. the "clean" task just ran)
            doFirst {
                jsBundleDir.deleteDir()
                jsBundleDir.mkdirs()
                resourcesDir.deleteDir()
                resourcesDir.mkdirs()
            }

            doLast {
                def moveFunc = { resSuffix ->
                    File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
                    if (originalDir.exists()) {
                        File destDir = file("$buildDir/../src/main/res/drawable-${resSuffix}");
                        ant.move(file: originalDir, tofile: destDir);
                    }
                }
                moveFunc.curry("ldpi").call()
                moveFunc.curry("mdpi").call()
                moveFunc.curry("hdpi").call()
                moveFunc.curry("xhdpi").call()
                moveFunc.curry("xxhdpi").call()
                moveFunc.curry("xxxhdpi").call()
            }

            // Set up inputs and outputs so gradle can cache the result
            inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
            outputs.dir jsBundleDir
            outputs.dir resourcesDir

            // Set up the call to the react-native cli
            workingDir reactRoot

            // Set up dev mode
            def devEnabled = !(config."devDisabledIn${targetName}"
                || targetName.toLowerCase().contains("release"))

            def extraArgs = extraPackagerArgs;

            if (bundleConfig) {
                extraArgs = extraArgs.clone()
                extraArgs.add("--config");
                extraArgs.add(bundleConfig);
            }

            if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                commandLine("cmd", "/c", *nodeExecutableAndArgs, cliPath, bundleCommand, "--platform", "Android", "--dev", "${devEnabled}",
                    "--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraArgs)
            } else {
                commandLine(*nodeExecutableAndArgs, cliPath, bundleCommand, "--platform", "Android", "--dev", "${devEnabled}",
                    "--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraArgs)
            }

            enabled config."bundleIn${targetName}" ||
                config."bundleIn${variant.buildType.name.capitalize()}" ?:
                targetName.toLowerCase().contains("release")
        }

        // Expose a minimal interface on the application variant and the task itself:
        variant.ext.bundleJsAndAssets = currentBundleTask
        currentBundleTask.ext.generatedResFolders = files(resourcesDir).builtBy(currentBundleTask)
        currentBundleTask.ext.generatedAssetsFolders = files(jsBundleDir).builtBy(currentBundleTask)

        // registerGeneratedResFolders for Android plugin 3.x
        if (variant.respondsTo("registerGeneratedResFolders")) {
            variant.registerGeneratedResFolders(currentBundleTask.generatedResFolders)
        } else {
            variant.registerResGeneratingTask(currentBundleTask)
        }
        variant.mergeResources.dependsOn(currentBundleTask)

        // packageApplication for Android plugin 3.x
        def packageTask = variant.hasProperty("packageApplication")
            ? variant.packageApplication
            : tasks.findByName("package${targetName}")

        def resourcesDirConfigValue = config."resourcesDir${targetName}"
        if (resourcesDirConfigValue) {
            def currentCopyResTask = tasks.create(
                name: "copy${targetName}BundledResources",
                type: Copy) {
                group = "react"
                description = "copy bundled resources into custom location for ${targetName}."

                from resourcesDir
                into file(resourcesDirConfigValue)

                dependsOn(currentBundleTask)

                enabled currentBundleTask.enabled


            }

            packageTask.dependsOn(currentCopyResTask)
        }

        def currentAssetsCopyTask = tasks.create(
            name: "copy${targetName}BundledJs",
            type: Copy) {
            group = "react"
            description = "copy bundled JS into ${targetName}."

            if (config."jsBundleDir${targetName}") {
                from jsBundleDir
                into file(config."jsBundleDir${targetName}")
            } else {
                into ("$buildDir/intermediates")
                into ("assets/${targetPath}") {
                    from jsBundleDir
                }

                // Workaround for Android Gradle Plugin 3.2+ new asset directory
                into ("merged_assets/${targetPath}/merge${targetName}Assets/out") {
                    from jsBundleDir
                }
            }

            // mergeAssets must run first, as it clears the intermediates directory
            dependsOn(variant.mergeAssets)

            enabled currentBundleTask.enabled
        }

        packageTask.dependsOn(currentAssetsCopyTask)
    }
}

クレジット: ZeroCoolmkchx

52
Jeffrey Rajan

このソリューションは私のために働きます

rm -rf ./Android/app/src/main/res/drawable-*

rm -rf ./Android/app/src/main/res/raw
19
tolotra

デバッグapkを生成する場合

"debug-build": "react-native bundle --platform Android --dev false --entry-file index.js --bundle-output Android/app/src/main/assets/index.Android.bundle --assets-dest Android/app/src/main/res/ && cd Android && ./gradlew assembleDebug && cd .."

リリースAPKを生成する場合

"release-build": "react-native bundle --platform Android --dev false --entry-file index.js --bundle-output Android/app/src/main/assets/index.Android.bundle --assets-dest Android/app/build/intermediates/res/merged/release/ && rm -rf Android/app/src/main/res/drawable-* && rm -rf Android/app/src/main/res/raw/* && cd Android && ./gradlew assembleRelease && cd .."

私のreact-native> = 0.61.2プロジェクトでうまく機能します(scriptsセクションの上記のコードを使用してpackage.jsonファイル

7
limbo

受け入れられた回答は機能しますが、ノードパッケージを変更すると、変更を更新すると変更が失われることを考慮に入れていません(ベストプラクティスに反している場合は、モジュールを拡張する必要があります)。

これは元々 React-native Androidリリースエラー:リソースの重複 からのものです

  1. プロジェクトの「Android」フォルダー({project-root}/Android/fixAndroid)に「fixAndroid」フォルダーを作成します。

  2. プロジェクトの「fixAndroid」フォルダーにファイルAndroid-gradle-fixを作成します({project-root}/Android/fixAndroid/Android-gradle-fix)。

            doLast {
        def moveFunc = { resSuffix ->
            File originalDir = file("${resourcesDir}/drawable-${resSuffix}")
            if (originalDir.exists()) {
                File destDir = file("${resourcesDir}/drawable-${resSuffix}-v4")
                ant.move(file: originalDir, tofile: destDir)
            }
        }
        moveFunc.curry("ldpi").call()
        moveFunc.curry("mdpi").call()
        moveFunc.curry("hdpi").call()
        moveFunc.curry("xhdpi").call()
        moveFunc.curry("xxhdpi").call()
        moveFunc.curry("xxxhdpi").call()
    }
    
    // Set up inputs and outputs so gradle can cache the result
    
  3. 作成した「fixAndroid」フォルダーにファイルAndroid-release-fix.jsを作成します。

            const fs = require('fs')
    
        try {
                var curDir = __dirname
                var rootDir = process.cwd()
    
                var file = `${rootDir}/node_modules/react-native/react.gradle`
                var dataFix = fs.readFileSync(`${curDir}/Android-gradle-fix`, 'utf8')
                var data = fs.readFileSync(file, 'utf8')
    
                var doLast = "doLast \{"
                if (data.indexOf(doLast) !== -1) {
                    throw "Already fixed."
                }
    
                var result = data.replace(/\/\/ Set up inputs and outputs so gradle can cache the result/g, dataFix);
                fs.writeFileSync(file, result, 'utf8')
                console.log('Android Gradle Fixed!')
            } catch (error) {
                console.error(error)
            }
    
  4. スクリプトをpackage.jsonスクリプトセクションに追加します。

    "postinstall": "node ./Android/fixAndroid/Android-release-fix.js"
    

これにより、「Android-gradle-fix」ファイルのコンテンツが検出され、node_modules/react-native/react.gradleに挿入されます。

  1. プロジェクトのルートからnpm installを実行します。
  2. プロジェクトのルートからrm -rf Android/app/src/main/res/drawable- *を実行します。

これで、リリースをReactコンソールまたはAndroid Studio:のいずれかにバンドルできます。

React Nativeコマンドライン

  1. cd {project-root}/Android
  2. ./gradlew/bundleRelease

Android Studio

  1. フォルダーを開くAndroid Android Studioでビルドしてプロジェクトをビルドします。
  2. [ビルド/生成された署名済みAPKを生成]を選択してリリースをビルドします。
5
DrCord

rNで同じ問題に直面している人!この問題が長い間ここに存在していることは非常に恐ろしいことだと思いますが、さまざまな解決策を調査した後、その解決方法を共有したいと思います。

ジェフリー・ラジャンはここで考えられる解決策について完全に正しいです https://stackoverflow.com/a/53260522/1611414

変更するのはとても悪いと思いますreact.gradleファイルnode_modulesそして、それはこのRNプロジェクトのメンテナンスで多くの多くの異なる問題につながります。だから私は最初のオプションを選択することをお勧めします-ビルドを実行する前にbashコマンドを使用してそのフォルダーを削除します。

私のプロジェクトで行ったことを共有したいと思います。おそらく同じアプローチを再利用できます。

// ./package.json

...
scripts: {
   "build": "react-native bundle --platform Android 
             --dev false
             --entry-file index.js
             --bundle-output Android/app/src/main/assets/index.Android.bundle
             --assets-dest Android/app/src/main/res/
          && rm -rf ./Android/app/src/main/res/drawable-mdpi/
          && rm -rf ./Android/app/src/main/res/raw/",

   "release": "yarn build && cd ./Android && ./gradlew bundleRelease"
}
...

そして、リリースはyarn release

これらの行は非常に重要です:

...
&& rm -rf ./Android/app/src/main/res/drawable-mdpi/
&& rm -rf ./Android/app/src/main/res/raw/
...

buildが実行される前に、重複するリソースをbundleReleaseステップから削除します。ソリューションはRN 0.57、0.58、0.59、0.60でテストされています

楽しい!

4
denieler

Com.Android.tools.build:gradle:3.1.4を使用してください。 RN 0.57は3.2でのビルドに問題があります

この質問は、次の重複の可能性があります。

React Native Error:重複するリソース、アセットが一部の画面に表示され、他の画面には表示されないAndroid release APK

それでも動作しない場合は、RN 0.57.2を使用してみてください。私はそれを使用しており、リリースの作成はこれらの依存関係で非常にうまく機能します。

   "dependencies": {
    "react": "16.5.0",
    "react-native": "0.57.2",
    .......
  }

  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/plugin-proposal-class-properties": "^7.0.0",
    "@babel/plugin-proposal-decorators": "^7.0.0",
    "@babel/plugin-proposal-do-expressions": "^7.0.0",
    "@babel/plugin-proposal-export-default-from": "^7.0.0",
    "@babel/plugin-proposal-export-namespace-from": "^7.0.0",
    "@babel/plugin-proposal-function-bind": "^7.0.0",
    "@babel/plugin-proposal-function-sent": "^7.0.0",
    "@babel/plugin-proposal-json-strings": "^7.0.0",
    "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",
    "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0",
    "@babel/plugin-proposal-numeric-separator": "^7.0.0",
    "@babel/plugin-proposal-object-rest-spread": "^7.0.0",
    "@babel/plugin-proposal-optional-chaining": "^7.0.0",
    "@babel/plugin-proposal-pipeline-operator": "^7.0.0",
    "@babel/plugin-proposal-throw-expressions": "^7.0.0",
    "@babel/plugin-syntax-dynamic-import": "^7.0.0",
    "@babel/plugin-syntax-import-meta": "^7.0.0",
    "@babel/plugin-syntax-object-rest-spread": "^7.0.0",
    "@babel/plugin-transform-runtime": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "@babel/preset-flow": "^7.0.0",
    "@babel/register": "^7.0.0",
    "babel-core": "^7.0.0-bridge.0",
    "babel-preset-react-native-stage-0": "^1.0.1",
    .....
}

Gradle deps:

classpath 'com.Android.tools.build:gradle:3.1.4'
classpath "io.realm:realm-gradle-plugin:4.0.0"

アプリグラドル

compileSdkVersion 27
    buildToolsVersion "27.0.3"

    defaultConfig {
        applicationId "de.burda.buntede"
        minSdkVersion 17
        targetSdkVersion 27

Gradleラッパーの小道具:

distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.Zip

0
Florin Dobre

私にとってはキャッシュの問題でした。次のコマンドは私のために働きました

cd into Androidフォルダ

./gradlew cleanを実行します

0
Cedric Sandars

tolotrasmileの答えは私のために働いた。

Androidをビルドしてインストールしたいときに実行する小さなbashスクリプトにそれを含めました

        cd $PROJECT_DIRECTORY && react-native bundle --platform Android --dev false --entry-file index.js --bundle-output Android/app/src/main/assets/index.Android.bundle --assets-dest Android/app/src/main/res

        rm -rf $PROJECT_DIRECTORY/Android/app/src/main/res/drawable-*
        rm -rf $PROJECT_DIRECTORY/Android/app/src/main/res/raw

        cd $PROJECT_DIRECTORY/Android/
        ./gradlew clean
        ./gradlew assembleRelease

        adb install -r $PROJECT_DIRECTORY/Android/app/build/outputs/apk/release/app-release.apk
0
Airman00

存在する可能性のあるファイルを削除します。

Android/app/src/main/res/drawable-mdpi/Android/app/src/main/res/drawable-xhdpi/Android/app/src/main/res/drawable-xxhdpi /ビルドを再実行して、問題を修正しました私のために。

0
RkKhanpuriya