I'm writing 2 Android libraries. When I obfuscate both, the obfuscated code in both of them contains a class named a.a.a.a.a which causes the following error when trying to use both libraries in the same application:
Duplicate class a.a.a.a.a found in modules classes.jar (lib1) and classes.jar (lib2)
How can I prevent Proguard from obfuscating the first 3 packages to end up with:
my.domain.lib1.a.a and my.domain.lib2.a.a?
Edit: The obfuscation is happening as part of building the libraries, not while building the application.
This can be resolved by putting -repackageclasses my.domain.lib#.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 my.domain.lib#.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.
Another solution is to use -keeppackagenames. Unfortunately, I couldn't find a way to make it keep only the first 3 packages.
See the Proguard documentation:
-keeppackagenames [package_filter]
Specifies not to obfuscate the given package names.
Add the code below to the proguard-rules.pro file.
-keeppackagenames
Related
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?
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.
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.
I have manually added a JAR to my project. It uses lots of classes with different prefixes and I can't search and add all of them to my proguard file.
Is there a way to keep all the file the jar uses? The jar is called nano-0.7.0.jar
Do you have a package name in your jar file? If you have, try -keep class yourpackageName.**{*;} to tell proguard system keep all the classes in your package, and then add -dontwarn yourpackageName.** to tell proguard system do not warning if the system can't find the class referenced by the class in your package.
I have obfuscated my apk, but the file size has only been reduced from 12MB to 10.5MB.
The reason it is only a relatively small reduction may be because my app uses a couple of large libraries, but is there any way I can check the level of obfuscation that has been performed?
Just in case, this is my proguard-project.txt file...
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-dontwarn twitter4j.**
...and the libraries I'm using are android-support-v4.jar, acra-4.5.0.jar and twitter4j-core-4.0.2.jar.
Here is probably a more visual way to check.
In the newer release of Android Studio, it comes with the APK Analyser that let user explore what is in the APK file and it is handy to check if your class has been obfuscated.
Below image shows that both package and method name have been obfuscated
In your project directory you will find a Proguard folder, in which you will see four text files:
dump.txt
Describes the internal structure of all the class files in the .apk file
mapping.txt
Lists the mapping between the original and obfuscated class, method, and field names. This file is important when you receive a bug report from
a release build, because it translates the obfuscated stack trace back to the
original class, method, and member names. See Decoding Obfuscated Stack Traces
for more information.
seeds.txt
Lists the classes and members that are not obfuscated
usage.txt
Lists the code that was stripped from the .apk
Source: Proguard
Hope this helps!
Proguard
Proguard workflow:
seeds.txt - list of what Proguard keeps. These are entry points and they nodes. For example for bare java it is a main function and others dependencies
usage.txt - list of what Proguard does not keep
mapping.txt - info about old and new naming in old_name -> new_name format. It can be used for decoding stacktrace by retrace or proguardui
dump.txt - describe everything that Proguard put into the result archive
You can find output
<module_name>/build/outputs/mapping/<buildType>/
You can use Analyze APK tool. Where you can look thought .class files, add a Proguard mapping file, show removed nodes, show deobfuscated names
[ProGuard vs R8]
any way I can check the level of obfuscation that has been performed?
You might be able to use the flag -optimizationpasses N.
Specifies the number of optimization passes to be performed. By default, a single pass is performed. Multiple passes may result in further improvements. If no improvements are found after an optimization pass, the optimization is ended. Only applicable when optimizing.
ProGuard only shrinks/optimizes the parts you did not create -keep options for. When using broad -keep rules (ending in .** { *; }), the shrinking/optimization results quickly decrease.
I can see from the snippet you did not create such broad -keep options yourself but they may be part of the ProGuard consumer rules which are part of certain dependencies. You can print all these -keep options by adding the follwing in your ProGuard configuration file:
-printconfiguration fullconfig.txt. This will create the file fullconfig.txt in which all -keep options, including the ones of the dependencies, are listed.
If one of your dependencies contains too broad -keep options you could choose to ignore these by creating a consumer rule filter. This will require you to create the -keep options for the dependency yourself.
Recently there was a tool released to inspect what parts of a jar/apk are being kept thus not shrunken/optimized. You need to provide the -keep options and upload the jar/apk, you can then see in a visual way what parts of your project are not processed with ProGuard. This tool is called the ProGuard Playground. I would recommend copy/pasting the content of the fullconfig.txt file, that way you can easily see what parts are left untouched by ProGuard.
For Android,will the unused class files in jar be (or not be) included in .apk?
For example, there is a library in the form of the jar file. I may only use some of the files. I am just wondering what the .apk will include.
Thanks!
Basically, the unused files will be still included in apk.
But if you enabled ProGuard, they will be removed.
The APK will include unused class files.
Expanding on #Ivan's answer: You can configure ProGuard to keep certain classes it would otherwise remove (for example, because they are only referenced by reflection) by adding lines like this to proguard-project.txt:
# single class
-keep class com.example.reflected.MyClass
# whole package
-keep class com.example.reflected.*
I have an Android App which consists on different modules. The Main module is using some libs like Google's GSON or the v4.support.package. A custom build script with the right proguard.cfg will build it, too.
Now I must integrate another "Android-Library" which uses partly the same libs (GSON support.v4). Beside from getting a lot of Notes like
Note: duplicate definition of program class [com.google.gson.Gson]
I get also some Notes like
[proguard] Note: com.google.gson.UnsafeAllocator: can't find dynamically referenced class sun.misc.Unsafe
[proguard] Note: the configuration refers to the unknown class 'sun.misc.Unsafe'
that I find strange cause i have some 'keeps' in my Proguard.cfg especially for that:
-keepattributes Signature, Annotation
-keep class com.google.gson.** {*;}
-keep class sun.misc.Unsafe { *; }
which works well on my project without referencing the module-library inside it.
I'm on the Latest SDK and Tools, and added a custom proguard.cfg to the module-library, which works well on the module-lib itself (if build in standalone-mode).
It seems to me, that the build is not depending on custom proguard.cfg inside library-projects. Any idea on what to try highly appreciated
I finally found a solution for it myself:
with the last Android Tools (16), every Android-Library gets compiled on its own first.
So when the lib has not a "standart" build and defines some custom build script including proguard --keeps, and this --keeps are defined on the same Project (excluding Android SDK classes, as thei're not compiled) it leads to an proguard error.
The Solution was do remove proguard out of the lib and copy the --keeps inside the main App