12

In my Android app, I'm getting a java.lang.NoClassDefFoundError when the code that references code in a dependent .jar is executed. My project includes an Android module as well as a java-only library module, which is where the jar dependency is. I'm using gradle 1.10 to build the project. Here is my project layout:

myProject
- app (Android)
  - src
  - build.gradle

- lib (java)
  - src     
  - libs
    - local-dependency.jar
  - build.gradle

- build.gradle
- settings.gradle

The main project build.gradle is blank while the main project settings.gradle looks like:

include ':app', ':lib'

The Android app build.gradle looks like:

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

apply plugin: 'android'

repositories {
    mavenCentral()
}

android {
    compileSdkVersion 18
    buildToolsVersion "19.0.2"

    defaultConfig {
        minSdkVersion 18
        targetSdkVersion 18
        versionCode 1
        versionName "1.0"
    }
}

dependencies {
    compile project(':lib')
}

The library build.gradle is:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile <some-dependency-in-maven>
    compile files('libs/local-dependency.jar') 
}

Everything compiles and packages with no errors and I'm not seeing any errors in the IDE (IntelliJ 13). For some reason, my local-dependency.jar is not getting added to the dex-ing process during the Android compile. Any maven dependencies specified in the lib project get added to the Android .apk just fine; it's just my local jar dependency. Is there something I'm missing?

Thanks!

gmusick
  • 133
  • 1
  • 4
  • You may want to try including the dependent jar in the android project also just to see if that works. – AndroidGuy Mar 12 '14 at 20:59
  • 1
    Hmm, yeah, it seems to work when I change my Android app build.gradle dependency section to add `compile files('../lib/libs/local-dependency.jar')`. But is there a way to get it work without having to have the Android app build.gradle have to know about a dependency's dependencies? – gmusick Mar 13 '14 at 05:45

2 Answers2

6

This is not directly possible as local jars are not declared as transitive dependencies in Gradle.

You have two options:

  • merge the two jars in your java library so that the output contains the local jar.
  • create a different project with no source, only the jar, and make the project depend on it.

The second option gives you the ability to have more than one project depend directly on the local jar (on top of it becoming a transitive dependency). To do it, create a new gradle project and just put in its build.gradle the following:

configurations.create("default")
artifacts.add("default", file('somelib.jar'))

This simply register your jar as the default artifact published by the project and this will get consumed by the other projects.

Xavier Ducrohet
  • 28,383
  • 5
  • 88
  • 64
  • Does this mean that in a parent project you'd put this in its build.gradle: dependencies { . . . compile project(':shared-jars') . . . } – Brad Rhoads Jun 09 '14 at 19:20
  • Yes. And it means that that parent project will publish this as its dependency to other projects that may consume it (the parent project). – Xavier Ducrohet Jun 10 '14 at 00:31
  • I'm having trouble getting this to work. When you say create a new project, do you mean a new Java module? I created a Java module and tried this but I run into one problem or the other. If I do "apply plugin: 'java'" in the build.gradle of the shared-jars module, Gradle complains that "default" configuration already exists. If i don't apply Java plugin, then it complains there's no assemble task in shared-jars. I tried commenting out the configurations.create() line. Here everything compiled properly but I get NoClassDef at runtime. Maybe I'm missing something basic. – curioustechizen Apr 09 '15 at 07:21
  • 1
    Just use "New Module" and select "Import Jar or Aar" option, it'll create the module wrapping the jar, putting only the line I mentioned above in your build.gradle. – Xavier Ducrohet Apr 09 '15 at 15:51
  • I would add that in my case I add to remove ```configurations.create("default")``` as gradle was complaining that a configuratioin with the name already existed. Is there a way in Gradle to see which artifact is created/exposed/exported? – Andrea Richiardi Apr 24 '15 at 10:15
  • 1
    @XavierDucrohet Thanks - using the New Module --> Import Jar option did the trick for me. Are there any best practices around grouping together multiple related JAR files into a single module using this approach? – curioustechizen Jun 18 '15 at 06:17
  • A jar I'm currently using is unfortunately not available publicly and I'm wondering if any of these approaches resolve the need for the jar to be available by projects that then consume a library/sdk project? – amadib May 13 '16 at 20:36
1

In recent (4+, IIRC) versions of gradle, you can achieve this with the following configuration:

compile (project(':ProjectIDependOn')) {
  transitive = true
}

Setting transitive to true when depending on another project will expose all of that project's libraries to this project.

Dmitri V
  • 65
  • 8