开启 R8 后,模块中发现重复的类

8
我创建了两个aar库:com.example:test1:1.0.0和com.example:test2:1.0.0。我将这些库添加到我的主应用程序中,但在构建时,Android-Studio报错:
“模块classes.jar(com.example:test1:1.0.0)和classes.jar(com.example:test2:1.0.0)都包含重复的类com.example.utils.a。”
我发现这个错误是因为两个库都有同一包中的类(com.example.utils),并且在混淆后,R8会创建具有相同完整名称(我在aar的classes.jar中看到了这一点)的类(a.class)。如果我在我的库属性中禁用R8,则此错误消失。
'a'不是库类:在混淆后,所有库类名仍保持不变,而R8通过额外添加a.class来解决问题。 我阅读了R8文档,但没有找到关于这个问题的解决方案。 是否有其他方法可以解决此问题,而无需在其中一个库中更改包名称?

我不认为这个问题很糟糕,但是考虑可能也发布一些代码,考虑发布模块甚至展示你在“混淆后R8创建具有相同全名的类(a.class)”中看到了什么。 - a_local_nobody
您可以通过删除其中一个库中的文件或使用使用相同类的版本来解决此问题。 - Blind Kai
1
我认为他们想知道为什么这是一个问题,而不是找到解决方法。“有没有办法在不重命名我的库中的包的情况下解决这个问题?”@BlindKai - a_local_nobody
@a_local_nobody,我遇到这个问题的唯一时候是当我尝试使用官方库与另一个使用off.lib类的库时。所以我不能确定。 但这是一个问题,因为编译器无法选择要使用哪个类。 - Blind Kai
2个回答

7

当创建两个库时,最好使用两个不同的名称空间(namespace),否则即使没有使用R8,也有可能出现重复类的情况,例如“意外地”在两个库中添加了同名的类。所以在您的情况下,请使用 com.example.test1com.example.test2

根据您的用例,不将 R8 应用于库,而仅将 R8 应用于包含两个库的最终应用程序也是更好的选择。缩小库的大小主要是为了减小分发大小,并重命名内部内容以避免库用户(无论是有意还是无意)依赖于可能在库版本之间发生变化的内部内容。

在缩小库时,您还需要考虑选项-keeppackagenames,以确保所有重命名的类都留在库的软件包中。否则,您可能会在多个库中得到类,例如a.a.a.a.class

如果此问题发生在您无法控制的库上,可以使用诸如shadow之类的工具进行重定位。


你能否添加如何使用“shadow”来重新定位软件包的说明? - cgb_pandey

2

在Java或其他JVM语言中,您应该始终使用唯一的包名来为代码添加前缀,以创建一个唯一的完全限定名称,因为任何两个具有完全相同完全限定名称的类将导致构建错误。这是因为JVM只使用最初保存在单个表中的完全限定名称字符串来实例化系统中的所有类和接口。如果表中有多个条目用于类/接口,则它不知道选择哪一个。您可以在此处阅读更多相关信息。

如我在这里所述,处理混淆相关冲突的最佳解决方案是在每个库的proguard-rules文件中使用-repackageclasses com.example:test#.ofs,同时将#分别替换为12。这将把所有混淆类移动到com.example:test#.ofs包中,而所有非混淆类将保留在其原始包中,您可以确保不会发生冲突。
正如Proguard 文档所述:

-repackageclasses [package_name]

指定重新打包所有被重命名的类文件,将它们移动到单个给定的包中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接