it-swarm.com.de

Methode nicht gefunden mit DigestUtils in Android

Ich versuche, die Bibliothek zu verwenden DigestUtils in Android 2.3.1 mit JDK 1.6, es wird jedoch die folgende Fehlermeldung angezeigt, wenn die App ausgeführt wird:

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

Hier haben Sie den 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)

Die Codezeile, die die Ausnahme verursacht, lautet:

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

Ich habe den gleichen Code in einer Java Klasse außerhalb Android ausgeführt und es funktioniert! Also, ich weiß nicht warum, wenn ich mit Android es funktioniert nicht ... Ich habe die Bibliothek in einen neuen libs/-Ordner in meiner App gestellt und BuildPath aktualisiert, um sie zu verwenden.Wenn ich versuche, md5 anstelle von sha1 zu verwenden, erhalte ich dieselbe Ausnahme geschätzt werden! Danke.

UPDATE:

Da dies eine sehr aktive Frage ist, habe ich die akzeptierte Antwort zu Gunsten von @ DA25 geändert, da seine Lösung unkompliziert ist und die hohe Anzahl von Upvotes beweist, dass es funktioniert.

68
Caumons

Beim Versuch, DigestUtils in meiner App Android=) zu verwenden, trat das gleiche Problem auf. Dies war die beste Antwort, die ich bei der Suche finden konnte, aber ich wollte die JAR-Datei nur ungern mit dem geänderten Namespace neu erstellen. Nachdem ich einige Zeit mit diesem Problem verbracht hatte, fand ich einen einfacheren Weg, das Problem für meinen Fall zu lösen

String s = DigestUtils.md5Hex(data);

Ersetzen Sie diese Anweisung durch die folgende und es wird funktionieren:

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

Ebenso können Sie zum Beispiel shaHex auf ändern

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

Dies funktioniert, weil Android hat nicht encodeHexString (), es hat encodeHex (). Ich hoffe, dies würde anderen helfen, die auf das gleiche Problem stoßen.

135
DA25

Da es keine eindeutige Antwort auf die eigentliche Ursache dieses Problems gibt, möchte ich klarstellen, was hier vor sich geht.

Warum wird der NoSuchMethodError zuerst ausgelöst?

Gemäß dem Ausnahmestapel-Trace ist die Zeile, die den Fehler verursacht, 226 in der Methode DigestUtils#md5hex. Mal sehen, was wir haben dort (Ich nehme an, Sie haben Version 1.4 verwendet, da dies die einzige Version ist, in der die Hex#encodeHexString - Methode in Zeile 226 aufgerufen wird):

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

Die Ausnahme lautet Java.lang.NoSuchMethodError: org.Apache.commons.codec.binary.Hex.encodeHexString. Verstehen wir mal warum.

Zunächst einmal enthält das Android Framework bereits die Commons Codec - Bibliothek (mit Ausnahme der DigestUtils -Klasse). Ja, es wird nicht als Teil von Android SDK Und Sie können es nicht direkt verwenden. Aber Sie möchten es trotzdem verwenden. Also, was Sie tun? Sie fügen die Bibliothek Commons Codec Als Teil Ihrer Anwendung hinzu. Der Compiler beschwert sich nicht - aus seiner Sicht alles war in Ordnung.

Aber was passiert zur Laufzeit? Lassen Sie uns die Ablaufverfolgung Ihres Ausnahmestapels verfolgen:
Zuerst rufen Sie DigestUtils#md5Hex Mit der onCreate -Methode Ihrer Aktivität auf. Wie ich oben geschrieben habe, enthält das Framework diese Klasse nicht, daher wird DigestUtils (ab Commons Codec Version 1.4) aus Ihrem Dex geladen.
Als nächstes versucht die Methode md5hex Die Methode Hex#encodeHexString Aufzurufen. Die Klasse Hex ist Teil der Bibliothek Commons Codec, die im Framework enthalten ist. Das Ding ist, dass seine Version 1.3 ist (alte Veröffentlichung von Juli 2004). Die Klasse Hex ist im Startklassenpfad vorhanden. Dies bedeutet, dass sie zur Laufzeit immer vor der Klasse Hex bevorzugt wird, die in Ihrem Dex enthalten ist. Sie können Warnungen dazu in Ihren Anwendungsprotokollen sehen, wenn Sie Ihre App starten (mit Dalvik Runtime):

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

