Description
Hi, while using your library I encountered the following runtime exception, which crashes my app:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xxxx.yyyy, PID: 17510
java.lang.NoSuchMethodError: No static method decodeBase64(Ljava/lang/String;)[B in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar)
at com.xxxx.yyyy.network.RealNetworkController$2.onResponse(RealNetworkController.java:172)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
This is caused by your use of the Apache Commons Codec library, in JWTDecoder.java:38:
headerJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[0]));
payloadJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[1]));
I have investigated the issue, and I believe it's down to an obscure problem with Android.
The Problem
Until recently, Android was bundled with Apache's HttpClient, which depended on Commons Codec.
However, the version originally bundled with Android (1.3) does not contain the static decodeBase64(String)
method. Furthermore, this ancient version overrides the version you specify in your lib's build.gradle
.
For a better explanation, see this blog post, and these stack overflow posts:
- http://stackoverflow.com/a/34473643
- http://stackoverflow.com/a/5902269
- http://stackoverflow.com/questions/24306695/base64-dependencies-issue-in-android-studio
The reason you (the developers of java-jwt) may not have been experiencing this error and I have, is because this ancient dependency has been removed from android entirely, after SDK 23 (version 6.0), removing the problem.
Unfortunately for me, my app's minimum version is 4.4 (SDK 19), so I suspect that the legacy code is still in my classpath (this is corroborated by the exception message I pasted above:
declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar
This effectively gives your library an undocumented requirement for Android SDK 23 and above!
The Solution
Some people have been using a workaround, but I would recommend that you simply replace your Commons Codec call with the android-internal Base64 implementation. I will be submitting a pull request to this effect, if/when I have time.
TL;DR
You have an obscure bug to do with historical dependencies in Android on Apache Commons Codec.
I'll submit a PR when I can.