【问题标题】:android java.lang.NoClassDefFoundError: org.bouncycastle.crypto.engines.AESEngine api 16android java.lang.NoClassDefFoundError: org.bouncycastle.crypto.engines.AESEngine api 16
【发布时间】:2017-03-27 03:03:51
【问题描述】:

我在我的 android 客户端中使用 com.nimbusds.jose.crypto 库来做一些 jwt 的事情。

这是我在我的 gradle 文件中声明的内容:

    compile 'com.nimbusds:nimbus-jose-jwt:4.23'

在 api >=19 上一切正常,但是当我在 api 16 上运行代码时,我得到了这个异常:

java.lang.NoClassDefFoundError: org.bouncycastle.crypto.engines.AESEngine

这里有什么问题?为什么 api 16 上没有 AESENGINE 类?

【问题讨论】:

标签: java android


【解决方案1】:

Android 操作系统随附已存在的 BouncyCastle。在 API 级别 16 中,AESEngine 类未随 Android OS 提供(Android 决定稍后提供该类)。因此,它无法找到该类。

但是,在编译时该类存在,但在运行时不存在。在这种情况下,当您需要在 API 16 或更低版本中使用该类时,您必须使用 APK 提供该类/jar。

除了写作

compile "com.madgag.spongycastle:prov:1.54.0.0"

这个也得写

apk "com.madgag.spongycastle:prov:1.54.0.0"

这会将此类的范围从编译时扩展到 APK,并将在所有版本的 Android 中可用。

注意:您必须使用 SpongyCastle 而不是 BouncyCastle 以避免类名冲突。

【讨论】:

    【解决方案2】:

    您的依赖 nimbus-jose-jwt 没有声明对 bouncycastle 的依赖,因此如果环境本身不提供 bouncycastle 版本,则会发生错误。这种情况发生在 API 版本 16 上。

    虽然您可以说这是库的问题,但这很可能是故意的,因为 Bouncycastle 可用于不同的 JDK 版本。 Bouncycastle 项目决定使用不同的 Artifact 名称来反映不同的 JDK 版本,而不是反映在 Bouncycastle 版本号中。 这会导致依赖管理中的问题,因为版本解析器不会将不同的版本识别为实际上是相同的工件(它们在技术上是相同的,因为它们包含一组相同的类)。并且无法解决版本冲突,因此无法引发版本解析错误,例如在不兼容的主要版本上。

    org.bouncycastle » bcprov-jdk16

    对比

    org.bouncycastle » bcprov-jdk15

    对比

    org.bouncycastle » bcprov-jdk14

    这可能导致类路径上出现多个并发版本的 bouncycastle,进而可能导致不可预知的类加载器行为或不可预知的 classNotFound /Symbol not found 错误(如果使用旧版本,而需要新版本)。

    解决方法很简单:

    像这样在你的 gradle 文件中显式添加所需的依赖项:

    dependencies {compile 'org.bouncycastle:bcprov-jdk16:1.46'}
    

    // https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk16
    compile group: 'org.bouncycastle', name: 'bcprov-jdk16', version: '1.46'
    

    如果缺少更多库,请尝试识别包含这些类的库(最简单的方法是用谷歌搜索它们)并明确添加它们。

    【讨论】:

      【解决方案3】:

      如果您查看 nimbus-jose-jwt 的依赖列表,则没有 bouncycastle 库。但是,如果您查看源代码,更准确地说是查看包com.nimbusds.jose.crypto.bc,那么您可以看到,它使用bouncycastle 而不将其声明为依赖项。所以库只是假设bouncycastle 存在。

      解决方法是手动添加依赖。首先,按照link实现一个标准的在Android上使用bouncycastle的方式。

      但这并不能解决问题,因为org.bouncycastle.crypto.engines.AESEngine 不在这些库之一中。解决办法是多加一个依赖:

      依赖{ 编译'org.bouncycastle:bcprov-jdk15on:1.54' }

      那么一切都应该正常。

      总结:

      gradle 依赖应该像这样:

      dependencies {
          compile 'com.nimbusds:nimbus-jose-jwt:4.23'
          compile 'com.madgag.spongycastle:core:1.54.0.0'
          compile 'com.madgag.spongycastle:prov:1.54.0.0'
          compile 'com.madgag.spongycastle:pkix:1.54.0.0'
          compile 'com.madgag.spongycastle:pg:1.54.0.0'
          compile 'org.bouncycastle:bcprov-jdk15on:1.54'
      }
      

      你应该注册java.security.Provider:

      static {
          Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
      }
      

      【讨论】:

        猜你喜欢
        • 2016-12-17
        • 1970-01-01
        • 1970-01-01
        • 2017-05-08
        • 1970-01-01
        • 2012-04-09
        • 2018-01-23
        • 2018-09-07
        • 2015-10-20
        相关资源
        最近更新 更多