23

数千名客户中的一位报告了我的一个应用程序中的错误。错误是:

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. 重新启动后,您可以像往常一样使用模拟器。运行任何嵌入了谷歌地图的应用程序都会失败。

这个过程不是永久性的。重新启动模拟器会将其恢复到正常工作状态。

KeyHelper.getSignatureFingerprint()可以通过反射获取地图库中的方法并调用它来检测此问题- 将 aPackageManager和您的包名称作为参数传递。或者,您可以捕获错误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 回答