Поскольку нет ясного ответа на причину этой проблемы, я хотел бы уточнить, что здесь происходит.
Почему NoSuchMethodError выбрасывается в первую очередь?
Согласно трассировке стека исключений, строка, вызывающая ошибку, равна 226 в методе DigestUtils#md5hex
.Давайте посмотрим, что у нас есть там (я предполагаю, что вы использовали версию 1.4, поскольку это единственный выпуск, где метод Hex#encodeHexString
вызывается в строке 226):
public static String md5Hex(String data) {
return Hex.encodeHexString(md5(data));
}
Исключение говорит java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString
.Давайте поймем почему.
Прежде всего, Android Framework уже включает библиотеку Commons Codec
(кроме класса DigestUtils
).Да, он не является частью Android SDK
, и вы не можете использовать его напрямую.Но вы все еще хотите использовать это.Так, что вы делаете?Вы добавляете библиотеку Commons Codec
как часть вашего приложения.Компилятор не жалуется - с его точки зрения все было хорошо.
Но что происходит во время выполнения?Давайте проследим вашу трассировку стека исключений:
Сначала вы вызываете DigestUtils#md5Hex
из метода вашей деятельности onCreate
.Как я писал выше, среда не включает этот класс, поэтому DigestUtils
(из Commons Codec
версии 1.4) загружается из вашего dex.
Далее, метод md5hex
пытается вызвать метод Hex#encodeHexString
.Класс Hex
является частью библиотеки Commons Codec
, которая включена в каркас.Дело в том, что его версия 1.3 (древний выпуск от июля 2004 года).Класс Hex
существует в bootpath classpath, что означает, что среда выполнения всегда будет отдавать ему предпочтение вместо класса Hex
, упакованного внутри вашего dex.Предупреждения об этом можно увидеть в журналах приложений при запуске приложения (со средой выполнения Dalvik):
D/dalvikvm? DexOpt: 'Lorg/apache/commons/codec/binary/Hex;' has an earlier definition; blocking out
I/dalvikvm? DexOpt: not resolving ambiguous class 'Lorg/apache/commons/codec/binary/Hex;'
D/dalvikvm? DexOpt: not verifying/optimizing 'Lorg/apache/commons/codec/binary/Hex;': multiple definitions
I/dalvikvm? Could not find method org.apache.commons.codec.binary.Hex.encodeHexString, referenced from method org.apache.commons.codec.digest.DigestUtils.md5Hex
Hex # encodeHexString метод был введен в версии 1.4 библиотеки Commons Codec
и поэтому он не существует в классе Hex
фреймворка.Среда выполнения не может найти этот метод и, таким образом, выдает NoSuchMethodError
исключение.
Почему работает решение принятого ответа?
String s = new String(Hex.encodeHex(DigestUtils.md5(data)));
Первый, метод DigestUtils#md5
называется.Как я уже говорил, класс DigestUtils
, который будет использоваться, - это тот, который упакован в вашем dex.Этот метод не использует другие классы Commons Codec
, поэтому проблем с ним нет.
Далее будет вызван Hex#encodeHex
.Класс Hex
, который будет использоваться, является классом фреймворка (версия 1.3).Метод encodeHex
(который принимает один параметр - массив байтов) существует в версии 1.3 библиотеки Commons Codec
, и поэтому этот код будет работать нормально.
Что бы я предложил?
Мое предлагаемое решение - переименовать пространство имен / пакет классов.Тем самым я явно указываю, какой код будет выполняться, и предотвращаю странное поведение, которое может возникнуть из-за проблем с версиями.
Вы можете сделать это вручную (как писал Камон в своем ответе) или автоматически с помощью инструмента jarjar .
См. Сводку этой проблемы и советы по использованию jarjar
в моем blogpost .