How to generate javadoc for android library when it has dependencies which are also aar libraries?

前端 未结 5 1559
遥遥无期
遥遥无期 2020-12-19 06:47

I have android library project which depends on other android library projects. I need to generate javadoc for library but it fails because gradle puts to javadoc classpath

相关标签:
5条回答
  • 2020-12-19 07:16

    I am running the new Android Studio 3.0-beta7, and tried to use @nicopico's answer, but it failed with a number of different errors, so here's an adaptation of it that doesn't rely on the non-existent java.nio utilities.

    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()
    }
    

    It bothers me that we need all this code to produce a freaking javadoc for a library, but at least I got this working. However, I do need to find a workaround for configuration.api and configuration.implementation not being resolvable.

    0 讨论(0)
  • 2020-12-19 07:19

    This only works for Android Studio older than 2.3 and/or Gradle older than 3.3

    To add the JARs from the AARs you can add the following doFirst to the javadoc task:

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

    It will add all .jar files from all the AARs to the javadoc classpath. (option 1 from your proposed solutions)

    0 讨论(0)
  • 2020-12-19 07:20

    I managed to automate the solution of Guillaume Perrot by extracting the classes.jar contained in each AAR file, and adding it to the classpath of the javadoc task.

    It seems to work for AAR dependencies and AAR modules on Android Studio 2.3 and Gradle 3.3

    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()
    }
    
    0 讨论(0)
  • 2020-12-19 07:20

    This is how I solved this issue, using zipTree. Configuration: Gradle 4.10, Gradle Plugin: 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'
    }
    
    0 讨论(0)
  • The solution from @rve is now broken on Android Studio 2.3 / Gradle 3.3 as the exploded-aar no longer exists (with no alternative inside the build directory).

    If the aar you depend on is not a module in your project, you will need first to extract the classes.jar before referencing it in the classpath (basically re-create intermediates/exploded-aar manually).

    If the aar you depend on is just another module in your project you can also make your javadoc task depends on the compile task of that module and reference the intermediates/classes/release of that module (if you make javadoc depends on assembleRelease for example). An example of that workaround: https://github.com/Microsoft/mobile-center-sdk-android/pull/345/files

    I really wish someone comes up with a better solution though.

    0 讨论(0)
提交回复
热议问题