Android映射异常java.lang.NoClassDefFoundError:android.security.MessageDigest

时间:2013-04-04 09:28:05

标签: android google-maps noclassdeffounderror

我有一个使用谷歌地图(v1)的应用程序,从崩溃报告中,我不时会看到这个例外:

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:513)
at com.google.android.maps.MapActivity.onCreate(MapActivity.java:409)

我已经定义了

<uses-library
            android:name="com.google.android.maps"
            android:required="true" />

在应用程序标记内部,我也在扩展MapActivity。该应用程序在大多数设备上运行良好,但有一些不常见的报告此异常,通常在Android 4.0.4上,如Woxter Tablet PC 90BL,TAB9008GBBK和其他通用名称。

从我在Stackoverflow中读到的内容来看,它是ROM中的一个问题,它可以通过用户做一些高级技巧来解决,但我想要的是防止这种崩溃,因为我不认为它可以解决,我只想告知用户(以及他们购买更好的设备:)并禁用地图功能而不是崩溃。但我找不到办法处理这个错误或用我的设备测试它。

此外我的主要活动是基于MapActivity,所以我不知道如何在打开它之前处理这个异常。

3 个答案:

答案 0 :(得分:4)

免责声明:我没有在我的任何应用/设备上遇到此错误,但我解决了类似的问题。可能是同样的技术可以帮助你。

假设在加载类时类是unavailable或发生异常,为什么不尝试在应用程序启动时强制加载它? Class.forName("android.security.MessageDigest")应加载该类,您可以捕获该调用引发的Error。我知道它很脏,但它应该工作。您可以在清单上声明自定义Application类来进行此检查。

班级加载测试

    try
    {
        Class.forName("android.security.MessageDigest");
    }
    catch (Throwable e1)
    {
        e1.printStackTrace();
        //Bad device
    }

如果类加载成功,您还可以通过消化简单的String来执行试金石并检查类的功能。

功能测试

    try
    {
        MessageDigest digester = MessageDigest.getInstance("MD5");
        digester.update("test".getBytes("UTF-8"));
        byte[] digest = digester.digest();
    }
    catch (Throwable e1)
    {
        e1.printStackTrace();
        // Class available but not functional
    }

如果类加载/试金石测试失败,请更新共享首选项标记并让用户知道他的设备很糟糕:)

答案 1 :(得分:2)

尝试将导入android.security.MessageDigest更改为java.security.MessageDigest

看看这个链接:

What is 'android.security.MessageDigest''?

看起来android.security.MessageDigest已从Honeycomb中移除,因此将其更改为java。并检查此链接:

http://productforums.google.com/forum/#!category-topic/maps/google-maps-for-mobile/KinrGn9DcIE

正如 @XGouchet 所建议的那样:

  

尝试下载最新版本的Google Maps API并重新设置您的应用程序,并将targetSDK设置为最高版本(截至今日它应为17 / Jelly Bean)。

答案 2 :(得分:1)

android.security.MessageDigest是一个抽象类(参见MessageDigest API),这意味着它无法立即实例化。那么,当设备/应用程序无法找到此类的实现时,您将获得上述异常,即

java.lang.NoClassDefFoundError: android.security.MessageDigest

这是一个很好的问题,为什么会发生这种情况。可能有些手机厂商没有发送带有实际实现这个抽象类的必需库的手机。我过去遇到了与TUN.ko模块类似的问题。

方法1

如果你提供你自己的(空)实现这个类“实现”这样的抽象类和方法,应该有什么帮助:

public class MessageDigestSpi extends Object {
     byte[] engineDigest() { return new byte[0]; }              

     void engineReset() { }

     void engineUpdate(byte[] input, int offset, int len) { }

}

public class MessageDigest extends MessageDigestSpi {

}

...并将这些类放入文件夹<src>/java/security/。因此,通过这种方式,您可以提供始终可以找到的自己的实现,并且可能包含一些代码,以便通知用户或提供替代实现。

所以剩下的问题是:如果系统提供实现,应用程序会做什么,以及如何控制系统实现是第一选择?

答案:选择哪种实施取决于导入顺序。查看Eclipse,您可以在项目属性,Java构建路径,Tab键顺序和导出中定义顺序。确保您的顶部有任何可能包含系统实现的系统库(很可能是Android库)。这样系统首先在这些库中搜索。如果没有找到任何内容,则会加载并执行您的类。

方法2

作为自己的抽象类中实现的替代方法,您当然可以简单地实例化MessageDigest类,捕获NoClassDefFoundError异常并存储结果以供以后评估:

import android.security.MessageDigest;

public class MessageDigestTester {

    private static Boolean messageDigestAvailable = null;

    public static Boolean isLibraryAvailable() {
        if (messageDigestAvailable == null) {
            try {
                MessageDigest digest = MessageDigest.getInstance("MD5");

                messageDigestAvailable = true;

            } catch (NoClassDefFoundError e) {
                messageDigestAvailable = false;
            }

        } 

        return messageDigestAvailable;
    }
}

然后在代码中使用if (MessageDigestTester.isLibraryAvailable()) { } else { }以封装此库的用法并提供替代方法。

方法二更容易实现,而方法一是更复杂的解决方案。

希望这有用...干杯!