Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix 'java.lang.NoClassDefFoundError' in Android .aar project

I have an android .aar library built and I am trying to integrate it with one of the projects. When the app tries to open the initial screen of the .aar library where I have API call using retrofit. I am getting the below exception

java.lang.NoClassDefFoundError: Failed resolution of:Lokhttp3/OkHttpClient$Builder;

I have not obfuscated or enabled pro-guard in my .aar project.

Below are my .aar Gradle dependencies

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'
like image 772
Niranjan Sheshadri Avatar asked Jul 11 '19 12:07

Niranjan Sheshadri


2 Answers

OK, this is a common issue. There are several ways to use an android library(aar) in other projects. For example:

  1. By importing this aar as a module into your sample project by using implementation project(':mylibrary').
  2. By uploading your aar to a maven repository(artifactory, maven local, Jitpack, etc)

Pay attention to this:

  1. If you are using number 1 above, so you will also have to add(retrofit, okhttp3, etc) to your sample project with the same version, because the aar by default doesn't include child dependencies. That's why you are getting that exception "java.lang.NoClassDefFoundError: Failed resolution of: Lokhttp3/OkHttpClient$Builder'".
  2. If you are using number 2 above, so you will have to make sure that your pom.xml file includes your child dependencies, because the server needs to download and have them available in your sample project.

What do I recommend?

I recommend developers to use MavenLocal(), it replicates a real scenario before publishing your aar to a public repository like Jitpack or whatever you want.

How can I do it?

  1. Inside build.gradle of your library module:

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 assemble and publishToMavenLocal gradle tasks. And you'll see something like this: enter image description here

  1. In your Sample Project
allprojects {
    repositories {
        mavenLocal()
        ...
    }
}

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

like image 59
Carlos Leonardo Camilo Vargas Avatar answered Nov 18 '22 11:11

Carlos Leonardo Camilo Vargas


Let's assume you've built your .aar, and published it to a maven repository (artifactory, nexus, what have you) - e.g., "implementation 'com.mycompany:library:1.0@aar'". Any child dependencies need to be included in the pom.xml delivered by the server to have them available in your application.

Since you've used the "implementation" keyword, those dependencies are considered private to the .aar, and will not be listed in the pom.xml. So they will not be available in your aar, and not automatically imported into the project by gradle.

If you change to the api keyword to "api" instead of implementation, those dependencies become public, and should be listed in the generated pom.xml, and thus should be automatically imported into the project.

This is actually also true also with aar's inside modules, rather than referenced via external systems (e.g. implementation project(':mylibrary') ). If you need the dependencies of mylibrary to run the project, they need to be api.

For reference, you may want to take a look at the Android Studio Dependency Configurations Documentation.

If, however, you're manually including the arr via a files statement (e.g., implementation files('libs/my.aar')), then you don't get automatic dependency management, and you're going to have to add the libraries needed by your aar to the main project manually as well via copy and paste between the build.gradle files.

like image 1
Mark Avatar answered Nov 18 '22 11:11

Mark