4

我有一个使用谷歌地图(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 的,所以我不知道在打开它之前如何处理这个异常。

4

3 回答 3

4

Disclaimer: I've not come across this error on any of my apps / devices but I solved a similar problem. May be that same technique can help you.

Given that the class is either unavailable or an exception occurrs while loading the class, why not try to force load it when your application starts ? Class.forName("android.security.MessageDigest") should load the class and you can catch the Error thrown from that call. I know its dirty, but it should work. You can declare a custom Application class on the manifest to make this check.

Class loading test

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

You can also perform a litmus test and check the functionality of the class should the class loading succeed by digesting a simple String.

Functional test

    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
    }

If the class loading / litmus test fails, update a shared preference flag and let the user know that his device sucks :)

于 2013-04-07T13:00:18.577 回答
2

尝试将导入更改android.security.MessageDigestjava.security.MessageDigest

通过查看此链接:

什么是“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)。

于 2013-04-07T13:18:30.630 回答
1

该类android.security.MessageDigest是一个抽象类(参见MessageDigest API),这意味着它不能立即实例化。所以发生的事情是,任何时候设备/应用程序找不到此类的实现,您都会得到上面的异常,即

java.lang.NoClassDefFoundError: android.security.MessageDigest

这是一个很好的问题,为什么会发生这种情况。可能是一些电话供应商没有在他们的电话中提供实际实现这个抽象类的所需库。我过去曾遇到过与该TUN.ko模块类似的问题。

方法一

应该有帮助的是,如果您提供此类的自己的(空)实现,该实现“实现”抽象类和方法,如下所示:

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 构建路径、选项卡顺序和导出中定义顺序。确保您有任何可能包含系统实现的系统库(最有可能是 Android 库)。这样系统首先在这些库中搜索。如果什么也没找到,你的类就会被加载并执行。

方法二

作为在自己的抽象类中实现的替代方案,您当然可以简单地实例化 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 { }在您的代码中使用以封装该库的使用并提供替代方案。

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

希望这会有所帮助......干杯!

于 2013-04-07T13:30:46.500 回答