103

I have investigated a while and probably saw most popular answers here related to aar and transitive dependencies but somehow it is still not clear for me how to make this working.

So:

I have android library with given gradle config:

apply plugin: 'android-library'
apply plugin: 'android-maven'

version = "1.0.0"
group = "com.somepackage"

buildscript {
    repositories {
        mavenCentral()
        mavenLocal()
    }

    dependencies {
        classpath 'com.github.dcendents:android-maven-plugin:1.0'
    }
}

android {
    compileSdkVersion 19
    buildToolsVersion '19.0.3'

    defaultConfig {
        minSdkVersion 10
    }
}

repositories {
    maven { url 'http://www.bugsense.com/gradle/' }
}

dependencies {
    provided 'com.google.android.gms:play-services:+'
    provided 'com.android.support:appcompat-v7:+'
    compile 'com.google.code.gson:gson:2.2.4'
    compile 'com.bugsense.trace:bugsense:3.6'
    compile 'commons-net:commons-net:3.3'
}

Then I am deploying it to local maven repo with gradle install. POM file of the deployed library looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sprezzat</groupId>
  <artifactId>app</artifactId>
  <version>1.0.0</version>
  <packaging>aar</packaging>
  <dependencies>
    <dependency>
      <groupId>com.bugsense.trace</groupId>
      <artifactId>bugsense</artifactId>
      <version>3.6</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>commons-net</groupId>
      <artifactId>commons-net</artifactId>
      <version>3.3</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.2.4</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>

And finally gradle config of my android application using above library as a dependency:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}
apply plugin: 'android'

repositories {
    mavenCentral()
    mavenLocal()
}

android {
    compileSdkVersion 15
    buildToolsVersion "19.0.2"

    defaultConfig {
        minSdkVersion 10
        targetSdkVersion 18
    }
}

dependencies {
    compile 'com.google.android.gms:play-services:+'
    compile 'com.android.support:appcompat-v7:+'
    compile 'com.somepackage:LIBRARY_NAME:1.0.0@aar'
}

And after deploying application on phone I am getting NoClassDefFoundError for classes belonging to compile dependencies of my android library.

Inspecting my android application dependencies using gradle dependencies:

apk - Classpath packaged with the compiled main classes.
+--- com.google.android.gms:play-services:+ -> 4.3.23
|    \--- com.android.support:support-v4:19.0.1 -> 19.1.0
+--- com.android.support:appcompat-v7:+ -> 19.1.0
|    \--- com.android.support:support-v4:19.1.0
\--- com.somepackage:LIBRARY_NAME:1.0.0

According to above tree, all transitive dependencies are not detected. Where is the problem and how should it be done correctly?

mkorszun
  • 4,461
  • 6
  • 28
  • 43
  • 1
    Have you examined the output of running **`gradle dependencies`** for your app? – CommonsWare Apr 01 '14 at 19:50
  • And are you really sure that you want the `provided` keyword there? According to Xav, [such dependencies are not packaged in the APK](https://groups.google.com/d/msg/adt-dev/WIjtHjgoGwA/h1gS9J5xLUAJ), and I would think that you would want those to be packaged in the APK. – CommonsWare Apr 01 '14 at 19:52
  • @CommonsWare `gradle dependencies` for my android lib: default - Configuration for default artifacts. +--- com.google.code.gson:gson:2.2.4 +--- com.bugsense.trace:bugsense:3.6 \--- commons-net:commons-net:3.3 – mkorszun Apr 01 '14 at 20:02
  • I am not aware that local AAR files like that work -- I think they need to go into a local Maven repository and be referenced that way. But I really was referring to running **`gradle dependencies`** for the *app*, not for a library that somebody decided to name "app". – CommonsWare Apr 01 '14 at 20:05
  • @CommonsWare please see updated question. I have installed library to local maven repo but this does not help. – mkorszun Apr 01 '14 at 21:26
  • `@aar` means "just the aar artifact, and no dependencies". – Peter Niederwieser Apr 01 '14 at 22:09
  • @PeterNiederwieser so what would be the alternative? Bundle all dependencies in separate jar and provide them together with aar? – mkorszun Apr 02 '14 at 08:50
  • I'd expect that omitting `@aar` would solve the problem. – Peter Niederwieser Apr 02 '14 at 09:11
  • @PeterNiederwieser but my library provides resources as well. How to solve this issue? – mkorszun Apr 02 '14 at 09:55
  • I am having the same issue. Never used @aar in compile line. When I build my final APK I pull aar from maven repo, but none of its deps are pulled into the final project, causes noclassdef errors. – lostintranslation Nov 25 '14 at 02:20
  • 1
    where should i place pom file in aar added app – skyshine Feb 16 '18 at 14:31

8 Answers8

91

I have solved my problem by setting transitive attribute for my aar dependency:

compile ('com.somepackage:LIBRARY_NAME:1.0.0@aar'){
    transitive=true
}
mkorszun
  • 4,461
  • 6
  • 28
  • 43
  • 4
    @PeterNiederwieser Omitting the `@aar` causes Gradle to attempt to grab the artifact as a .jar file. This kills the build. – cwc Aug 21 '14 at 20:02
  • 4
    It did not worked for me. I have the exact problem. I have 2 libraries and one of them is using the other. `compile project(':LeafPeripheralsContract') { transitive=true }` did not work. It complained about transitive. And I created an `aar` and tried to add transitive to it. It did not complain but it did not include it in the other aar package as well. – tasomaniac Oct 23 '14 at 17:18
  • 1
    Did not work for me either. I have a classifier in the dependency as well. Wondering if that is the problem. Using Android Studio RC1 with gradle build tools 0.14.4. – lostintranslation Nov 26 '14 at 18:17
  • 1
    Yup, if you are using classifiers, doesn't seem like transitive deps work. Look here: https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=80989 – lostintranslation Nov 26 '14 at 21:48
  • 2
    if you have both .jar and .aar artifacts, this is the only solution to use the @aar and include transitives. – Jeffrey Blattman Oct 15 '15 at 17:07
  • where should i place pom file in android application – skyshine Feb 18 '18 at 17:15
  • 1
    In case you are using flavors for your aar you need to workaround this issue as well: https://github.com/gradle/gradle/issues/1487 – Sergey Dryganets Feb 16 '19 at 01:32
23

you should not use "@aar", if use "@" is become "Artifact only notation", if you want to use "@" and want have dependence transitive, you should add "transitive=true"

user3070402
  • 239
  • 2
  • 3
  • 2
    This answer is helpful. There was a typo in my previous comment and I deleted that one. Thanks for your answer, have a good day :). – srain May 24 '16 at 15:33
