web-dev-qa-db-ja.com

AndroidでDigestUtilsを使用してメソッドが見つかりません

JDK 1.6を使用してAndroid 2.3.1でライブラリ DigestUtils を使用しようとしていますが、アプリを実行すると次のエラーが表示されます。

_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: 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)
_

例外の原因となるコード行は次のとおりです。

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

Javaの外のAndroidクラスで同じコードを実行しましたが、動作します!そのため、Androidを操作するときに動作しない理由がわかりません...アプリの新しいlibs /フォルダー内にlibratyを配置し、それを使用するようにBuildPathを更新しました。 sha1の代わりにmd5を使用しようとすると、同じ例外が発生します。助けていただければ幸いです!ありがとうございました。

UPDATE:

これは非常に活発な質問なので、彼の解決策は簡単であり、多数の賛成票がそれが機能することを証明しているので、@ DA25に代わって受け入れられた答えを変更しました。

68
Caumons

私はAndroidアプリでDigestUtilsを使用しようとすると同じ問題に遭遇しました。これは検索で見つけることができる最良の答えでしたが、名前空間を変更して.jarファイルを再構築しませんでした。この問題にしばらく時間を費やした後、自分のケースの問題を解決する簡単な方法を見つけました。

String s = DigestUtils.md5Hex(data);

このステートメントを次のものに置き換えれば、機能します。

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

同様に、shaHex examplの場合は、次のように変更できます。

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

これは、AndroidにencodeHexString()がなく、encodeHex()があるためです。同じ問題に遭遇する他の人に役立つことを願っています。

135
DA25

この問題の根本原因に対する明確な答えはないので、ここで何が起こっているのかを明確にしたいと思います。

最初にNoSuchMethodErrorがスローされるのはなぜですか?

例外スタックトレースによると、DigestUtils#md5hexメソッドのフォールトを引き起こす行は226です。私たちが持っているものを見てみましょう あり (バージョン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フレームワークにはCommons Codecライブラリが既に含まれています(DigestUtilsクラスを除く)。はい、Android SDKの一部として公開されていないため、直接使用できません。しかし、あなたはまだそれを使いたいので、あなたは何をしますか?アプリケーションの一部としてCommons Codecライブラリを追加すると、コンパイラは文句を言いません-彼の観点からはすべてがうまくいきました。

しかし、実行時にはどうなりますか?例外スタックトレースを見てみましょう。
最初に、アクティビティのonCreateメソッドからDigestUtils#md5Hexを呼び出しています。上で書いたように、フレームワークにはそのクラスが含まれていないので、DigestUtilsCommons Codecバージョン1.4から)がdexからロードされます。
次に、md5hexメソッドはHex#encodeHexStringメソッドの呼び出しを試みます。 Hexクラスは、フレームワークに含まれるCommons Codecライブラリの一部です。問題は、そのバージョンが1.3(2004年7月からの古代リリース)であることです。 Hexクラスはブートクラスパスに存在します。つまり、ランタイムは、dex内にパッケージ化されたHexクラスではなく、常にそれを優先します。 (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 メソッドはCommons Codecライブラリのバージョン1.4で導入されたため、フレームワークのHexクラスには存在しません。ランタイムはこのメソッドを見つけることができないため、NoSuchMethodError例外をスローします。

受け入れられた答えのソリューションが機能する理由

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

最初に、DigestUtils#md5メソッドが呼び出されます。既に述べたように、使用されるDigestUtilsクラスは、dexにパッケージ化されたものです。このメソッドは他のCommons Codecクラスを使用しないため、問題ありません。

次に、Hex#encodeHexが呼び出されます。使用されるHexクラスは、フレームワークのバージョン(バージョン1.3)です。 Commons Codecライブラリのバージョン1.3にはencodeHexメソッド(単一のパラメーター-バイト配列を取る)が存在するため、このコードは正常に機能します。

私は何を提案しますか?

私の提案する解決策は、クラスの名前空間/パッケージの名前を変更することです。そうすることで、実行するコードを明示的に指定し、バージョン管理の問題が原因で発生する可能性のある奇妙な動作を防ぎます。

手動で(Caumonsが答えに書いたように)、または jarjar ツールで自動的に行うことができます。

この問題の概要と blogpostjarjarを使用するためのヒントを参照してください。

31
Alex Lipov

最終的に私は答えを得て、それはうまくいきます。 Apacheコーデックではこのようなメソッドエラーはありません 別のタイプの暗号化(Base64)で説明したように、同じ問題を再現しようとしましたが、まったく同じエラーが発生します。だから、私は添付の質問の場合でした。彼らが言うように、それはパッケージ名org.Apache.commons.codecとの内部名の衝突のようです。@ Donが述べたように、私はそれをcom.Apache.commons.codecに変更し、うまくいきました!どうやって?

ソースコードをダウンロードし、3つのディレクトリorgcomに変更しました。また、ファイル内のパッケージ名の出現箇所をすべて置き換え、ドキュメント内の参照をcom/Apache/commons/codec/に変更しました。 (手動でそれらを再生しようとしないでください、さもないとあなたは穴の日を過ごすでしょう)。次に、ライブラリをコンパイルし、Antでjarを生成しました。これをcommons-codec-1.6-Android.jarと呼びました。 jarをAndroidアプリのlibs/フォルダーに入れ、ビルドパスに追加しました。また、すべてのファイルを含むフォルダーとしてソースを添付しました。 Androidで使用するには!

それが他の誰かを助けることを願っています!

19
Caumons

ありがとう@ DA25

これは私のためにうまく機能しています

依存関係を追加しました

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

参照: http://mvnrepository.com/artifact/commons-codec/commons-codec/1.9

私の機能

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

私の場合、proguardは難読化中にクラスを削除しました。これをProguardルールに追加します。

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

Apacheパッケージで使用していた方法を次に示します。

Hex.encodeHex(digest)
2

以下のコードを使用しましたが、うまくいきました:

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

メソッドを追加

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