当android库具有依赖项(也是aar库)时,如何生成javadoc for android库?

当android库具有依赖项(也是aar库)时,如何生成javadoc for android库?,android,gradle,android-gradle-plugin,javadoc,android-library,Android,Gradle,Android Gradle Plugin,Javadoc,Android Library,我有一个android库项目,它依赖于其他android库项目。我需要为库生成javadoc,但它失败了,因为gradle将javadoc类路径放到.aar位置,但javadoc需要.jar文件 简化的渐变文件: android { compileSdkVersion 23 buildToolsVersion "23.0.2" configurations { javadocDeps } defaultConfig {

我有一个android库项目,它依赖于其他android库项目。我需要为库生成javadoc,但它失败了,因为gradle将javadoc类路径放到.aar位置,但javadoc需要.jar文件

简化的渐变文件:

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    configurations {
        javadocDeps
    }

    defaultConfig {
        minSdkVersion 7
        targetSdkVersion 23
        versionCode 1
        versionName "0.1.0"
    }
}

dependencies {
    compile 'com.android.support:support-v4:23.2.0'
    compile 'com.android.support:appcompat-v7:23.2.0'
    compile 'com.nineoldandroids:library:2.4.0'
    compile 'com.annimon:stream:1.0.7'
    javadocDeps 'com.android.support:support-annotations:23.2.0'
    javadocDeps 'com.nineoldandroids:library:2.4.0'
    javadocDeps 'com.android.support:support-v4:23.2.0'
}

task sourcesJar(type: Jar) {
    from android.sourceSets.main.java.srcDirs
    classifier = 'sources'
}    

task javadoc(type: Javadoc, dependsOn: explodeAars) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
    classpath += configurations.javadocDeps
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

artifacts {
    archives javadocJar
    archives sourcesJar
}
3种可能的解决方案:

1) 以某种方式从它所依赖的每个aar库添加到classpath classes.jar构建/中间/分解aar/library/version/jars/classes.jar 我不知道如何在javadoc任务中包含这些路径

2) 从aar文件中手动解包classes.jar,并将它们添加到javadoc任务的类路径中

3) 非常肮脏的黑客-硬编码的图书馆路径-但我认为这是错误的


如何使用gradle dsl实现1或2?

这只适用于早于2.3和/或早于3.3的Android Studio

要从AAR中添加JAR,可以将以下
doFirst
添加到javadoc任务中:

task javadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
}
.doFirst {
    classpath += fileTree(dir: "$buildDir/intermediates/exploded-aar/", include:"**/classes.jar")
}

它将把所有AAR中的所有
.jar
文件添加到javadoc类路径。(您建议的解决方案中的选项1)

来自@rve的解决方案现在在Android Studio 2.3/Gradle 3.3上被破坏,因为分解的aar不再存在(在构建目录中没有替代方案)

如果您所依赖的aar不是项目中的一个模块,那么您需要首先提取classes.jar,然后再在类路径中引用它(基本上是手动重新创建
中间/分解的aar

如果您所依赖的aar只是项目中的另一个模块,那么您也可以使您的javadoc任务依赖于该模块的编译任务,并引用该模块的
中间体/类/发行版
(例如,如果您使javadoc依赖于assembleRelease)。该解决方案的一个示例:


我真的希望有人能想出一个更好的解决方案。

我通过提取每个AAR文件中包含的
classes.jar
并将其添加到javadoc任务的类路径,成功地自动化了Guillaume Perrot的解决方案

它似乎适用于Android Studio 2.3和Gradle 3.3上的AAR依赖项和AAR模块

import java.nio.file.Files
import java.nio.file.Paths
import java.io.FileOutputStream
import java.util.zip.ZipFile

task javadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += configurations.compile
    classpath += configurations.provided

    afterEvaluate {
        // Wait after evaluation to add the android classpath
        // to avoid "buildToolsVersion is not specified" error
        classpath += files(android.getBootClasspath())

        // Process AAR dependencies
        def aarDependencies = classpath.filter { it.name.endsWith('.aar') }
        classpath -= aarDependencies
        aarDependencies.each { aar ->
            // Extract classes.jar from the AAR dependency, and add it to the javadoc classpath
            def outputPath = "$buildDir/tmp/aarJar/${aar.name.replace('.aar', '.jar')}"
            classpath += files(outputPath)

            // Use a task so the actual extraction only happens before the javadoc task is run
            dependsOn task(name: "extract ${aar.name}").doLast {
                extractEntry(aar, 'classes.jar', outputPath)
            }
        }
    }
}

// Utility method to extract only one entry in a zip file
private def extractEntry(archive, entryPath, outputPath) {
    if (!archive.exists()) {
        throw new GradleException("archive $archive not found")
    }

    def zip = new ZipFile(archive)
    zip.entries().each {
        if (it.name == entryPath) {
            def path = Paths.get(outputPath)
            if (!Files.exists(path)) {
                Files.createDirectories(path.getParent())
                Files.copy(zip.getInputStream(it), path)
            }
        }
    }
    zip.close()
}

