Andrei Herford
Andrei Herford

Reputation: 18729

Proguard complains about missing classes in external JARs. How to solve this correctly?

I am trying to obfuscate an Android 4+ app that uses Dropbox with Proguard in Eclipse. So far I have no experience with Proguard and thus I used different tutorials and answers here on SO to configure my proguard-project.txt:

-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService

When I try to export the APK using the File/Export.../Export Android Application/... dialog the creation fails with an Proguard error:

[2014-08-29 09:50:30 - MyApp] Proguard returned with error code 1. See console
[2014-08-29 09:50:30 - MyApp] Note: there were 367 duplicate class definitions.
[2014-08-29 09:50:30 - MyApp] Warning: org.apache.commons.logging.impl.ServletContextCleaner: can't find superclass or interface javax.servlet.ServletContextListener
[2014-08-29 09:50:30 - MyApp] Warning: org.apache.http.entity.mime.FormBodyPart: can't find superclass or interface org.apache.james.mime4j.message.BodyPart
...
[2014-08-29 09:50:30 - MyApp] Warning: library class android.net.http.AndroidHttpClient extends or implements program class org.apache.http.client.HttpClient
...
[2014-08-29 09:50:30 - MyApp] Warning: org.bouncycastle.x509.util.LDAPStoreHelper: can't find referenced class javax.naming.directory.DirContext
[2014-08-29 09:50:30 - MyApp]       You should check if you need to specify additional program jars.
[2014-08-29 09:50:30 - MyApp] Warning: there were 223 unresolved references to classes or interfaces.
[2014-08-29 09:50:30 - MyApp]          You may need to specify additional library jars (using '-libraryjars').
[2014-08-29 09:50:30 - MyApp] Warning: there were 1 instances of library classes depending on program classes.
[2014-08-29 09:50:30 - MyApp]          You must avoid such dependencies, since the program classes will
[2014-08-29 09:50:30 - MyApp]          be processed, while the library classes will remain unchanged.
[2014-08-29 09:50:30 - MyApp] Warning: there were 13 unresolved references to program class members.
[2014-08-29 09:50:30 - MyApp]          Your input classes appear to be inconsistent.
[2014-08-29 09:50:30 - MyApp]          You may need to recompile them and try again.
[2014-08-29 09:50:30 - MyApp]          Alternatively, you may have to specify the option 
[2014-08-29 09:50:30 - MyApp]          '-dontskipnonpubliclibraryclassmembers'.
[2014-08-29 09:50:30 - MyApp] java.io.IOException: Please correct the above warnings first.
[2014-08-29 09:50:30 - MyApp]   at proguard.Initializer.execute(Initializer.java:321)
[2014-08-29 09:50:30 - MyApp]   at proguard.ProGuard.initialize(ProGuard.java:211)
[2014-08-29 09:50:30 - MyApp]   at proguard.ProGuard.execute(ProGuard.java:86)
[2014-08-29 09:50:30 - MyApp]   at proguard.ProGuard.main(ProGuard.java:492) 

First Thing I tried was to add some -libraryjars ... commands:

-libraryjars 'F:/Path/To/Workspace/Third Party/Dropbox/dropbox-android-sdk-1.6.1/lib/bcprov-jdk16-146.jar'
-libraryjars 'F:/Path/To/Workspace/Third Party/Dropbox/dropbox-android-sdk-1.6.1/lib/commons-logging-1.1.1.jar'
-libraryjars 'F:/Path/To/Workspace/Third Party/Dropbox/dropbox-android-sdk-1.6.1/lib/dropbox-android-sdk-1.6.1.jar'
-libraryjars 'F:/Path/To/Workspace/Third Party/Dropbox/dropbox-android-sdk-1.6.1/lib/httpclient-4.0.3.jar'
-libraryjars 'F:/Path/To/Workspace/Third Party/Dropbox/dropbox-android-sdk-1.6.1/lib/httpcore-4.0.1.jar'
-libraryjars 'F:/Path/To/Workspace/Third Party/Dropbox/dropbox-android-sdk-1.6.1/lib/httpmime-4.0.3.jar'
-libraryjars 'F:/Path/To/Workspace/Third Party/Dropbox/dropbox-android-sdk-1.6.1/lib/json_simple-1.1.jar'

This does not solve the problem. In fact now there are 2468 duplicate class definitions (367 before...)

The next I tried is to ignore the warnings:

-dontwarn org.bouncycastle.** 
-dontwarn org.apache.** 

This solves the problem! The creation of the APK now runs without any error. Fine... But I don't have a good feeling about this. Is ignoring warnings really the best way to solve this issue? Is this the "corrent" way of handling such issues?

When I run the APK on my device and try to use the Dropbox functions the app crashes. But this can be solved by adding the following:

-keep class org.** { *; }
-keep class com.dropbox.** {*;}

This protects the Dropbox code from being obfruscated. But again I am not sure if this is the right way to handle this.

So far the app seems to work fine with this configuration. But is there any way I can be sure Proguard did not broke anything (beside running a complete beta-test of every app function everytime the app is created?)

Thank your very much!

Upvotes: 1

Views: 3750

Answers (1)

AZ_
AZ_

Reputation: 21899

Your 3rd party libraries are being processed twice. Add them to another folder in this case to lib and add the following line to proguard.cfg file.

 -injars lib/dropbox.jar 

See Pro Guard Troubleshooting

Note: duplicate definition of program/library class

Your program jars or library jars contain multiple definitions of the listed classes. ProGuard continues processing as usual, only considering the first definitions. The warning may be an indication of some problem though, so it's advisable to remove the duplicates. A convenient way to do so is by specifying filters on the input jars or library jars. You can switch off these notes by specifying the -dontnote option.

As indicated by the link to the ProGuard Troubleshooting page in your console log, you should change the target in project.properties to a target that contains the missing classes. In this case: "android-18" or maybe "Google Inc.:Google APIs:18".

You can still specify a different minSdkVersion in AndroidManifest.xml.

You should not specify any -libraryjars options, since the Android build process already specifies those options for you -- you'll just see warnings about duplicate classes now. In fact, the Android build process specifies most other options for you as well.

Upvotes: 1

Related Questions