Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native : Error: Duplicate resources - Android

I was trying to create a release apk file from Android but when I create a release apk with PNG image I'm getting Duplicate Resource error. Initially I thought this is happening because I made a mistake in the existing project but when I created a new project with a single Image component itself I'm getting the Duplicate Resource error. Here are the steps I followed

  1. Create a app - react-native init demo
  2. Create a assets folder in the project root folder.
  3. Add a PNG image inside the assets folder.
  4. Now implement the Image component with the above PNG image.
  5. Now bundle it using the 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. Then generate release apk using Generate Signed APK from Android Studio.

This will throw the following error:

[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 

Note: When you generate a release apk without any PNG image you will not get any error, it will create you the release apk.

Here are the other files code.

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

Any solution for this?

Update:

Here are the other details

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 

Tried with Android Studio 3.0, 3.0.1, 3.1, 3.1.4 & 3.2

like image 708
Jeffrey Rajan Avatar asked Nov 10 '18 13:11

Jeffrey Rajan


People also ask

What is duplicate resources error in Android Studio?

It seems like you have the same image resource in two files OR you added an additional, non-required file to the res folder. Rename or remove the other. You can check the required structure of the res folder and subfolders by downloading a fresh copy of WebViewGold from CodeCanyon.


2 Answers

(UPDATED)

This solution works for me

rm -rf ./android/app/src/main/res/drawable-*  rm -rf ./android/app/src/main/res/raw 

In my case, build failed because there is a duplicated resources in my Android project (inside android folder), these two lines is necessary to remove duplicated resources, that's it.

like image 99
tolotra Avatar answered Sep 17 '22 11:09

tolotra


After trying a lot of solutions I found only Three solution is working. Here they are

Solution 1:

Clean the drawable folder from the terminal using Gradle. cd into the android folder, then run cmd ./gradlew clean

Solution 2:

After bundling delete the drawable folder from Android Studio. You could find this in android/app/src/main/res/drawable

Solution 3:

PLEASE DO NOT USE SOLUTION #2, AS PROPOSED BY THE ORIGINAL AUTHOR! All packages under node_modules are generated, and any changes you make will be lost when the react-native package is reinstalled / upgraded.

In this solution you no need to delete any drawable folder. Just add the following code in the react.gradle file which you could find under node_modules/react-native/react.gradle path

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() } 

For reference I will add the full react.gradle file code here

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

Credit: ZeroCool00 mkchx

like image 33
Jeffrey Rajan Avatar answered Sep 20 '22 11:09

Jeffrey Rajan