14

Try this if you are using aar locally:

compile(project(:your-library-name)) {
    transitive=true
}
suhas_sm
  • 2,064
  • 1
  • 18
  • 23
  • 6
    Hi, its not working for me. I have created one library project which internally uses volley library. I have included aar file created using library project in my application. I am getting "Error:(8, 26) error: package com.android.volley does not exist" error. In my library project, I have included volley using compile(project(':volley')){ transitive = true } – Manish Jul 27 '16 at 07:24
  • 2
    Hey Manish, Facing the same issue, did you find any solution? – Jalpesh Aug 17 '16 at 05:52
  • I'm stuck with the same problem – Alejandro Rangel Sep 30 '16 at 18:18
  • 1
    Are you including the aar as flatDir? If so, I would refer you to the following comment: http://stackoverflow.com/questions/25698160/can-an-aar-include-transitive-dependencies#comment68753630_25730092 – FloG Jan 23 '17 at 14:26
9

I was having a similar problem and felt I could share the steps of solving the problem.

The basic idea of not being able to use the transitive dependencies while you are publishing your own aar is actually not having the .pom file generated with the expected transitive dependencies.

I was using 'maven-publish' plugin for my android aar dependency to publish it in my own private maven repository. The transitive dependencies were not resolved when my other projects were adding my aar dependency in their build.gradle. Hence here what I did to modify the .pom file while publishing my aar.

An important thing to note here that, the dependencies which you want to have the transitive behavior should be imported using the api in your library project's build.gradle file like the following.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    api 'com.android.volley:volley:1.0.0'
    api "com.google.code.gson:gson:$globalGsonVersion"
}

Now as I said earlier, I was using maven-publish plugin to publish the aar dependency and hence my publishing task in the gradle looks like the following.