Die Methode Hex # encodeHexString wurde in Version 1.4 der Bibliothek Commons Codec Eingeführt und ist daher in der Klasse Hex des Frameworks nicht vorhanden. Die Laufzeitumgebung kann diese Methode nicht finden und löst daher die Ausnahme NoSuchMethodError aus.

Warum funktioniert die Lösung der akzeptierten Antwort?

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

Zunächst wird die Methode DigestUtils#md5 Aufgerufen. Wie bereits erwähnt, wird die Klasse DigestUtils verwendet, die in Ihrem Dex enthalten ist. Diese Methode benutzt keine anderen Commons Codec Klassen, also kein Problem damit.

Als nächstes wird Hex#encodeHex Aufgerufen. Die Hex-Klasse, die verwendet wird, ist die Framework-Klasse (Version 1.3). Die encodeHex -Methode (die ein einzelnes Parameter-Byte-Array akzeptiert) ist in Version 1.3 der Bibliothek Commons Codec Vorhanden. Daher funktioniert dieser Code einwandfrei.

Was würde ich vorschlagen?

Meine vorgeschlagene Lösung besteht darin, den Namespace/das Package der Klasse umzubenennen. Auf diese Weise gebe ich explizit an, welcher Code ausgeführt werden soll, und verhindere bizarres Verhalten, das aufgrund von Versionsproblemen auftreten kann.

Sie können dies manuell (wie Caumons in seiner Antwort schrieb) oder automatisch mit dem Tool jarjar tun.

Lesen Sie die Zusammenfassung dieses Problems und Tipps zur Verwendung von jarjar in meinem Blogpost .

31
Alex Lipov

Endlich bekomme ich die Antwort und es funktioniert gut. Wie unter Kein solcher Methodenfehler im Apache-Codec für einen anderen Verschlüsselungstyp (Base64) beschrieben, habe ich versucht, dasselbe Problem zu reproduzieren, und es wird genau derselbe Fehler angezeigt. Ich war also im Falle der Frage beigefügt. Wie sie sagen, scheint es sich um eine interne Namenskollision mit dem Paketnamen org.Apache.commons.codec Zu handeln, und wie von @Don angegeben, habe ich ihn in com.Apache.commons.codec Geändert und funktioniert! Wie habe ich das gemacht?

Ich habe den Quellcode heruntergeladen und die 3 Verzeichnisse org in com geändert. Ich habe auch alle Vorkommen des Paketnamens in den Dateien, in denen sie vorkommen, ersetzt und die Verweise in den Dokumenten in com/Apache/commons/codec/ Geändert. (Versuchen Sie nicht, sie manuell nachzubessern, sonst verbringen Sie den ganzen Tag). Dann habe ich die Bibliothek kompiliert und das Glas mit Ant generiert, das ich commons-codec-1.6-Android.jar Nannte. Ich habe das Glas in den Ordner libs/ Meiner App Android=) gelegt und in den Erstellungspfad eingefügt. Außerdem habe ich die Quellen als Ordner angehängt, der alle Dateien enthält Ich habe die Bibliothek bereit, mit Android zu verwenden!

Hoffe, dass es jemand anderem hilft!

19
Caumons

Vielen Dank @ DA25

Das funktioniert gut für mich

Ich habe Abhängigkeit hinzufügen

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

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

meine Funktion

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;
}
2
Bikesh M

Für mich hat proguard die Klasse während der Verschleierung entfernt. Fügen Sie dies zu Ihren Proguard-Regeln hinzu.

-keep class org.Apache.commons.** { *; }

Hier ist die Methode, die ich von Apache-Paket verwendet habe.

Hex.encodeHex(digest)
2

Wir haben folgenden Code verwendet und es hat funktioniert:

  HmacUtils hmacUtils = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, keyString);
  String digest = new String( Hex.encodeHex(hmacUtils.hmac(msg)));
0
Alok Gupta

Methode hinzufügen

public static String byteArrayToHexString(byte[] bytes) {
    final char[] toDigits = "0123456789abcdef".toCharArray();
    int l = bytes.length;
    char[] out = new char[l << 1];

    int i = 0; for (int j = 0; i < l; ++i) {
        out[(j++)] = toDigits[((0xF0 & bytes[i]) >>> 4)];
        out[(j++)] = toDigits[(0xF & bytes[i])];
    }
    return new String(out);
}
0
reznic