提问人:CalvinChe 提问时间:11/17/2023 更新时间:11/17/2023 访问量:3874
Android 应用构建错误:D8:切换分支时多次定义 XXXXXXX
Android app build error: D8: XXXXXXX is defined multiple times when switching branches
问:
我们在构建 Android 应用程序时遇到了一个特殊的问题。当我们在一个分支上开发时,一切都会成功编译。但是,一旦我们切换到另一个分支(当前分支以外的任何分支),我们就会遇到以下错误:
D8: XXXXXXX is defined multiple times:
Type com.xxxxxxxxx is defined multiple times: /Users/xxxxx/app/build/intermediates/mixed_scope_dex_archive/normal_Debug/out/75dc6161aec3efe974a08e13687ced704791b9c6e7797bbab5932f7bab205fc9_14.jar:classes.dex, /Users/xxxxx/app/build/intermediates/mixed_scope_dex_archive/normal_Debug/out/ff31007b66c63e303d30cc9551267d87131906985d359c93f6793be7006cde58_14.jar:classes.dex
com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives.
请注意,XXXXXXX部分每次都会更改,并且每次都引用不同的类。
我们将不胜感激有关如何永久解决此问题的任何见解或建议。谢谢!
为了暂时解决这个问题,我们必须清理项目,然后它成功构建,直到下一个分支切换。
因为重复的类一直在变化。所以我试图查找不同模块中是否有相同的包名称,但一无所获。
答:
在我看来,您的代码在不同的分支上具有不同的 lib 版本,这会导致使用该特定库的不同类出现此错误。
Gradle 通过两种方式优化构建过程:增量构建和构建缓存。
日常生活
让我们从没有惊喜开始。引用 Gradle 的文档:
增量生成是一种生成,它避免运行输入自上一次生成以来未更改的任务,从而不需要执行此类任务。要使增量生成正常工作,任务必须定义其输入和输出。在构建时,Gradle 将确定输入或输出是否已更改。如果它们发生了变化,Gradle 将执行该任务。否则,它将跳过执行。
增量构建 [...] 有助于避免已经完成的工作。如果开发人员不断对单个文件进行更改,则可能不需要重新生成项目中的所有其他文件。
戈尔迪结
到目前为止,很清楚。有人可能会认为,切换分支将无缝地继续该新分支上的增量构建过程。然而:
当同一个开发人员决定切换到上周创建的新分支时,会发生什么?即使开发人员正在构建以前构建的内容,也会重新生成文件。
这是一个新分支,从 Gradle 的角度来看,这里还没有做任何事情,尽管仍然有来自旧分支的旧结果文件。这就是为什么你会得到这样的行(重新格式化):
ERROR:
/.../build/intermediates/.../out/1703be4408d6a5fd21e9e69c71e1314b194fe435af52fc6e7692eeeb63105993_13.jar:
D8: Type com.xxxxxxxxxx.ams.dynamicwidget.BuildConfig is defined multiple times:
/.../build/intermediates/.../out/1703be4408d6a5fd21e9e69c71e1314b194fe435af52fc6e7692eeeb63105993_13.jar:classes.dex
/.../build/intermediates/.../out/375fc00ebbbf2a453f2f11eb16313b871cac6c4588166b726e8a4a3afec805fa_13.jar:classes.dex
新创建的
1703be4408d6a5fd21e9e69c71e1314b194fe435af52fc6e7692eeeb63105993_13.jar
与中间文件冲突
375fc00ebbbf2a453f2f11eb16313b871cac6c4588166b726e8a4a3afec805fa_13.jar
从旧分支,导致 D8 看到相同的多个定义。
亚历山大之剑
解决方案是使用 Gradle 的 Build Cache 机制。使用它所需的几个步骤在有关如何启用构建缓存的相应文档中进行了详细描述,因此我只是参考了它们以供自读。相反,我想把你的注意力引向几点:
- 默认情况下,“增量生成”处于打开状态。
- 但默认情况下,Build Caching 处于关闭状态。
- 缓存将服务于所有项目和项目分支。
Gradle 将查看您计算机上的缓存目录,以检查可能已存在的输出文件。如果他们这样做,它不会运行该任务,而是将其(输出)结果复制到您的项目构建目录中。
- 将不时通过删除最近未使用的文件来清理本地生成缓存。
评论