83

JDK1.6を使用してAndroid2.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");

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

アップデート:

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

4

8 に答える 8

152

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

String s = DigestUtils.md5Hex(data);

このステートメントを次のように置き換えると、機能します。

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

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

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

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

于 2012-02-14T20:59:00.537 に答える
37

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

そもそもなぜNoSuchMethodErrorがスローされるのですか?

例外スタックトレースによると、障害の原因となる行はDigestUtils#md5hexメソッドで226です。そこにあるものを見てみましょう(これはHex#encodeHexString226行目でメソッドが呼び出されている唯一のリリースであるため、バージョン1.4を使用していると仮定します):

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アプリケーションの一部としてライブラリを追加します。コンパイラは文句を言いません-彼の観点からは、すべてが順調でした。

しかし、実行時に何が起こりますか?例外スタックトレースをたどってみましょう。まず、アクティビティのメソッドから
呼び出しています。上で書いたように、フレームワークにはそのクラスが含まれていないため、(バージョン1.4から)dexからロードされます。 次に、メソッドはメソッドを呼び出そうとします。クラスは、フレームワークに含まれているライブラリの一部です。問題は、そのバージョンが1.3(2004年7月からの古代リリース)であるということです。クラスはブートクラスパスに存在します。つまり、ランタイムは、dex内にパッケージ化されたクラスではなく常にそれを優先します。(Dalvikランタイムを使用して)アプリを起動すると、アプリケーションログに警告が表示されます。 DigestUtils#md5HexonCreateDigestUtilsCommons Codec
md5hexHex#encodeHexStringHexCommons CodecHexHex

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メソッドはライブラリのバージョン1.4で導入されたため、フレームワークのクラスCommons Codecには存在しません。Hexランタイムはこのメソッドを見つけることができないため、NoSuchMethodError例外をスローします。

受け入れられた回答の解決策が機能するのはなぜですか?

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

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

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

私は何を提案しますか?

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

手動で(Caumonsが彼の回答に書いたように)、またはjarjarツールを使用して自動的に行うことができます。

この問題の概要と私のブログ投稿で使用jarjarするためのヒントを参照してください

于 2015-04-23T19:55:38.143 に答える
19

最後に私は答えを得て、それはうまくいきます。別の種類の暗号化(Base64)のApacheコーデックでこのようなメソッドエラーが発生しないで説明したように、同じ問題を再現しようとしましたが、まったく同じエラーが発生します。だから私は添付の質問の場合でした。彼らが言うように、それはパッケージ名との内部名の衝突のようであり、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をlibs/Androidアプリのフォルダーに入れて、ビルドパスに追加しました。また、すべてのファイルを含むフォルダーとしてソースを添付しました。これで、ライブラリをAndroidで使用できるようになりました。

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

于 2012-02-04T11:11:00.483 に答える
3

ありがとう@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;
}
于 2016-03-14T07:52:31.557 に答える
1

私にとって、プロガードは難読化中にクラスを削除しました。これをプロガードルールに追加してください。

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

これが私がapacheパッケージで使用していた方法です。

Hex.encodeHex(digest)
于 2017-10-30T06:30:23.850 に答える
0

メソッドを追加

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);
}
于 2017-12-08T16:23:10.663 に答える
0

以下のコードを使用しましたが、機能しました:

  HmacUtils hmacUtils = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, keyString);
  String digest = new String( Hex.encodeHex(hmacUtils.hmac(msg)));
于 2019-05-02T14:40:36.603 に答える
0

クラスの名前を変更する別の方法DigestUtilsは、proguardを使用することです。プロガードを使用していない場合は、プロガードを有効にして、DigestUtilsクラスのみを難読化するこの1行を追加し、他のすべてをそのままにしておくことができます。

-keep class !org.apache.commons.codec.digest.DigestUtils,com.** { *; }

これをアプリに追加しますbuild.gradle

buildTypes {
        debug {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

またはオプション2 コードで古いバージョンのライブラリを使用します。

implementation("commons-codec:commons-codec:1.3"){
        force = true
    }

force = true依存関係がサードパーティライブラリからのものである場合は使用する必要がcommon-codecあります。そうでない場合、Gradleはデフォルトで上位バージョンに解決されます。

于 2019-10-02T12:14:11.713 に答える