Android: ClassNotFoundException when using library project that has gradle dependencies
Asked Answered
K

1

8

I have a custom view library that compiles and runs correctly on it's own (through another activity created just for testing purposes inside the library project). However when I build the library, and then import the aar into another project (open module settings->new module->existing aar..) I'm getting a runtime ClassNotFoundException - the exception is on the only gradle dependency that the library is using. Why is this happening?

Library gradle file:

    apply plugin: 'com.android.library'

    android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    compile 'com.googlecode.libphonenumber:libphonenumber:7.2.1'
}

The error that I'm getting:

Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.i18n.phonenumbers.PhoneNumberUtil" on path: DexPathList[[zip file..
Knorring answered 26/1, 2016 at 10:34 Comment(2)
what does 'somegradledependency' means @KnorringZabrze
@AmitVaghela sorry, my own attempts at obfuscation which obviously I can't use here. I edited and added the libraries in aboveKnorring
I
1

An aar dependency is not like a maven/ivy dependency in that there is no transitive dependency bundled with it in a pom or xml file. When you add a aar dependency, gradle has no way to know what transitive dependencies to fetch.

A common practice in the android world seems to be, to add transitive dependencies explicitly to your app, that uses the aar. This can get cumbersome and sort of defeats the point of a dependency management system.

There are a couple of workarounds:

1. android-maven plugin

There is a 3rd party gradle plugin that allows you to publish the aar file to a local maven repo, along with a valid pom file.

2. maven-publish plugin

You an use the standard maven-publish plugin to publish the aar to a maven repo, but you have to assemble pom dependencies yourself. For example:

publications {
    maven(MavenPublication) {
        groupId 'com.example' //You can either define these here or get them from project conf elsewhere
        artifactId 'example'
        version '0.0.1-SNAPSHOT'
        artifact "$buildDir/outputs/aar/app-release.aar" //aar artifact you want to publish

        //generate pom nodes for dependencies
        pom.withXml {
            def dependenciesNode = asNode().appendNode('dependencies')
            configurations.compile.allDependencies.each { dependency ->
                def dependencyNode = dependenciesNode.appendNode('dependency')
                dependencyNode.appendNode('groupId', dependency.group)
                dependencyNode.appendNode('artifactId', dependency.name)
                dependencyNode.appendNode('version', dependency.version)
            }
        }
    }
}

In both of these cases, once aar+pom are available in a maven repo, you can use it in your app like this:

compile ('com.example:example:0.0.1-SNAPSHOT@aar'){transitive=true}

(I'm not entirely sure how transitives work if you add a dependency as compile project(:mylib). I will update this answer for this case shortly)

Irresolution answered 26/1, 2016 at 12:11 Comment(10)
I don't understand. That dependency is inside the library and if I change it the way you suggest it won't compile anymore. Inside my app the relevant line is: compile project(':libraryname')Knorring
Sorry, I misunderstood your question. So you imported an aar but studio added compile project() ?Irresolution
I made a library project that has a compile dependency through gradle. When I run the library project by itself it runs fine. When I import the library project into another app and try to run the app I get a runtime crash with the exception.Knorring
Can you try project(':libraryname'){transitive = true} ?Irresolution
If I do it like this then it will compile: compile(project(':somelibrary')) {transitive = true} but I still get the same classnotfoundexception as I got at the beginningKnorring
Just to check, what if you add the library's dependency to your app as well?Irresolution
If I add the dependency to the app (and make it a normal compile - not transitive) then it works. However, there should be a way to do this without duplicating the dependencies.Knorring
The issue is that an aar doesn't come with a pom file that describes it's dependencies. So your app won't know what dependencies to get. I did write an SO answer about generating your own pom, let me go find it.Irresolution
My confusion was that if you add a dependency as project , instead of aar, I assumed gradle would resolve transitive dependencies. I will do some research and update the answer.Irresolution
This all seems to be related to this issue in the google issue tracker: code.google.com/p/android/issues/detail?id=55863Knorring

© 2022 - 2024 — McMap. All rights reserved.