我试图从 Android创建一个发布apk文件,但当我创建一个PNG图像的发布apk时,我得到重复资源错误.最初我认为这种情况正在发生,因为我在现有项目中犯了一个错误,但是当我创建一个带有单个
>创建一个应用程序 – react-native init demo
>在项目根文件夹中创建资产文件夹.
>在assets文件夹中添加PNG图像.
>现在使用上面的PNG图像实现Image组件.
>现在使用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 /主/ RES /
>然后使用Android Studio的Generate Signed APK生成发布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图像的版本apk时,您将不会收到任何错误,它将为您创建发布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
在尝试了很多解决方案后,我发现只有两个解决方案正在运行.他们来了解决方案1:
捆绑后从Android Studio中删除drawable文件夹.你可以在android / app / src / main / res / drawable中找到它
解决方案2:
在此解决方案中,您无需删除任何可绘制文件夹.只需在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) } }
信用:
ZeroCool00
mkchx