Home > Software design >  Gradle/Maven/Android: Library-private dependency not found when library is used via maven
Gradle/Maven/Android: Library-private dependency not found when library is used via maven

Time:10-12

I have a SampleApp with a library module attached:

:app
:library

The library is using the following dependency and the following code:

implementation "com.google.android.gms:play-services-safetynet:17.0.1"

----

import android.content.Context
import com.google.android.gms.safetynet.SafetyNet

class ClassUsingSafetynet {
    fun trigger(context: Context) {
        SafetyNet.getClient(context)
    }
}

The SampleApp is calling trigger somewhere:

val triggerClass = ClassUsingSafetynet()
triggerClass.trigger(context)

This works without problems as long as the SampleApp declares its dependency directly on the library module:

implementation project(path: ':library')

But if I deploy the library aar to my local maven and declare the dependency accordingly like this:

implementation ('com.myapplication:library:1.0.3@aar') { transitive = true }

I get the following crash

java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/safetynet/SafetyNet;
        at com.library.ClassUsingSafetynet.trigger(ClassUsingSafetynet.kt:10)
        at com.myapplication.MainActivity.onCreate$lambda-0(MainActivity.kt:38)

Here is the publish gradle task:

afterEvaluate {
    publishing {
        publications {
            release(MavenPublication) {

                groupId 'com.myapplication'
                artifactId 'library'
                version '1.0.3'
                artifact 'build/outputs/aar/library-release.aar'

                pom.withXml {
                    def dependenciesNode = asNode().appendNode('dependencies')

                    configurations.api.allDependencies.each {
                        def dependencyNode = dependenciesNode.appendNode('dependency')
                        dependencyNode.appendNode('groupId', it.group)
                        dependencyNode.appendNode('artifactId', it.name)
                        dependencyNode.appendNode('version', it.version)
                    }
                }
            }
        }
        repositories {
            mavenLocal()
        }
    }
}

I have tried to use api instead of implementation for the SafetyNet dependency. No difference.

I have tried to set/not set {transitive = true}. No difference.

I have tried to set/not set @aar. No difference.

I have tried to not create the pom file. No difference.

No ProGuard is applied for now.


What's especially strange to me is that "SafetyNet" is a private dependency of the library. My app doesn't even need to know about it.

CodePudding user response:

The published POM file needs to declare all runtime dependencies of the library, not just its API dependencies. In other words, you need to use the following when adding dependencies to the POM:

    configurations.releaseRuntimeClasspath.allDependencies.each {
        // …
    }

The following is a misunderstanding:

"SafetyNet" is a private dependency of the library. My app doesn't even need to know about it.

Your app should indeed not have to worry about this “private dependency” but it still has to (be able to) make it available to the library at runtime – as the library doesn’t work without it because it still is a dependency of the library.

I’ve successfully tested this change with a small dummy Android project. Let me know if you can’t get your build to work with the above information; then I can add a self-contained, working sample project to my answer.


That said, I wonder why you manually (a) specify the published artifact and (b) create the POM? The following should work automagically (tested as described above):

    release(MavenPublication) {
        groupId 'com.myapplication'
        artifactId 'library'
        version '1.0.3'

        from components.release
    }

See also the docs.

  • Related