Método no encontrado con DigestUtils en Android

Estoy tratando de usar la biblioteca DigestUtils en Android 2.3.1 usando JDK 1.6, sin embargo me sale el siguiente error al ejecutar la aplicación:

Could not find method org.apache.commons.codec.binary.Hex.encodeHexString, referenced from method org.apache.commons.codec.digest.DigestUtils.shaHex

Aquí tienes el stacktrace:

 02-03 10:25:45.153: I/dalvikvm(1230): Could not find method org.apache.commons.codec.binary.Hex.encodeHexString, referenced from method org.apache.commons.codec.digest.DigestUtils.shaHex 02-03 10:25:45.153: W/dalvikvm(1230): VFY: unable to resolve static method 329: Lorg/apache/commons/codec/binary/Hex;.encodeHexString ([B)Ljava/lang/String; 02-03 10:25:45.153: D/dalvikvm(1230): VFY: replacing opcode 0x71 at 0x0004 02-03 10:25:45.153: D/dalvikvm(1230): VFY: dead code 0x0007-0008 in Lorg/apache/commons/codec/digest/DigestUtils;.shaHex ([B)Ljava/lang/String; 02-03 10:25:45.163: D/AndroidRuntime(1230): Shutting down VM 02-03 10:25:45.163: W/dalvikvm(1230): threadid=1: thread exiting with uncaught exception (group=0x40015560) 02-03 10:25:45.173: E/AndroidRuntime(1230): FATAL EXCEPTION: main 02-03 10:25:45.173: E/AndroidRuntime(1230): java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString 02-03 10:25:45.173: E/AndroidRuntime(1230): at org.apache.commons.codec.digest.DigestUtils.md5Hex(DigestUtils.java:226) 02-03 10:25:45.173: E/AndroidRuntime(1230): at com.caumons.trainingdininghall.ConnectionProfileActivity.onCreate(ConnectionProfileActivity.java:20) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1586) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1638) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.access$1500(ActivityThread.java:117) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:928) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.os.Handler.dispatchMessage(Handler.java:99) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.os.Looper.loop(Looper.java:123) 02-03 10:25:45.173: E/AndroidRuntime(1230): at android.app.ActivityThread.main(ActivityThread.java:3647) 02-03 10:25:45.173: E/AndroidRuntime(1230): at java.lang.reflect.Method.invokeNative(Native Method) 02-03 10:25:45.173: E/AndroidRuntime(1230): at java.lang.reflect.Method.invoke(Method.java:507) 02-03 10:25:45.173: E/AndroidRuntime(1230): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 02-03 10:25:45.173: E/AndroidRuntime(1230): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 02-03 10:25:45.173: E/AndroidRuntime(1230): at dalvik.system.NativeStart.main(Native Method) 

La línea de código que causa la excepción es:

String hash = DigestUtils.shaHex("textToHash");

He ejecutado el mismo código en una clase Java fuera de Android y funciona! Por lo tanto, no sé por qué al trabajar con Android no funciona … Pongo el libraty dentro de una libs / carpeta nueva en mi aplicación y actualizó el BuildPath para usarlo. Si intento usar md5 en lugar de sha1 obtengo la misma excepción. ¡Cualquier ayuda sería apreciada! Gracias.

ACTUALIZAR:

Como esta es una pregunta muy activa, he cambiado la respuesta aceptada a favor de @ DA25, ya que su solución es sencilla y el alto número de upvotes demuestra que funciona.

Me encontré con el mismo problema tratando de usar DigestUtils en mi aplicación para Android. Esta fue la mejor respuesta que pude encontrar al buscar, pero estaba reacio a reconstruir el archivo .jar con el espacio de nombres cambiado. Después de pasar algún tiempo en este tema, encontré una manera más fácil de resolver el problema para mi caso. La sentencia de problema para mi código fue

 String s = DigestUtils.md5Hex(data); 

Reemplace esta declaración con lo siguiente y funcionará:

 String s = new String(Hex.encodeHex(DigestUtils.md5(data))); 

Del mismo modo, para el ejemplo de shaHex, puede cambiarlo a

 String hash = new String(Hex.encodeHex(DigestUtils.sha("textToHash"))); 

Esto funciona porque aunque Android no tiene codificarHexString (), tiene codificarHex (). Espero que esto ayude a otros que se encuentran con el mismo problema.

Dado que no hay una respuesta clara para la causa raíz de este problema, me gustaría aclarar lo que está sucediendo aquí.

¿Por qué el NoSuchMethodError se lanza en primer lugar?

De acuerdo con el rastreo de la pila de excepciones, la línea que causa el error es 226 en DigestUtils#md5hex método DigestUtils#md5hex . Vamos a ver lo que tenemos allí (estoy asumiendo que ha utilizado la versión 1.4, ya que esta es la única versión donde Hex#encodeHexString método Hex#encodeHexString se invoca en la línea 226):

 public static String md5Hex(String data) { return Hex.encodeHexString(md5(data)); } 

La excepción dice java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString . Vamos a entender por qué.

