当 android 库具有也是 aar 库的依赖项时,如何为它生成 javadoc?
How to generate javadoc for android library when it has dependencies which are also aar libraries?
我有 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 任务的类路径中
3) 非常肮脏的 hack - 库的硬编码路径 - 但我认为这是错误的。
如何使用 gradle dsl 实现 1 或 2?
这仅适用于 Android Studio 早于 2.3 and/or Gradle 早于 3.3
要从 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 上被破坏,因为 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
不过,我真的希望有人能提出更好的解决方案。
我设法通过提取每个 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()
}
我是 运行 新的 Android Studio 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
解决这个问题的方法。配置: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'
}
如果您正在使用 Kotlin 开发 Android app/library,那么此处列出的所有解决方案都已过时。要生成 javadoc 以及其他几种格式的文档,请使用 KDoc 和 Dokka:
https://kotlinlang.org/docs/kotlin-doc.html
我有 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 任务的类路径中
3) 非常肮脏的 hack - 库的硬编码路径 - 但我认为这是错误的。
如何使用 gradle dsl 实现 1 或 2?
这仅适用于 Android Studio 早于 2.3 and/or Gradle 早于 3.3
要从 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 上被破坏,因为 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
不过,我真的希望有人能提出更好的解决方案。
我设法通过提取每个 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()
}
我是 运行 新的 Android Studio 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
解决这个问题的方法。配置: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'
}
如果您正在使用 Kotlin 开发 Android app/library,那么此处列出的所有解决方案都已过时。要生成 javadoc 以及其他几种格式的文档,请使用 KDoc 和 Dokka:
https://kotlinlang.org/docs/kotlin-doc.html