Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicate class found in modules with R8 enabled

I created two aar-libraries: com.example:test1:1.0.0 and com.example:test2:1.0.0. I added these libs to my main app and after build Android-Studio throws error:

Duplicate class com.example.utils.a found in modules classes.jar (com.example:test1:1.0.0) and classes.jar (com.example:test2:1.0.0)

I find out that this error happens because both libraries have classes in same package (com.example.utils) and after obfuscation R8 creates classes (a.class) with same full name (I saw this in classes.jar of aar). If I disable R8 in properties of my libs this error has gone.

'a' is not library class: after obfuscation all library classe names remain unchanged and a.class was added in package additionaly by R8. I read R8 documentation and found nothing about this problem. Are there any ways to solve this issue without ranaming the package in one of my libs?

like image 879
Ivan Mikhayluts Avatar asked Aug 15 '19 13:08

Ivan Mikhayluts


2 Answers

When creating two libraries it is best practice to use two different namespaces, as otherwise there will be the possibility of duplicate classes even without using R8 when "accidentally" a class with the same name is added to both. So in your case use com.example.test1 and com.example.test2.

Depending on you use case, it might also be a better option to not apply R8 to the libraries, but only apply R8 to the final app including the two libraries. Shrinking libraries are mainly to make distribution size smaller, and rename internals to avoid library users (accidentally or knowingly) depend on internals which might change between library versions.

When shrinking libraries you also want to consider the option -keeppackagenames to make sure that all renamed classes stay within the package of the library. Otherwise you might end up with class e.g. a.a.a.a.class in multiple libraries.

If this issue happens for libraries that you don't have control over tools like shadow can be used to relocate.

like image 185
sgjesse Avatar answered Nov 10 '22 20:11

sgjesse


You should always prefix all of your code in Java or other JVM languages with unique packages to create a unique fully qualified name because any two classes with the exact same fully qualified name will cause a build error. This happens because the JVM only uses the fully qualified name string, saved initially in a single table, to instantiate all the classes and interfaces in the system. If the table will have more than one entry for a class/interface, it won't know which one to choose. You can read more about it here.

As I describe in my answer here, the best solution for obfuscation related collisions is to use -repackageclasses com.example:test#.ofs in the proguard-rules file of each library while replaceing # with 1 and 2 respectivly. This will move all the obfuscated classes into the com.example:test#.ofs package while all the non-obfuscated classes will remain in their original packages and you're guaranteed to have no collisions.

As the Proguard documentation states:

-repackageclasses [package_name]

Specifies to repackage all class files that are renamed, by moving them into the single given package.

like image 42
Sir Codesalot Avatar answered Nov 10 '22 19:11

Sir Codesalot