publishing {
    publications {
        mavenAar(MavenPublication) {
            from components.android
        }

        mavenJava(MavenPublication) {
            pom.withXml {
                def dependenciesNode = asNode().appendNode('dependencies')
                // Iterate over the api dependencies (we don't want the test ones), adding a <dependency> node for each
                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 {
        maven {
            // Your repository information goes here
        }
    }
}

Hence, I used another mavenJava task to publish the .pom file in my private maven repo so that when the aar file is added as a dependency to some other module, it gets the .pom information and download the transitive dependency.

To complete the answer, this is how you should add the dependency in the build.gradle file for your own published aar to me imported.

api('com.example.masudias:my_lib:1.0.0@aar') {
    transitive = true
}
Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98
  • 1
    That worked, thanks! Not sure why adding the transitive dependencies to the POM isn't default behaviour though. – Micha Jan 21 '21 at 19:46
  • 1
    Nice one! Just to add a point here. When the dependencies are added as `api`, the scope of the dependency within the pom file is `compile`. But if the dependencies are added as `implementation`, the scope becomes `runtime` in the pom file. – Nikhil Kumar Apr 01 '21 at 06:34
  • Thank you for these addition @NikhilKumar. Appreciate it! – Reaz Murshed Apr 01 '21 at 14:04
  • 2
    `An important thing to note here that, the dependencies which you want to have the transitive behavior should be imported using the api in your library project's build.gradle file like the following.` OMG, thank you. – Bill Mote Jun 09 '21 at 18:17
  • Спасибо! Мне тоже помог ваш рецепт. – Andrey Feb 09 '23 at 18:20
7

Transitive dependency

transitive means that the consumer(e.g. app) includes a producer and all producer's dependencies(e.g. libraries). It increase build time and can create some issues with dependency versions

By default, Gradle dependency has transitive = true

api ('com.package:library:0.0.1')
//the same
api ('com.package:library:0.0.1') {
    transitive = true
}

When you use @artifact notation it has transitive = false

api ('com.package:library:0.0.1@aar')
//the same
api ('com.package:library:0.0.1@aar') {
    transitive = false
}
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
0

For me complete publishing solution looks like this:


apply plugin: 'com.github.dcendents.android-maven'

group = GROUP
version = VERSION

// you could move it to env variable or property
def publishFlavorless = true
def firstTask = null

android.libraryVariants.all { variant ->

    if (variant.name.toLowerCase().contains("debug")) {
        // Workaround for https://github.com/gradle/gradle/issues/1487
        if (publishFlavorless && firstTask == null) {
            def bundleTask = tasks["bundle${variant.name.capitalize()}Aar"]
            firstTask = bundleTask
            artifacts {
                archives(firstTask.archivePath) {
                    builtBy firstTask
                    name = project.name
                }
            }
        }
        return
    }

    def bundleTask = tasks["bundle${variant.name.capitalize()}Aar"]

    artifacts {
        archives(bundleTask.archivePath) {
            classifier variant.flavorName
            builtBy bundleTask
            name = project.name
        }
    }
}

install {
    repositories.mavenInstaller {
        // This generates POM.xml with proper parameters
        pom.project {
            name POM_NAME
            artifactId POM_ARTIFACT_ID
            // For aar it is equal to 'aar' with jar transitive dependencies won't work
            packaging POM_PACKAGING
            description POM_DESCRIPTION
        }
    }
}

The transitive = true block is required as well ...

Sergey Dryganets
  • 899
  • 8
  • 18
0

AAR file doesn't contain transitive dependencies. So even if use api instead of implementation it wont work.

In our team we had developed a library to use in our applications and we wanted it to be for internal use only. Earlier we used to include whole module that seems to work. Later we decided to move to aar file but we were also facing same issue of classpath not found. After some research we came to know that we can also use local maven repo. We decided to use that.

Here is step by step process

Publishing repo

1.In your Library's root build.gradle file you need to include

id 'com.github.dcendents.android-maven' version '2.0' apply false

2.In you library's module level build.gradle file you need to add

a) In plugins

id 'maven-publish'

b) At bottom of gradle file add

publishing {
    publications {
        release(MavenPublication) {
            groupId = 'com.demo.android'
            artifactId = 'qrcodescanner'
            version = '1.0.0'

            afterEvaluate {
                from components.release
            }
        }
    }
    repositories {
        maven {
            name = "qrcodescanner"
            url = "${project.buildDir}/repo"

        }
    }
}

3.Depends on the name you have given a gradle tasks will be generated you can check using gradlew tasks or by using gradle window at top right corner in android studio, Our was

publishReleasePublicationToQrcodescannerRepository

4.Run it and repo will be generated in given path

gradlew publishReleasePublicationToQrcodescannerRepository
  1. Final step you need to publish it to maven local using

    gradlew publishToMavenLocal

if it doesn't work you can try gradlew clean and gradlew build before executing it.

Using local repo

1.You need to add mavenLocal() in root level build.gradle file of your project you wanted to use it in like this before other central repos

allprojects {
    repositories {
        mavenLocal()
        google()
        jcenter()
        maven { url "https://jitpack.io" }
        mavenCentral()
    }
}
  1. Now you need to include your dependency in the project like we do with other dependencies as well

implementation 'com.demo.android:qrcodescanner:1.0.0' keep in mind format should groupdId:artifactId:version

That's it.

References :

Publish Library

Local Maven

pintu236
  • 148
  • 2
  • 11
-2

Simply adding @aar at the end of the dependency is what worked for me.

dependencies {
    implementation 'org.videolan.vlc:libvlc:3.0.13@aar'
}
Merc
  • 393
  • 5
  • 10