Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Duplicate class errors in proguard

When compiling my app, I get the following error (sensitive pieces of path edited out)

Execution failed for task ':app:proguardDebug'.
> java.io.IOException: Can't write [/projects/app/build/intermediates/classes-proguard/debug/classes.jar] (Can't read [/.gradle/caches/modules-2/files-2.1/commons-codec/commons-codec/1.4/4216af16d38465bbab0f3dff8efa14204f7a399a/commons-codec-1.4.jar(;;;;;;!META-INF/MANIFEST.MF)] (Duplicate zip entry [commons-codec-1.4.jar:org/apache/commons/codec/binary/Base64.class]))

This indicates to me that the compiler sees two places where the app is trying to use commons.codec.binary.Base64.class as a dependency. I have checked and checked my libraries again, but only one library (Amazon AWS) is attempting to use it.

Above this error, I'm getting some other warnings which also raise a red flag for me:

Warning:can't write resource [META-INF/LICENSE.txt] (Duplicate zip entry [commons-lang3-3.1.jar:META-INF/LICENSE.txt])
Warning:can't write resource [META-INF/NOTICE.txt] (Duplicate zip entry [commons-lang3-3.1.jar:META-INF/NOTICE.txt])
Warning:can't write resource [META-INF/LICENSE.txt] (Duplicate zip entry [commons-codec-1.4.jar:META-INF/LICENSE.txt])
Warning:can't write resource [META-INF/NOTICE.txt] (Duplicate zip entry [commons-codec-1.4.jar:META-INF/NOTICE.txt])

I don't explicitly use commons-codec-1.4 or commons-lang3-3.1 in my app at all, thought I used to use lang3 before later removing it. Why are these being referenced in the compile log? Could one of my maven libraries be using them? I'll include a list of maven libraries below in my gradle file.

Here are my proguard and gradle files for reference:

PROGUARD

-keep class org.w3c.dom.bootstrap.** { *; }
-keep class org.joda.time.** { *; }
-keep class com.facebook.** { *; }
-keep class org.apache.commons.** { *; }
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-dontwarn org.codehaus.jackson.map.ext.**
-dontwarn oauth.**
-dontwarn com.amazonaws.**
-dontwarn org.joda.time.**
-dontwarn org.apache.commons.codec.**
-dontwarn com.fasterxml.jackson.databind.ext.**

GRADLE

apply plugin: 'com.android.application'

android {
    compileSdkVersion 20
    buildToolsVersion '20.0.0'

    defaultConfig {
        applicationId 'com.my.package'
        minSdkVersion 14
        targetSdkVersion 20
        versionCode 9
        versionName '1.2'
    }

    buildTypes {
        release {
            debuggable false
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
        debug {
            debuggable true
            runProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    lintOptions {
        checkReleaseBuilds false
    }

    packagingOptions {
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/MANIFEST.MF'
    }
}

dependencies {
    compile fileTree(dir: 'libs',  include: ['*.jar'])

    //noinspection GradleDependency
    compile 'com.google.android.gms:play-services:5.0.89'

    compile 'com.nineoldandroids:library:2.4.0'
    compile 'com.viewpagerindicator:library:2.4.1@aar'
    compile 'se.emilsjolander:StickyScrollViewItems:1.1.0'
    compile 'se.emilsjolander:stickylistheaders:2.5.0'
    compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.2'
    compile project(':facebook')
    compile 'com.tumblr:jumblr:0.0.10'
    compile 'com.android.support:support-v4:20.0.0'
}

My best guess is one or more of those libraries is using apache lang3 and codec as dependencies of their own, which is resulting in a conflict when I compile the app. This problem only happens when I include Amazon as a required jar, so I know that is in some way acting as the culprit, but I don't know what else is conflicting with it.

I read something about using -injars with proguard, but according to their documentation Android shouldn't need you to use that.

Any advice would be greatly appreciated, thanks!

like image 883
JMRboosties Avatar asked Sep 05 '14 00:09

JMRboosties


People also ask

Does ProGuard work with missing classes on Android?

This is a bit shady, since Android doesn't have this package at all, but if your application works anyway, you can let ProGuard accept it with " -dontwarn java.awt.** ", for instance. If the missing class is an Android run-time class, you should make sure that you are building against an Android run-time that is sufficiently recent.

How can ProGuard reduce the size of my code?

Another thing that ProGuard can do, which makes a big impact on code size, is change all identifiers (package, class and class members) to use short names, such as a.A and a.a.B. This process is known as obfuscation.

Why does ProGuard fail my build?

Unfortunately, ProGuard can fail your build by emitting warnings at compile time when it detects problems with your code, such as referencing missing classes.

Why can't ProGuard find a dynamically referenced class?

Note: can't find dynamically referenced class ... ProGuard can't find a class or interface that your code is accessing by means of introspection. You should consider adding the jar that contains this class. Your code uses reflection to dynamically create class instances, with a construct like " (MyClass)Class.forName (variable).newInstance () ".


1 Answers

I am not sure if this will help you or not but I am posting my answer here in case others find this useful. My issue was that I had 2 references in my dependencies statement. I was using the Universal Image Loader library and my statement looked like this:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.1.1'
    compile 'com.android.support:support-v4:22.1.1'
    compile 'uk.co.chrisjenx:calligraphy:2.0.2'
    /* UIL was the failing reference */
    compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
    compile 'com.google.android.gms:play-services:7.3.0'
}

The problem with this I realized (after a head smack moment) was that I had already referenced UIL via the libs folder (i.e. it was already being compiled by the statement compile fileTree(dir: 'libs', include: ['*.jar']). So it was compiling it once via libs and once via the explicit call to compile the reference to UIL. I removed the explicit call and that cleared up the error. Perhaps you are calling something in your libs directory that also contains a reference to the offending library then when it tries to compile the AWS Services it already has a version of the commons library and pukes.

like image 144
akousmata Avatar answered Oct 10 '22 07:10

akousmata