23

数千人の顧客のうちの 1 人が、私のアプリの 1 つでエラーを報告しました。エラーは次のとおりです。

java.lang.NoClassDefFoundError - android.security.MessageDigest

アプリでそのクラス/メソッドを使用しません。何千人ものユーザーが同じアプリを同じバージョンで問題なく実行しているため、Google Mapkey は問題ないはずです。スタックトレースは次のとおりです。

java.lang.NoClassDefFoundError: android.security.MessageDigest
at com.google.android.maps.KeyHelper.getSignatureFingerprint(KeyHelper.java:60)
at com.google.android.maps.MapActivity.createMap(MapActivity.java:552)
at com.google.android.maps.MapActivity.onCreate(MapActivity.java:422)
at xx.yyy.zzzz.MyMapActivity.onCreate(MyMapActivity.java:41)
at xx.yyy.zzzz.TheMap.onCreate(TheMap.java:89)
at android.app.Activity.performCreate(Activity.java:4465)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
at android.app.ActivityThread.access$600(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)

これは何ですか?

前もって感謝します。

4

3 に答える 3

20

私はこの問題を調査するのにしばらく時間を費やしました。他の人々のトラブルを救うことを期待して、ここで発見したことを文書化しています。

このエラーは、デバイス メーカーまたは ROM 作成者が新しいバージョンの Android で古いマップ ライブラリを使用した結果です。通常、これはタブレットを目立たなくするために分離されていますが、理論的には他の状況でも発生する可能性があります。次の手順に従って、エミュレーターでこの問題を再現することができます。

  1. Google API を含む古い API (10 以下) 用のエミュレーターを作成してロードする
  2. エミュレーターからマップ jar を抽出します adb pull /system/framework/com.google.android.maps.jar <destination_folder> 。これが完了したら、エミュレーターを閉じることができます。
  3. Google API を含む新しい API (11 以降) のエミュレーターを作成してロードします。
  4. エミュレーターで /system を再マウントして、書き込みできるようにします。adb remount
  5. 抽出したマップ jar を新しいエミュレーターに配置します。adb push <destination_folder>/com.google.android.maps.jar /system/framework
  6. エミュレータを再起動します。これは実行可能であるはずですがadb reboot、エミュレーターがハングアップしました。代わりに、同じ効果を持つ特定のプロセスを強制終了する必要があります。Eclipse/DDMS では呼び出されsystem_process、そこで強制終了できます。または、次のコマンドを実行できます。adb shell ps | grep system_server | awk '{print $2}' | xargs adb shell kill
  7. 再起動後、通常どおりエミュレータを使用できます。Google マップが埋め込まれたアプリの実行は失敗します。

このプロセスは永続的ではありません。エミュレータを再起動すると、通常の動作状態に戻ります。

リフレクションを介してマップ ライブラリのメソッドを取得し、それを呼び出すことで、この問題を検出することができます。引数として a とパッケージ名KeyHelper.getSignatureFingerprint()を渡します。PackageManagerまたは、エラーをトラップして、onCreate()代わりに新しいアクティビティをロードすることもできます。

于 2012-10-24T02:11:43.347 に答える
9

MessageDigest クラスは、MD5 や SHA-1 などの一般的な方法を使用して、キーをエンコード/デコードするために使用されるヘルパー クラスです。

クラス android.security.MessageDigest は Honeycomb 以降の Android リリースから削除されたようで、java.security.MessageDigest に置き換える必要があります (このページを参照) 。

最新バージョンの Google Maps API をダウンロードして、targetSDK を利用可能な最大値に設定してアプリケーションを再構築してください (現時点では 16 / Jelly Bean のはずです)。

于 2012-07-10T06:41:40.753 に答える
9

簡単な回避策を見つけました!src ディレクトリにパッケージ android\security を作成し、その中に MessageDigest.java を配置するだけです。

package android.security;

import java.security.NoSuchAlgorithmException;

public class MessageDigest
{
    private java.security.MessageDigest instance;

    public MessageDigest() {}

    private MessageDigest(java.security.MessageDigest instance)
    {
        this.instance = instance;
    }

    public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException
    {
        if (algorithm == null) return null;

        try
        {
            if (algorithm.equals("SHA-1"))
                return (MessageDigest) Class.forName("android.security.Sha1MessageDigest").newInstance();
            else if (algorithm.equals("MD5"))
                return (MessageDigest) Class.forName("android.security.Md5MessageDigest").newInstance();
        }
        catch (Exception e) {}

        return new MessageDigest(java.security.MessageDigest.getInstance(algorithm));
    }

    public void update(byte[] input)
    {
        instance.update(input);
    }

    public byte[] digest()
    {
        return instance.digest();
    }

    public byte[] digest(byte[] input)
    {
        return instance.digest(input);
    }
}

動作しますが、マップ ライブラリが Android バージョンと一致しないため、他の例外が発生する可能性があります。

于 2013-02-22T09:19:04.577 に答える