【问题标题】:Android AAR depending on AAR fails with javadoc generation依赖于 AAR 的 Android AAR 因 javadoc 生成而失败
【发布时间】:2022-07-24 15:07:05
【问题描述】:

我有一个看起来像这样的 android gradle 项目结构

  • module1-aar
  • module2-aar
  • testapp-apk

关键事实

  • module2-aar 依赖于 module1-aar
  • testapp-apk 依赖于 module2-aar
  • JDK11
  • Gradle 7.4.2
  • Android gradle 插件 7.1.3

没有 javadocs、gpg、签名或发布,一切都很好。应用程序运行,一切都很好。

当我开始添加任务以生成 javadocs 时,一切都变得混乱了。 module1-aar 将毫无问题地构建和生成 javadocs。然而,module2-aar 在 javadoc 任务期间总是失败。

任务如下。大部分都是从这里借来的How to generate javadoc for android library when it has dependencies which are also aar libraries?

project.task("javadoc", type: Javadoc) {
    afterEvaluate {
        configurations.all
                .each {item ->
                    item.setCanBeResolved(true)
                }

        classpath += configurations.api
        classpath += configurations.implementation
        // 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
        //fails here when an AAR depends on an AAR
        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)
            }
        }

    }

    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
    classpath += project.files(android.getBootClasspath())
    classpath += configurations.implementation
    classpath += fileTree(dir: project.buildDir.absolutePath + "/tmp/aarsToJars/")
    classpath += files(project.buildDir.absolutePath + "/intermediates/compile_r_class_jar/release/R.jar")
    classpath += files(project.buildDir.absolutePath + "/generated/source/buildConfig/release/release")
    classpath += files(project.buildDir.absolutePath + "/generated/source/r/buildConfig/release/release")
    destinationDir = file( project.buildDir.absolutePath + "/outputs/javadoc/")
     failOnError true
    options.charSet 'UTF-8'
    options.docEncoding 'UTF-8'
    options.encoding 'UTF-8'
    options.addBooleanOption 'Xdoclint:none', true
    exclude '**/BuildConfig.java'
    exclude '**/R.java'
    exclude '**/doc-files/*'
}


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

//wires in the javadoc task to the normal build
tasks.named("build") { finalizedBy("generateJavadocJar") }

我收到的错误消息如下

* What went wrong:
A problem occurred configuring project ':module2-aar'.
> Could not resolve all files for configuration ':module2-aar:implementation'.
   > Could not resolve project :module1-aar.
     Required by:
         project :module2-aar
      > Cannot choose between the following variants of project :module1-aar:
          - debugRuntimeElements
          - releaseRuntimeElements
        All of them match the consumer attributes:
          - Variant 'debugRuntimeElements' capability com.github.test:module1-aar:6.1.11-SNAPSHOT:
              - Unmatched attributes:
                  - Provides com.android.build.api.attributes.AgpVersionAttr '7.1.3' but the consumer didn't ask for it
                  - Provides com.android.build.api.attributes.BuildTypeAttr 'debug' but the consumer didn't ask for it
                  - Provides com.android.build.gradle.internal.attributes.VariantAttr 'debug' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it
          - Variant 'releaseRuntimeElements' capability com.github.test:module1-aar:6.1.11-SNAPSHOT:
              - Unmatched attributes:
                  - Provides com.android.build.api.attributes.AgpVersionAttr '7.1.3' but the consumer didn't ask for it
                  - Provides com.android.build.api.attributes.BuildTypeAttr 'release' but the consumer didn't ask for it
                  - Provides com.android.build.gradle.internal.attributes.VariantAttr 'release' but the consumer didn't ask for it
                  - Provides org.gradle.usage 'java-runtime' but the consumer didn't ask for it

我一直在玩 gradle 任务,似乎每当我尝试遍历 module2-aar 的类路径时都会生成错误消息。

我尝试了许多其他建议,例如更改 module2-aar 的依赖声明

api  project(':module2-aar')

api  project(path:':module2-aar')

但是这没有任何作用

我也试过这个:

api project(path: ':module1-aar', configuration: 'default')

虽然上述解决了报告的问题,但它会导致编译问题,即 module2-aar 在编译期间似乎在类路径中没有 module1-aar...而且它似乎在 module1-aar 之前编译。

不幸的是,configuration 在引用 android 项目时的含义的文档有点薄,或者我可能找错地方了。我不确定还有哪些其他有效值可用。

不管怎样,我不知道这里出了什么问题,除了我在这上面花了太多时间。

【问题讨论】:

  • 您是否尝试将 aar 解压缩到一个模块中并为该模块运行 javadoc 命令?
  • 手动?不。但这就是上述任务的作用
  • 我认为您走在正确的道路上,但在我看来,您仍在将 aar 文件添加到 javadoc 类路径中,但只是将其重命名为 jar 文件。我认为您需要从 aar 文件中提取 classes.jar 文件并将提取的 classes.jar 文件添加到 javadoc 类路径中。
  • 顺便说一句,不要再使用“配置”参数了。它只是出于遗留原因而存在,并且它的使用可能会产生重复类的问题。这是我从安卓开发团队得到的信息。

标签: android gradle javadoc aar


【解决方案1】:

