We're using Android Studio 0.6.1 with Gradle plugin 0.11.+ in our current project, and we're running into a dependency issue with commons-codec
. We're pulling in a dependency class from our local Artifactory instance that contains a "crypto" service that uses the following two lines of code:
byte[] encryptedOutput = cipherFactory.getEncryptCipher().doFinal(plaintext.getBytes());
byte[] encryptedCipherText = Base64.encodeBase64URLSafe(encryptedOutput);
The problem is that even if we define a specific dependency of commons-codec
in our Gradle configuration, we get the following exception
java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.encodeBase64URLSafe
At first, we were manually including a dependency for 'commons-codec:commons-codec:1.9', but according to Android Studio when I drill down into the code in the IDE, it's looking at the version of that method in 1.9, but when the app runs, we get the exception. Even changing the dependency to 1.4 it still fails, even though according to the Javadocs that's when that method became available. Even removing the manual dependency altogether causes the same thing to happen.
Is there any way I can find out where the running app is pulling this dependency from? This is our complete dependency list at the moment, and I can't find commons-codec
from any of these
compile files('libs/HockeySDK-3.0.2.jar')
compile files('libs/PushIOManager.jar')
compile 'commons-lang:commons-lang:2.6@jar'
compile 'org.codehaus.jackson:jackson-core-asl:1.9.2@jar'
compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.2@jar'
compile 'com.google.android.gms:play-services:4.4.52'
compile 'com.mcxiaoke.volley:library:1.0.4'
compile 'fr.avianey:facebook-android-api:3.14.1@aar'
compile 'javax.validation:validation-api:1.0.0.GA'
My fear is that this class is buried somewhere with the Android SDK and we'll have no way to override it to use a version of commons-codec
that will allow us to use our library. And even if we could do that, I'm concerned doing so might cause some fundamental issue with Android itself. We can (and currently do) have the source for that crypto service class pulled into our app and tweaked it to use the appropriate equivalent, but this means any time we make a change to one or the other version, we'd have to keep them in sync.
Any ideas?
UPDATE: What seems to work in this specific case is to scan the dependencies in the Gradle build files and once the dependency is found you're looking for, override is with the version you want to use. For example:
def versionOverrides = [
"commons-codec:commons-codec": "1.9",
]
subprojects {
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def overrideVersion = versionOverrides[details.requested.group + ":" + details.requested.name]
if (overrideVersion != null && details.requested.version != overrideVersion) {
logger.info "Overriding dependency ${details.requested.group}:${details.requested.name} version ${details.requested.version} --> $overrideVersion"
details.useVersion overrideVersion
}
}
}
}
My fear is that this class is buried somewhere with the Android SDK and we'll have no way to override it to use a version of
commons-codec
that will allow us to use our library.
This is exactly what's happening.
The boot classloader is pre-loaded with classes from the version 1.3 of Commons Codec library.
You can repackage (rename classes's package/namespace) the Commons Codec library to avoid this conflict. See my answer here for more detailed description.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With