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
- Android: Cómo descomprimir un archivo zip cifrado
- Descodificación de cifrado RSA en Android
- Cómo descifrar AndroidManifest.xml
- Transferencia PrivateKey de KeyStore, uso en OpenSSL con JNI
- Cómo proteger las preferencias compartidas de Android?
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.
- Encriptación de Android "bloque pad bloqueado" excepción
- Error de cifrado en Android 4.2
- Android cifrar / descifrar sqlite base de datos 100% seguro
- Android - Almacenamiento seguro
- Cómo proteger los datos de intención mientras lo envía a través de aplicaciones
- Facebook ocultar - cifrado y descifrado de la imagen
- Descifrar Android SSE con OpenSSL
- SetStorageEncryption no produce ningún efecto
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; }
- No hay números de línea en Eclipse o en el editor de Android Studio XML.
- ¿Cómo cambiar el idioma de la aplicación cuando el usuario selecciona el idioma?