React Native Android生成apk时出现重复文件错误



当我试图使用./gradlew installRelease生成android apk时,我在控制台中得到了这个错误:

~/React-Native/mockingbird/android/app/build/intermediates/res/merged/release/drawable-mdpi-v4/src_resources_img_loading.gif: error: Duplicate file.
~/React-Native/mockingbird/android/app/build/intermediates/res/merged/release/drawable-mdpi/src_resources_img_loading.gif: Original is here. The version qualifier may be implied.

我通过Android Studio尝试了Build->Clean Project,并再次运行了./gradlew installRelease;它也不起作用。

此外,我尝试删除build文件夹,但也无济于事。

给你一些提示,希望能奏效。

更新为"react":"16.7.0","react native":"0.57.8">

自定义node_modules/areact native/areact.gradle以完美解决重复文件错误。将以下代码添加到currentBundleTask的创建块(在doFirst块之后)

doLast {
def moveFunc = { resSuffix ->
File originalDir = file("${resourcesDir}/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()
}

您可以创建脚本来自动执行。

  1. 创建android-react-gradle-fix文件
  2. 创建脚本android-release-gradle-fix.js文件
  3. 更新package.json文件:

    "脚本":{"postinstall":"node./android release gradle fix.js">},

就是这样!运行npm install以获得卓越表现。

注意:如果你像jenkins一样在ci上运行npm install,你可能会得到错误:postinstall: cannot run in wd %s %s (wd=%s) node=>只使用npm install --unsafe-perm而不是

在撰写本文时,React Native的最新版本(>0.57.0)已将Gradle包装级别提高到4.4,Gradle插件级别提高到3.1.4,如变更日志所示。这具有使Gradle构建过程将AAPT的结果存储在与以前不同的目录中的效果,AAPT现在是必需的

就Nhan Cao令人敬畏的变通方法而言,我们需要进行轻微修改,以防止重复的资源冲突,因为它看起来指向旧目录,而不是应用程序的generated目录。在生成资源后,通过更改将这些重复文件合并在一起的目标目录,我们仍然可以对资源进行重复数据消除。

现有的react.gradle是指以下路径:

$buildDir === <project-working-directory>/android/app/build

重复的文件路径可能出现在以下位置之间:

file("$buildDir/../src/main/res/drawable-${resSuffix}")
file("$buildDir/generated/res/react/release/drawable-${resSuffix}")

作为一种变通方法,我们可以如下更新Nhan的解决方案(请确保在react.gradle:中声明doFirst后将其包含在currentBundleTask

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

如果您的应用程序也依赖于/raw资产,下面列出的方法应该会对您有所帮助:

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

如果您的应用程序还使用自定义";构建类型";除了release,例如preReleasestagingRelease(Android Gradle插件允许您在build.gradle中定义它们),您应该更改originalDir变量,如下所示:

# from
File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");
# to 
File originalDir = file("$buildDir/generated/res/react/${targetName}/drawable-${resSuffix}");

删除您可能在上的文件

android/app/src/main/res/drawable-mdpi/
android/app/src/main/res/drawable-xhdpi/
android/app/src/main/res/drawable-xxhdpi/

再次运行Build,这为我修复了问题。

请勿在./gradlew assembleRelease之前运行react-native bundle

就我自己而言,在运行./gradlew assembleRelease之前,我运行的是react-native bundle

我的一个资产收到了类似的重复错误消息。

看看./gradlew assembleRelease的输出,我可以看出它是自己构建JS捆绑包的(多亏了build.gradle文件中的apply from: "../node_modules/react-native/react.gradle"),所以不需要手动运行react-native bundle

如果我只是在运行./gradlew assembleRelease之前没有运行react-native bundle,那么一切都很好。

我测试了Release APK和JS捆绑包负载良好,包括所有图像。

我唯一关心的是是否会创建源映射--sourcemap-output(用于Bugsnag)。如果没有,我相信有一种方法可以让./gradlew assembleRelease生成这些。我只是还没有测试过。

为了让我的构建适用于React Native 0.57.5,我使用了Mapsy的答案,并进行了一些小的增强。我需要能够为多种口味构建,通常我会尽量避免硬编码。当查看我的react.gradle文件时,我发现它定义了以下变量:

def resourcesDir = file("$buildDir/generated/res/react/${targetPath}")

因此,与其在如下路径中硬编码构建类型/风格:

File originalDir = file("$buildDir/generated/res/react/release/drawable-${resSuffix}");

相反,我使用resourcesDir变量来设置originalDir路径,如下所示:

File originalDir = file("${resourcesDir}/drawable-${resSuffix}");

因此,我的doLast看起来是这样的:

doLast {
def moveFunc = { resSuffix ->
File originalDir = file("${resourcesDir}/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()
}

对我来说,删除文件夹android/build并再次运行./gradlew assembleRelease是可行的。

对我有用的是在package.json中添加这个额外的命令,并使用它来构建:

"android-build-release": "cd ./android && rm -rf app/src/main/res/drawable* && ./gradlew app:assembleRelease",

1.删除可绘制的xxx文件夹2.删除原始内部src->main->res文件夹然后

3.在终端中运行此命令:

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

4.然后使用密钥库生成签名的apk,使用终端或安卓工作室生成别名和密码

删除错误的方法是:

  • 将您的图像放在android/app/src/main/res/drawable文件夹中(如果不存在,请创建一个"drawable"文件夹)
  • 删除所有带有后缀的可绘制文件夹(即可绘制hdpi、可绘制mdpi等)
  • 不捆绑资产(即不运行:react native bundle…)
  • 运行Gradle的assemblyRelease

但是,这不是一个理想的解决方案,因为对于所有设备尺寸,每个图像都只有一个分辨率。对于对于设备来说太大的图像,它将缩小尺寸留给设备,并导致下载大小和速度问题;对于对于设备而言太小的图像,则会导致图像质量下降。

我发现的一个方便的解决方案是使用一个名为Android Drawable Importer的Android Studio插件。安装后使用:

  • 在Android工作室中打开您的项目,并导航到:Android/app/src/main/res/drawable
  • 右键单击文件夹,然后选择:新建>批量绘图导入
  • 选择并配置要导入的图像资源

该插件将处理可绘制文件夹和正确图像大小的生成。导入映像后,您应该能够运行Gradle的assemblyRelease,而不会出现重复资源错误。

如果有其他人遇到这种情况,而doLast解决方案不起作用,那是因为在运行bundleRelease之前,您不必再运行react原生bundle了。这花了几个小时的时间,因为我发现有很多帖子说doLast解决了这个问题

相关内容

  • 没有找到相关文章

最新更新