NoSuchMethodError: org.apache.co

2019-07-31  本文已影响0人  DD_Dog

一、问题描述

在Android项目中使用到了org.apache.commons.codec.jar包下的DigestUtils.md5Hex()获取文件的md5值,结果编译通过,运行时总是报java.lang.NoSuchMethodError:org.apache.commons.codec.binary.Hex.encodeHexString([B)Ljava/lang/String;错误
我在APP中使用的是common-codec-1.9.jar

调用代码如下:

//直接传入文件输入流就可以得到文件的标准md5值
String cacheDirMd5Hex = DigestUtils.md5Hex(new FileInputStream(file));
String assetMd5Hex = DigestUtils.md5Hex(FileUtils.getBytes(context.getAssets().open(SkinConfig.SKIN_DIR_NAME + File.separator + fileName)));
DDLog.i(getClass(), "assetMd5Hex=" + assetMd5Hex + ",cacheDirMd5Hex=" +cacheDirMd5Hex);
if (!TextUtils.equals(assetMd5Hex, cacheDirMd5Hex)){    //如果缓存路径中与assets中的文件不相同
    DDLog.i(getClass(), "skin资源文件校验错误");
    file.delete();
    SkinFileUtils.copySkinAssetsToDir(context, fileName, SkinFileUtils.getSkinDir(context));
}

栈信息如下 :

System.err: java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString
System.err:     at org.apache.commons.codec.digest.DigestUtils.md5Hex(DigestUtils.java:310)
System.err:     at com.skin.loader.SkinManager.setUpSkinFile(SkinManager.java:106)
System.err:     at com.skin.loader.SkinManager.access$100(SkinManager.java:38)
System.err:     at com.skin.loader.SkinManager$1.run(SkinManager.java:73)

二、先上解决办法

既然找不到该方法,那么让它找到这个方法或者使用其它方法就可以解决此问题。
思路一是:保证AndroidStudio中调用的API与系统中的API版本一致,这样就不会导致方法找不到的问题。
思路二是:去掉系统中的相关API,这样就应用就会只调用我们自己APP中的API,但是这样未免代价太大,而且系统中其它地方可能对这些API有依赖,不推荐。

方法一、依据思路一:在AndroidStudio中使用1.3或者更低版本的API

另寻途径,改用其它方法。高版本的API使用起来是更方便快捷的,更换到低版本后就需要自己手动做一些工作了
1.3版本的DigestUtils.md5Hex(byte[] data)只能传入字节数组,所以需要自己把文件读出转换成字节数组才行

String cacheDirMd5Hex = DigestUtils.md5Hex(FileUtils.getBytes(file));
String assetMd5Hex = DigestUtils.md5Hex(FileUtils.getBytes(context.getAssets().open(SkinConfig.SKIN_DIR_NAME + File.separator + fileName)));
DDLog.i(getClass(), "assetMd5Hex=" + assetMd5Hex + ",cacheDirMd5Hex=" +cacheDirMd5Hex);
if (!TextUtils.equals(assetMd5Hex, cacheDirMd5Hex)){    //如果缓存路径中与assets中的文件不相同
    DDLog.i(getClass(), "skin资源文件校验错误");
    file.delete();
    SkinFileUtils.copySkinAssetsToDir(context, fileName, SkinFileUtils.getSkinDir(context));
}
//没办法,自己写个工具类吧
public class FileUtils {
    /**
     * 将文件转换成字节数组
     *
     * @param filePath
     * @return
     */
    public static byte[] getBytes(String filePath) {
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
        try {
            fis = new FileInputStream(filePath);
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new byte[0];
    }
    /**
     * 将文件转换成字节数组
     *
     * @param file
     * @return
     */
    public static byte[] getBytes(File file) {
        FileInputStream fis = null;
        ByteArrayOutputStream baos = null;
        try {
            fis = new FileInputStream(file);
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = fis.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new byte[0];
    }

    /**
     * 将文件转换成字节数组
     *
     * @param is
     * @return
     */
    public static byte[] getBytes(InputStream is) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int read = 0;
            while ((read = is.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new byte[0];
    }
}

方法二、依据思路一:在更新系统中的common-codec库版本为1.4以上

因为common库会兼容低版本,所以不会引入更多问题,而且是一种更值得做的方法,开历史倒车总是不好的。当然该方法仅限于你是做系统开发的,可以修改系统源码,否则只有依据方法一。
需要懂一些Android Build相关知识。

//TODO 有空再更

三、问题原因

通过网络查找相关文章,发现根本原因如下:
其根本原因在于android内置了一个Codec库,但是版本过老,如果使用了外部引入的新版本的codec.jar中的DigestUtils执行方法的时候,DigestUtils优先调用的是系统自带的老版本的codec库中相应的方法,当老版本的安卓自带codec.jar中不包含新版本DigestUtil需要的方法时,就产生了异常!

由于我使用的是Android4.4版本,于是在代码中搜索了一番,发现在源码编译后的out目录下:
out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes/org/apache/commons/codec/
编译了系统使用的common-codec库,其对应的源码中的jar包为common.jar,于是我打开了common-codec-1.9.jar,common-codec-1.4.jar,common-codec-1.3.jar和common.jar,对比发现在common.jar和common-codec-1.3.jar中的Hex类中没有对应的方法Hex.encodeHexString,如下图:

1.4版本:


image.png

1.9版本:


image.png

1.3版本:


image.png

Android4.4系统中使用的版本(我的测试机)


image.png

通过对比得出结论:common-codec.jar在1.4及之后的版本中才有Hex.encodeHexString方法,在AndroidStudio中编译的时候使用的是我引入的1.9版本的jar包,不会出现编译错误,但是一旦安装到Android4.4系统中,会首先寻找系统中是否有相同的API,结果找到了系统中低版本(1.3或者更低)的Hex类,然后就找不到encodeHexString方法了。

参考链接

Method not found using DigestUtils in Android

上一篇下一篇

猜你喜欢

热点阅读