51

How can I generate JavaDocs for an Android project using the new Gradle build system?

Here is what I have come up with but it doesn't work.

task generateJavadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    ext.cp = android.libraryVariants.collect { variant ->
        variant.javaCompile.classpath.files
    }
    classpath = files(ext.cp) 
}

The main problem is that I do not get the appropriate android.jar on the classpath so some of the links in the JavaDocs are not resolved. I have to find a way to get all the necessary jars on the classpath.

Another problem with the approach I took is it collects the classpaths for all the build variants, rather than selecting one.

Jonik
  • 80,077
  • 70
  • 264
  • 372
Matt Accola
  • 4,090
  • 4
  • 28
  • 37
  • possible duplicate of [Gradle, Javadoc and Android documentation](http://stackoverflow.com/questions/23297562/gradle-javadoc-and-android-documentation) – sschuberth Jul 14 '14 at 11:05

9 Answers9

42

For Android gradle plugin 1.1.2+ (com.android.tools.build:gradle:1.1.2+)

libraryVariants - does not work anymore

use:

task javadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
    destinationDir = file("../javadoc/")
    failOnError false
}

destinationDir = file("../javadoc/") - locate javadocs at root of project directory (in this way jenkins javadoc plugin could find it and show in special Document panel)

failOnError false - for suppress warnings that can cause fail build on jenkins

Oleksandr B
  • 3,400
  • 1
  • 25
  • 28
  • 2
    +1 Absolute genius!!! Every approach I have seen (examples are all over this SO q) for creating javadocs for aars uses the `.all` approach which is long-winded and cant be called from other consuming tasks. This approach is so much cleaner and usable. – Dori Nov 12 '15 at 16:52
  • 1
    Gradle says "Cannot add task ':mossosdesign:javadoc' as a task with that name already exists." – Juan José Melero Gómez Mar 17 '17 at 07:59
24

Gradle 1.11 - Gradle Plugin 0.10.0

Replace android.plugin.sdkDirectory by android.sdkDirectory

android.libraryVariants.all { variant ->
    task("generate${variant.name}Javadoc", type: Javadoc) {
        description "Generates Javadoc for $variant.name."
        source = variant.javaCompile.source
        ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
        classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar)
        options.links("http://docs.oracle.com/javase/7/docs/api/");
        options.links("http://d.android.com/reference/");
        exclude '**/BuildConfig.java'
        exclude '**/R.java'
    }
}
flav
  • 593
  • 6
  • 10
  • 8
    Works, though I would use `"generate${variant.name.capitalize()}Javadoc"` for a slightly better formatted task name (e.g., `generateReleaseJavadoc` versus `generatereleaseJavadoc`). – CommonsWare May 16 '14 at 13:49
  • I had to use `options.linksOffline("http://d.android.com/reference", "${android.plugin.sdkDirectory}/docs/reference");` instead of `options.links("http://d.android.com/reference/");`. Otherwise it gave a warning and wouldn't link to the Android documentation. Besides this it seems to work great! – user1 Oct 03 '14 at 07:01
  • 1
    Better than building your own path to the android jar with `ext.androidJar` would be to simply use `android.bootClasspath`. `classpath = files(variant.javaCompile.classpath.files) + files(android.bootClasspath)` – tophyr Oct 23 '14 at 17:28
12

The solution I ended up settling on is as follows:

android.libraryVariants.all { variant ->

    task("generate${variant.name}Javadoc", type: Javadoc) {
        description "Generates Javadoc for $variant.name."
        source = variant.javaCompile.source
        ext.androidJar = "${android.plugin.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
        classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar)
    }

}

Xavier Ducrohet confirmed this is the way to do it (with caveats) on the adt-dev group, https://groups.google.com/forum/#!searchin/adt-dev/javadoc/adt-dev/seRizEn8ICA/bafEvUl6mzsJ.

Matt Accola
  • 4,090
  • 4
  • 28
  • 37
  • 1
    If you get "javaCompile" is deprecated in latest version of android studio, change to "javaCompiler" – midhunhk Oct 12 '17 at 19:13
  • 6
    If you get 'variant.getJavaCompiler()' is deprecated, use `variant.javaCompileProvider.get().source` and `variant.javaCompileProvider.get().classpath` – istrocode Feb 05 '19 at 17:48
  • 1
    [note] javadoc was generated but was empty. Final solution I used was `source = android.sourceSets.main.java.srcDirs classpath += variant.javaCompileProvider.get().classpath` – istrocode Feb 07 '19 at 13:18
  • @istrocode THANK YOU. I was struggling to replace my deprecated calls but despite looking at several guides, there was no clear indication that you should use `TaskProvider.get()`. This solved my issue. – JHH Feb 11 '20 at 07:55
9

With android gradle tools 1.10.+ getting the android SDK dir is different than before. You have to change the following:

android.sdkDirectory 

instead of

android.plugin.sdkDirectory

This is the complete solution to the problem:

android.applicationVariants.all { variant ->

    task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
        title = "Documentation for Android $android.defaultConfig.versionName b$android.defaultConfig.versionCode"
        destinationDir = new File("${project.getProjectDir()}/doc/compiled/", variant.baseName)
        source = variant.javaCompile.source

        ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
        classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar)

        description "Generates Javadoc for $variant.name."

        options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PRIVATE
        options.links("http://docs.oracle.com/javase/7/docs/api/");
        options.links("http://developer.android.com/reference/");
        exclude '**/BuildConfig.java'
        exclude '**/R.java'
    }
}
Louis CAD
  • 10,965
  • 2
  • 39
  • 58
Julian Pieles
  • 3,880
  • 2
  • 23
  • 33
  • 1
    Just use `android.sdkDirectory` instead of `android.plugin.sdkDirectory` (https://plus.google.com/114432517923423045208/posts/NphSRvqAo6m) – flav May 15 '14 at 08:11
  • I had to leave out the exclude of the R.java files otherwise I did get a lot of errors, but this was the solution that worked for me too. – Mark Nov 08 '14 at 16:56
  • Thanks, just note it must be `options.links("https://developer.android.com/reference/")` and not `options.links("https://developer.android.com/reference/reference")` – Quentin Klein Jul 26 '16 at 15:18
8

The android jars seem to be in the property android.plugin.runtimeJarList. It's not documented anywhere though, so it might break at anytime.

I've refined your solution to work across build variants:

android.applicationVariants.all { variant ->
    def name = variant.name
    task "javadoc$name"(type: Javadoc) {
        description = "Generates javadoc for build $name"
        destinationDir = new File(destinationDir, variant.baseName)
        source = files(variant.javaCompile.source)
        classpath = files(android.plugin.runtimeJarList, variant.javaCompile.classpath)
        exclude '**/R.html', '**/R.*.html'
    }
}

It generally doesn't make sense to do a javadoc on just the main branch since you might rely on some things from the product flavors. Even debug vs release could have some differences. You could of course, just pick a default variant to use. So you could do something like,

task javadoc(dependsOn: javadocDebug)
thatsmydoing
  • 863
  • 7
  • 10
  • 1
    Got error `Could not find property 'applicationVariants'` as of AS 0.2.9 tips? – chakrit Sep 17 '13 at 06:41
  • 1
    Oh figured it out, if you are building a library project, you need to use `android.libraryVariants` as the OP did instead. – chakrit Sep 17 '13 at 06:44
  • After getting your solution to compile, no tasks was added. Seems the variants list are empty as I've confirmed in by adding [this debug task](https://gist.github.com/chakrit/6590917). Any ideas what might be the problem? – chakrit Sep 17 '13 at 07:06
  • 1
    Hmmm, it seems to work for me. I changed applicationVariants to libraryVariants and it adds a javadocDebug task for me. Maybe you should update the android plugin and/or gradle? – thatsmydoing Sep 17 '13 at 07:46
  • 1
    R.java files can be excluded with the following line in the task: `exclude '**/R.html', '**/R.*.html'` – Andrey Nov 14 '13 at 01:16
  • i would include `task(..., dependsOn: "assemble${variant.name.capitalize()}")` else javadoc may fail if the version is not uptodate – k3b Jun 07 '14 at 13:02
4

Here is a updated version that used to work in 2014:

android.libraryVariants.all { variant ->
    def name = variant.buildType.name

    if (name.equalsIgnoreCase("debug")) {
        return; // Skip debug builds.
    }
    task("javadoc${variant.name.capitalize()}", type: Javadoc) {
        description "Generates Javadoc for $variant.name."
        source = variant.javaCompile.source
        ext.androidJar = files(plugins.findPlugin("com.android.library").getBootClasspath())
        classpath = files(variant.javaCompile.classpath.files) + ext.androidJar
        exclude '**/internal/**'
        failOnError false
    }

    task("bundleJavadoc${variant.name.capitalize()}", type: Jar) {
        description "Bundles Javadoc into zip for $variant.name."
        classifier = "javadoc"
        from tasks["javadoc${variant.name.capitalize()}"]
    }
}
GVillani82
  • 17,196
  • 30
  • 105
  • 172
volkersfreunde
  • 1,095
  • 1
  • 12
  • 22
  • `plugins.findPlugin("com.android.library").getBootClasspath()` failed for me with Gradle 2.3, Gradle Android Plugin 1.2.3. But it worked when I removed the whole ext.androidJar line (and the line following it that uses it). – Jesse W at Z - Given up on SE Sep 25 '15 at 20:01
3

I made an open source plugin for that. GitHub Repository

buildscript {
    repositories {
        maven {
            url "https://plugins.gradle.org/m2/"
        }
    }
    dependencies {
        classpath "gradle.plugin.com.vanniktech:gradle-android-javadoc-plugin:0.2.1"
    }
}

Add this line into your build.gradle

apply plugin: "com.vanniktech.android.javadoc"

Then just execute one of the following:

./gradlew generateDebugJavadoc
./gradlew generateReleaseJavadoc

The java documentation can be found in module/javaDoc/

Niklas
  • 23,674
  • 33
  • 131
  • 170
2

I found that this solution works on Gradle plugin 1.3.1 if you have different product flavors.

This will create Gradle tasks to generate Javadoc for each product flavor and build type. For instance, if the module name is app and you have a production and dev product flavor and debug and release build types, you'll have the following Gradle tasks:

  • :app:generateDevDebugJavadoc
  • :app:generateDevReleaseJavadoc
  • :app:generateProductionDebugJavadoc
  • :app:generateProductionReleaseJavadoc

app/build.gradle

android {

    // ...

    applicationVariants.all { variant ->
        // create tasks to generate Javadocs
        task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
            source = variant.javaCompile.source
            classpath += project.files(android.getBootClasspath().join(File.pathSeparator))

            // choose the destination that works best for you here
            // I chose this particular directory because Jenkins pulls reports 
            // from this directory already if you need to have the output 
            // folder be parameterized for the build variant, use
            // "build/outputs/docs/javadoc-${variant.name}/" instead and it'll 
            // be in `javadoc-productionRelease` for example
            destinationDir = file("build/outputs/docs/javadoc/")

            // the name that will appear in the docs
            title = rootProject.name

            // you will probably get errors from using the @annotations and 
            // the support library, so just turn off failing for errors
            failOnError false    
        }
    }

    // ...

}
Phazor
  • 1,032
  • 1
  • 9
  • 15
0

One more

android.libraryVariants.all { variant ->
    if(variant.name.equals('release'))
        task("generateJavadoc", type: Javadoc) {
            description "Generate Javadoc"
            source = android.sourceSets.main.java.srcDirs
//            println '=== source ==='
//            source.collect { relativePath(it) }.sort().each { println it }
            ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
            classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar)
//            println '=== classpath ==='
//            classpath.collect { relativePath(it) }.sort().each { println it }
        }
}

Use:

gradle generateJavadoc

mc.dev
  • 2,675
  • 3
  • 21
  • 27