En primer lugar, el marco de Android ya incluye la biblioteca Commons Codec (excepto la clase DigestUtils ). Sí, no está expuesto como parte del Android SDK y no puede utilizarse directamente. Pero todavía quieres usarlo. ¿Entonces, que haces? Añade biblioteca Commons Codec como parte de su aplicación. El compilador no se queja – desde su punto de vista todo estaba bien.

Pero, ¿qué ocurre en tiempo de ejecución? Sigamos su rastro de la pila de excepciones:
Primero, estás llamando DigestUtils#md5Hex desde el método DigestUtils#md5Hex de tu actividad. Como escribí anteriormente, el marco no incluye esa clase, por lo que DigestUtils (de Commons Codec versión 1.4) se carga desde tu dex.
A continuación, el método md5hex intenta invocar Hex#encodeHexString método Hex#encodeHexString . Hex clase Hex es parte de la biblioteca Commons Codec incluida en el framework. La cosa es que su versión es 1.3 (lanzamiento antiguo de julio de 2004). Hex clase Hex existe en el classpath de arranque, lo que significa que el tiempo de ejecución siempre lo favorecerá en lugar de la clase Hex que se empaquetó dentro de su dex. Puede ver advertencias en los registros de la aplicación cuando inicie su aplicación (con el tiempo de ejecución de 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 

El método hexadecimal # encodeHexString se introdujo en la versión 1.4 de la biblioteca Commons Codec y por lo tanto no existe en la clase Hex del framework. El tiempo de ejecución no puede encontrar este método y, por tanto, lanza NoSuchMethodError excepción.

¿Por qué funciona la solución de respuesta aceptada?

 String s = new String(Hex.encodeHex(DigestUtils.md5(data))); 

Primero, se llama al método DigestUtils#md5 . Como ya he dicho, la clase DigestUtils que se utilizará es la que se empaqueta en su dex. Este método no utiliza ninguna otra clase de Commons Codec , así que no hay problema con ella.

A continuación, se Hex#encodeHex . La clase Hex que se utilizará es la del framework (versión 1.3). El método encodeHex (que toma un solo parámetro – matriz de bytes) existe en la versión 1.3 de la biblioteca Commons Codec , y por lo tanto este código funcionará bien.

¿Qué sugiero?

Mi solución sugerida es cambiar el nombre del espacio de nombres / paquete de las clases. Al hacerlo, estoy especificando explícitamente qué código se va a ejecutar, y evitar el comportamiento extraño que puede ocurrir debido a problemas de control de versiones.

Puedes hacerlo manualmente (como escribió Caumons en su respuesta), o automáticamente con la herramienta jarjar .

Vea este resumen y consejos para usar jarjar en mi blogpost .

Finalmente consigo la respuesta y funciona bien. Como se describe en No tal error de método en el códec Apache para otro tipo de cifrado (Base64) traté de reproducir el mismo problema y recibo exactamente el mismo error. Así que yo estaba en el caso de la pregunta adjunta. Como dicen, parece ser una colisión de nombre interno con el nombre del paquete org.apache.commons.codec y como lo declaró @Don lo cambié a com.apache.commons.codec y funcionó bien! ¿Cómo lo hice?

Descargé el código fuente y cambié los 3 directorios org a com . También reemplazé todas las apariciones del nombre del paquete en los archivos donde aparecen y también cambié las referencias en los documentos a com/apache/commons/codec/ . (No trate de remane ellos manualmente o usted pasará el día del agujero). Luego compilé la biblioteca y generé el tarro con Ant, que llamé commons-codec-1.6-android.jar . Puse el tarro en la libs/ carpeta de mi aplicación de Android y lo agregué al buildpath. Además, adjunto las fuentes como la carpeta que contiene todos los archivos. Así que ahora tengo la biblioteca lista para usar con Android!

Espero que ayude a alguien más!

Gracias @ DA25

Esto está funcionando bien para mí

Tengo add dependencia

 compile 'commons-codec:commons-codec:1.9' 

Ref: http://mvnrepository.com/artifact/commons-codec/commons-codec/1.9

Mi función

 public String encode(String key, String data) { try { Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256"); sha256_HMAC.init(secret_key); return new String(Hex.encodeHex(sha256_HMAC.doFinal(data.getBytes("UTF-8")))); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } 
  • ¿Cómo puedo hacer que sea más difícil para los jugadores hackear datos de nivel de juego?
  • Cómo cifrar y descifrar archivos en Android?
  • Android cómo proteger contenido en el directorio de documentos
  • Descifrar audio / video sobre la marcha a MediaPlayer
  • Error de descifrado en Android 4.4
  • ¿Cuál es la forma más adecuada de almacenar la configuración de usuario en la aplicación de Android?
  • ¿Cómo almacenar módulo, exponente público y exponente privado de forma segura en Android?
  • ¿Es posible escribir un wifi cracking util para teléfonos Android? Modo de monitor vs Multicast?
  • ¿Cifrado de archivos de vídeo?
  • Android Keystore - ¿se puede recuperar una clave de usuario por root si se establece en ese usuario?
  • ¿Dónde almacenar las claves del algoritmo de cifrado?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.