如何修复 Android .aar 项目中的“java.lang.NoClassDefFoundError”

Nir*_*dri 5 android aar retrofit2 okhttp3

.aar构建了一个 android库,我正在尝试将它与其中一个项目集成。当应用程序尝试打开.aar我使用改造进行 API 调用的库的初始屏幕时。我收到以下异常

java.lang.NoClassDefFoundError:解析失败:Lokhttp3/OkHttpClient$Builder;

我没有在我的.aar项目中混淆或启用 pro-guard 。

以下是我的.aarGradle 依赖项

implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:converter-gson:2.2.0'

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
Run Code Online (Sandbox Code Playgroud)

Car*_*as 8

好的,这是一个常见问题。有几种方法可以在其他项目中使用 android 库 (aar)。例如:

  1. 通过使用 implementation project(':mylibrary').
  2. 通过将您的 aar 上传到 maven 存储库(artifactory、maven local、Jitpack 等)

注意这一点:

  1. 如果您使用上面的数字 1,那么您还必须将(retrofit、okhttp3 等)添加到具有相同版本的示例项目中,因为默认情况下 aar 不包含子依赖项。这就是为什么您会收到异常“java.lang.NoClassDefFoundError:解析失败:Lokhttp3/OkHttpClient$Builder'”。
  2. 如果您使用上面的数字 2,那么您必须确保您的 pom.xml 文件包含您的子依赖项,因为服务器需要下载并在您的示例项目中提供它们。

我推荐什么?

我建议开发人员使用MavenLocal(),它会在将你的 aar 发布到像 Jitpack 或任何你想要的公共存储库之前复制一个真实的场景。

我该怎么做?

  1. 在你的库模块的 build.gradle 里面

apply plugin: 'maven-publish'

project.afterEvaluate {
    publishing {
        publications {
            library(MavenPublication) {
                setGroupId 'YOUR_GROUP_ID'
                //You can either define these here or get them from project conf elsewhere
                setArtifactId 'YOUR_ARTIFACT_ID'
                version android.defaultConfig.versionName
                artifact bundleReleaseAar //aar artifact you want to publish

                pom.withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')
                    configurations.implementation.allDependencies.each {
                        def dependencyNode = dependenciesNode.appendNode('dependency')
                        dependencyNode.appendNode('groupId', it.group)
                        dependencyNode.appendNode('artifactId', it.name)
                        dependencyNode.appendNode('version', it.version)
                    }
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

运行assemblepublishToMavenLocalgradle 任务。你会看到这样的事情: 在此处输入图片说明

  1. 在您的示例项目中
allprojects {
    repositories {
        mavenLocal()
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

implementation '${YOUR_GROUP_ID}:${YOUR_ARTIFACT_ID}:${YOUR_VERSION}'


Mar*_*ark 1

假设您已经构建了 .aar,并将其发布到 Maven 存储库(artifactory、nexus 等等) - 例如,“implementation 'com.mycompany:library:1.0@aar'”。任何子依赖项都需要包含在服务器交付的 pom.xml 中,以便它们在您的应用程序中可用。

由于您使用了“implementation”关键字,因此这些依赖项被视为 .aar 私有的,并且不会在 pom.xml 中列出。所以它们不会在你的aar中可用,也不会被gradle自动导入到项目中。

如果将 api 关键字更改为“api”而不是实现,则这些依赖项将变为公共,并且应在生成的 pom.xml 中列出,因此应自动导入到项目中。

这实际上对于 aar 的内部模块也是如此,而不是通过外部系统引用(例如实现项目(':mylibrary'))。如果你需要mylibrary的依赖来运行项目,它们需要是api。

作为参考,您可能需要查看Android Studio 依赖项配置文档

但是,如果您通过文件语句手动包含 arr(例如,实现文件('libs/my.aar')),那么您将无法获得自动依赖项管理,并且必须添加手动将 aar 所需的库添加到主项目中,也可以通过在 build.gradle 文件之间复制和粘贴来实现。