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に代わって受け入れられた答えを変更しました。
私は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()があるためです。同じ問題に遭遇する他の人に役立つことを願っています。
この問題の根本原因に対する明確な答えはないので、ここで何が起こっているのかを明確にしたいと思います。
最初に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
を呼び出しています。上で書いたように、フレームワークにはそのクラスが含まれていないので、DigestUtils
(Commons 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 ツールで自動的に行うことができます。
この問題の概要と blogpost でjarjar
を使用するためのヒントを参照してください。
最終的に私は答えを得て、それはうまくいきます。 Apacheコーデックではこのようなメソッドエラーはありません 別のタイプの暗号化(Base64)で説明したように、同じ問題を再現しようとしましたが、まったく同じエラーが発生します。だから、私は添付の質問の場合でした。彼らが言うように、それはパッケージ名org.Apache.commons.codec
との内部名の衝突のようです。@ Donが述べたように、私はそれをcom.Apache.commons.codec
に変更し、うまくいきました!どうやって?
ソースコードをダウンロードし、3つのディレクトリorg
をcom
に変更しました。また、ファイル内のパッケージ名の出現箇所をすべて置き換え、ドキュメント内の参照をcom/Apache/commons/codec/
に変更しました。 (手動でそれらを再生しようとしないでください、さもないとあなたは穴の日を過ごすでしょう)。次に、ライブラリをコンパイルし、Antでjarを生成しました。これをcommons-codec-1.6-Android.jar
と呼びました。 jarをAndroidアプリのlibs/
フォルダーに入れ、ビルドパスに追加しました。また、すべてのファイルを含むフォルダーとしてソースを添付しました。 Androidで使用するには!
それが他の誰かを助けることを願っています!
ありがとう@ 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;
}
私の場合、proguardは難読化中にクラスを削除しました。これをProguardルールに追加します。
-keep class org.Apache.commons.** { *; }
Apacheパッケージで使用していた方法を次に示します。
Hex.encodeHex(digest)
以下のコードを使用しましたが、うまくいきました:
HmacUtils hmacUtils = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, keyString);
String digest = new String( Hex.encodeHex(hmacUtils.hmac(msg)));
メソッドを追加
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);
}