我将发布我对在 javadoc 中使用“aar”文件问题的解决方案。在尝试解决问题的过程中,我也遇到了间谍所指的相同错误。这个实际错误意味着它可以区分它应该使用发布库还是调试库。在我看来,试图纠正这个问题是徒劳的,所以我采取了不同的方法来解决我认为本质上相同的问题。

在我的例子中,我有一个包含多个子项目的项目,当我生成我的 javadoc 文档时,我想生成一个合并的 javadoc 文档,它只包含一些子项目(不是所有子项目)。据我所知,这不是内置于 Android Studio 中的功能。当前版本的 Android Studio(2021.2.1) 似乎在为 android 库模块生成 javadoc 文档时存在问题。有两个问题:

1.) javadoc 类路径没有添加 android 引导类。引用任何 android SDK 方法(如“Context”、“Typeface”等)都会出错。

2.) javadoc 类路径没有添加任何 AndroidX 库。许多 AndroidX 库都是“aar”文件。 Android Studio(2021.2.1) 在使用 javadoc 时无法正确处理 aar 文件。

我的环境和spy类似,只不过我使用的是android gradle plugin 7.2.0。我在“app”模块的 build.gradle.kts 脚本中创建了一个自定义 javadoc 任务。我的“app”模块是一个 android 应用程序模块。代码需要放在任何包含插件“com.android.application”或“com.android.library”的模块中。我为其生成合并的 javadoc 的一些模块是 java 库,这没关系。

 // create a custom configuration  
 val javadocDeps = configurations.create("javadocDeps")

 // add javadoc dependencies that you need.
 dependencies {
     javadocDeps(project(":OsgiFramework"))
     // note: I'm using a libs version catalog for the dependencies
     // you can add hardwired dependencies if you prefer
     javadocDeps (libs.androidx.appcompat)
     javadocDeps (libs.androidx.fragment)
     javadocDeps (libs.androidx.navigation.fragment)
     javadocDeps (libs.androidx.navigation.ui)
     javadocDeps (libs.androidx.constraint.layout)
 }

 // register the createCoreJavadoc task
 // in my case, "gradlew app:createCoreJavadoc" creates the merged javadoc 
 tasks {
    register<Javadoc>("createCoreJavadoc") {
        setFailOnError(true)
        val docDir: File = File(project.projectDir.parentFile.parentFile, "Doc/Core")
        println("javadoc destination dir: " + docDir.absolutePath)
        // set the location where the documentation is produced in
        setDestinationDir(docDir)

        // select the projects to produce merged javadoc for
        var sourcepaths: FileCollection = project(":CoreInterfaces").files("src/main/java")
        sourcepaths =
            sourcepaths.plus(project(":CoreInternalInterfaces").files("src/main/java"))
        sourcepaths = sourcepaths.plus(project(":CoreAndroidInterfaces").files("src/main/java"))
        sourcepaths =
            sourcepaths.plus(project(":CoreAndroidInternalInterfaces").files("src/main/java"))
        sourcepaths = sourcepaths.plus(project(":OsgiInterface").files("src/main/java"))
        sourcepaths =
            sourcepaths.plus(project(":InstallPlanInterfaces_1_0_0").files("src/main/java"))
        setSource(sourcepaths.asFileTree)


        // fix the problem with the missing android bootclasses
        android.bootClasspath.forEach{
            classpath += fileTree(it)
        }

        // create a temporary directory for storing the "classes.jar" file contained in the *.aar files
        val tmpDir:File = File(project.buildDir, "\\tmpAar\\")
        if (tmpDir.exists()) tmpDir.delete()
        tmpDir.mkdirs()
        // add the javadoc dependencies
        javadocDeps.forEach {
            // I've got a custom class that allows me to treat jar or zip files and a file system
            // you could replace this using spy's zip file extraction method
            val zipFileSystem: com.phinneyridge.ZipFileSystem = ZipFileSystem(it.absolutePath,null)
            if (it.name.endsWith(".aar")) {
                // extract the classes.jar file from the aar file to the tmpDir
                // renaming it to name of the aar file, but change the extension to jar
                val tmpFile:File = File(tmpDir, it.name.replace(".aar", ".jar"))
                zipFileSystem.extractEntry("classes.jar", tmpFile)
            } else {
                // for jar files, we just add it to the path
                classpath += fileTree(it)
            }
        }
        // now add the tmpDir files to the javadoc classpath
        classpath += fileTree(tmpDir)
        // for diagnosis purposes, we'll print the classpath.
        // Notice that you have a lot more path entries then you have javadocDeps
        println("classpath: " + classpath.asPath)

    }
}

【讨论】:

    【解决方案2】:

    我了解到您的项目结构是这样的:app -&gt; module2 -&gt; module1。

    其中-&gt; 表示依赖流。所以我部署了一个具有相同依赖流的项目,但使用 gradle 7.0.2(因为这是我目前正在使用的),并且为 module2 和 module1 生成 javadoc 没有问题

    基本上归结为在每个模块的每个 gradle 中实现这一点:https://stackoverflow.com/a/73096187/9902249

    我希望它对你有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-21
      • 2014-05-27
      • 2016-07-10
      • 1970-01-01
      • 2014-09-29
      相关资源
      最近更新 更多