当它具有也是 aar 库的依赖项时,如何为 android 库生成 javadoc?

Posted

技术标签:

【中文标题】当它具有也是 aar 库的依赖项时,如何为 android 库生成 javadoc?【英文标题】:How to generate javadoc for android library when it has dependencies which are also aar libraries? 【发布时间】:2016-06-21 14:28:48 【问题描述】:

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

简化的 gradle 文件:

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 库添加到类路径路径 classes.jar build/intermidiates/exploded-aar/library/version/jars/classes.jar 我不知道如何在 javadoc 任务中包含这些路径。

2) 手动从aar文件中解压classes.jar并将它们添加到javadoc任务的classpath中

3) 非常肮脏的 hack - 库的硬编码路径 - 但我认为这是非常错误的。

如何用gradle dsl实现1或2?

【问题讨论】:

你用的是安卓工作室吗?在 Tools > Generate JavaDoc 中有一个方便的工具来选择 javadoc 需要采取的内容。 我使用 android studio,但是这个任务必须在远程 jenkins 实例上自动完成。此任务用于将库上传到 jcenter/mavenCentral 【参考方案1】:

我通过提取每个 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()

【讨论】:

干得好!这似乎对我很有效!使用 gradle 3.3。 这对我不起作用,但我在金丝雀频道(Android Studio 3.0-beta 7)中使用了 gradle 插件 3.0。我必须删除“提供的”配置才能编译它,但结果和以前一样 - javadoc 生成失败,因为没有解决外部依赖关系。 使用 com.android.tools.build:gradle:3.0.0-beta7 和 gradle-4.1,我遇到了几个不同的问题。首先,一些java.nio类不可用,所以我重写了你的代码,没有PathsFiles。下一个问题是新配置apiimplementation 无法解析,所以我不得不求助于使用compile 依赖项。这样做之后它仍然失败,因为它找不到自己的 R 类。手动添加 /build/generated/source/r/debug 后,我得到了一个工作的 javadoc。但我真的需要新指令才能工作.. 我的@nicopico 代码的调整版本作为替代答案发布在下面。非常感谢您@nicopico 的努力!!【参考方案2】:

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

如果你依赖的 aar 不是你项目中的一个模块,你需要先提取 classes.jar,然后在类路径中引用它(基本上是手动重新创建 intermediates/exploded-aar)。

如果您所依赖的 aar 只是项目中的另一个模块,您还可以使您的 javadoc 任务依赖于该模块的编译任务并引用该模块的 intermediates/classes/release(例如,如果您使 javadoc 依赖于 assembleRelease )。该解决方法的一个示例:https://github.com/Microsoft/mobile-center-sdk-android/pull/345/files

我真的希望有人提出更好的解决方案。

【讨论】:

【参考方案3】:

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

要从 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)

【讨论】:

这在 Android Studio 2.3 / Gradle 3.3 中被打破了。已分解的 aar 目录不再存在。 附注:这不适用于带有 android gradle 插件 2.3.3 的库项目【参考方案4】:

我正在运行新的 Android Studio 3.0-beta7,并尝试使用 @nicopico 的答案,但由于许多不同的错误而失败,所以这里有一个不依赖于不存在的 @987654322 的改编版@ 实用程序。

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 无法解析找到解决方法。

【讨论】:

还提出了单独的问题:***.com/questions/46810769/…【参考方案5】:

这就是我使用zipTree 解决此问题的方法。配置:Gradle 4.10,Gradle 插件:3.3.2,Android Studio: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'

【讨论】:

【参考方案6】:

如果您正在使用 Kotlin 开发 Android 应用/库,则此处列出的所有解决方案都已过时。要生成 javadocs 以及其他几种格式的文档,请使用 KDoc 和 Dokka:

https://kotlinlang.org/docs/kotlin-doc.html

https://kotlin.github.io/dokka/1.5.0/

https://github.com/Kotlin/dokka

【讨论】:

以上是关于当它具有也是 aar 库的依赖项时,如何为 android 库生成 javadoc?的主要内容,如果未能解决你的问题,请参考以下文章

当它是另一个项目的依赖项时,捆绑我的汇总项目是什么

在android中创建一个具有依赖项的库

安卓项目中有maven库的依赖(aar/jar)。如何使用jacoco测试依赖库的覆盖率呢

制作包含依赖库的AAR包

Gradle:下载包含的 aar 库的依赖项

本地 aar 库的传递依赖