我正在运行新的AndroidStudio 3.0-beta7,并尝试使用@nicopico的答案,但失败了,出现了许多不同的错误,因此这里对它进行了修改,它不依赖于不存在的
java.nio
实用程序

task javadoc(type: Javadoc) {
    failOnError false
    source = android.sourceSets.main.java.srcDirs
    // Also add the generated R class to avoid errors...
    // TODO: debug is hard-coded
    source += "$buildDir/generated/source/r/debug/"
    // ... but exclude the R classes from the docs
    excludes += "**/R.java"

    // TODO: "compile" is deprecated in Gradle 4.1, 
    // but "implementation" and "api" are not resolvable :(
    classpath += configurations.compile

    afterEvaluate {
        // Wait after evaluation to add the android classpath
        // to avoid "buildToolsVersion is not specified" error
        classpath += files(android.getBootClasspath())

        // Process AAR dependencies
        def aarDependencies = classpath.filter { it.name.endsWith('.aar') }
        classpath -= aarDependencies
        aarDependencies.each { aar ->
            System.out.println("Adding classpath for aar: " + aar.name)
            // Extract classes.jar from the AAR dependency, and add it to the javadoc classpath
            def outputPath = "$buildDir/tmp/exploded-aar/${aar.name.replace('.aar', '.jar')}"
            classpath += files(outputPath)

            // Use a task so the actual extraction only happens before the javadoc task is run
            dependsOn task(name: "extract ${aar.name}").doLast {
                extractEntry(aar, 'classes.jar', outputPath)
            }
        }
    }
}

// Utility method to extract only one entry in a zip file
private def extractEntry(archive, entryPath, outputPath) {
    if (!archive.exists()) {
        throw new GradleException("archive $archive not found")
    }

    def zip = new java.util.zip.ZipFile(archive)

    zip.entries().each {
        if (it.name == entryPath) {
            def path = new File(outputPath)

            if (!path.exists()) {
                path.getParentFile().mkdirs()

                // Surely there's a simpler is->os utility except
                // the one in java.nio.Files? Ah well...
                def buf = new byte[1024]
                def is = zip.getInputStream(it)
                def os = new FileOutputStream(path)
                def len

                while ((len = is.read(buf)) != -1) {
                    os.write(buf, 0, len)
                }
                os.close()
            }
        }
    }
    zip.close()
}

让我烦恼的是,我们需要所有这些代码来为一个库生成一个奇怪的javadoc,但至少我做到了这一点。但是,我确实需要为configuration.api和configuration.implementation找到一个解决方案。这就是我使用zipTree解决这个问题的方法。配置:Gradle4.10,Gradle插件:3.3.2,安卓工作室:3.4

task javadoc(type: Javadoc) {

    doFirst {
        configurations.implementation
                .filter { it.name.endsWith('.aar') }
        .each { aar ->
            copy {
                from zipTree(aar)
                include "**/classes.jar"
                into "$buildDir/tmp/aarsToJars/${aar.name.replace('.aar', '')}/"
            }
        }
    }

    configurations.implementation.setCanBeResolved(true)
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
    classpath += configurations.implementation
    classpath += fileTree(dir: "$buildDir/tmp/aarsToJars/")
    destinationDir = file("${project.buildDir}/outputs/javadoc/")
    failOnError false
    exclude '**/BuildConfig.java'
    exclude '**/R.java'
}

你在用安卓工作室吗?有into Tools>Generate JavaDoc一个方便的工具来选择JavaDoc需要采取什么。我使用android studio,但这个任务必须在远程jenkins实例上自动完成。这个用于将库上传到jcenter/Mavencentralt的任务现在已经被AndroidStudio 2.3/Gradle 3.3打破。分解后的aar目录已经不存在了。附带说明:这对于android gradle插件2.3.3中的库项目不起作用!这似乎对我很有效!使用gradle 3.3对我来说不起作用,但我在金丝雀频道使用gradle插件3.0(Android Studio 3.0-beta 7)。我不得不删除“提供的”配置以进行编译,但结果与以前一样-javadoc生成失败,因为没有解决外部依赖关系。使用com.android.tools.build:gradle:3.0.0-beta7和gradle-4.1,我遇到了几个不同的问题。首先,一些java.nio类不可用,所以我重写了您的代码,没有
路径
文件
。下一个问题是新的配置
api
implementation
无法解决,因此我不得不求助于使用
compile
依赖项。这样做之后,它仍然失败,因为它找不到自己的R类。在手动添加/build/generated/source/r/debug之后,我得到了一个工作的javadoc。但是我真的需要新的指令来工作..我的@nicopico代码的调整版本发布在下面作为替代答案。非常感谢您的努力@nicopico!!另外还提出了另外一个问题: