简体   繁体   English

Android AAR 取决于 AAR 失败并生成 javadoc

[英]Android AAR depending on AAR fails with javadoc generation

I have an android gradle project structure that looks like this我有一个看起来像这样的 android gradle 项目结构

  • module1-aar模块1-aar
  • module2-aar模块2-aar
  • testapp-apk testapp-apk

Key facts关键事实

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

Without javadocs, gpg, signing, or publishing, everything builds just fine.没有 javadocs、gpg、签名或发布,一切都很好。 App runs, everything is great.应用程序运行,一切都很好。

When i started adding in tasks to generate javadocs, that's when everything went haywire.当我开始添加任务以生成 javadocs 时,一切都变得混乱了。 module1-aar will build and generate javadocs with no problem. module1-aar 将毫无问题地构建和生成 javadocs。 module2-aar however always fails during the javadoc task.然而,module2-aar 在 javadoc 任务期间总是失败。

Task is below.任务如下。 Most of it was borrowed from here How to generate javadoc for android library when it has dependencies which are also aar libraries?大部分是从这里借来的How to generate javadoc for android library 当它有依赖关系时也是 aar 库?

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

The error message i'm getting is the following我收到的错误消息如下

* 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

I've been playing around with the gradle task a bit and it seems that the error message is generated anytime i attempt to iterate over the classpath of the module2-aar.我一直在玩 gradle 任务,似乎每当我尝试遍历 module2-aar 的类路径时都会生成错误消息。

I have tried a number of other suggestions, like changing module2-aar's dependency declaration from我尝试了许多其他建议,例如更改 module2-aar 的依赖声明

api project(':module2-aar')

to

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

However that doesn't do anything然而,这并没有做任何事情

I also tried this:我也试过这个:

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

While the above resolves the reported issue, it causes a compile issue whereby module2-aar doesn't appear to have module1-aar in the classpath during compile...and it seems to compile before module1-aar.虽然上面解决了报告的问题,但它会导致编译问题,即 module2-aar 在编译期间似乎没有 module1-aar 在类路径中......并且它似乎在 module1-aar 之前编译。

Unfortunately, the documentation for what configuration means when referencing an android project is a bit thin, or perhaps I'm looking in the wrong place.不幸的是,在引用 android 项目时,关于configuration意味着什么的文档有点薄,或者我可能找错地方了。 I'm not sure what other valid values are available.我不确定还有哪些其他有效值可用。

Anyhow, I'm not sure what's wrong here other than I've spent way too much time on this.无论如何,我不确定这里出了什么问题,除了我在这上面花了太多时间。

I going to publish my solution to the problem of using "aar" files in javadoc.我将发布我对在 javadoc 中使用“aar”文件问题的解决方案。 In the course of trying to solve the problem, I too, had been getting the same error that spy was referring to.在尝试解决问题的过程中,我也遇到了间谍所指的相同错误。 That actually error means it can differentiate whether it should be using release or debug libraries.这个实际的错误意味着它可以区分它应该使用发布库还是调试库。 It seemed to me to be too futile to try and correct that issue, so instead, I took a different approach to solving what I think is essentially the same problem.在我看来,试图纠正这个问题是徒劳的,所以相反,我采取了不同的方法来解决我认为本质上相同的问题。

In my case, I have a project that contains multiple subprojects, and when I produce my javadoc documentation I wanted to produce a merged javadoc document, that consisted of just some of the subprojects (not all of the subprojects).就我而言,我有一个包含多个子项目的项目,当我生成我的 javadoc 文档时,我想生成一个合并的 javadoc 文档,它只包含一些子项目(不是所有子项目)。 As far as I know, this is not a capability, built into Android Studio.据我所知,这不是 Android Studio 内置的功能。 The current version of Android Studio(2021.2.1) seems to have problems producing javadoc documentation for android library modules.当前版本的 Android Studio(2021.2.1) 似乎在为 android 库模块生成 javadoc 文档时存在问题。 There are two issues:有两个问题:

1.) the javadoc classpath doesn't have the android bootclasses added. 1.) javadoc 类路径没有添加 android bootclasses。 You get errors for referencing any android SDK method such as "Context", "Typeface", etc.引用任何 android SDK 方法(如“Context”、“Typeface”等)都会出错。

2.) the javadoc classpath doesn't get any AndroidX libraries added to it. 2.) javadoc 类路径没有添加任何 AndroidX 库。 Many of the AndroidX libraries are "aar" files.许多 AndroidX 库都是“aar”文件。 Android Studio(2021.2.1) does not handle aar files correctly when using javadoc. Android Studio(2021.2.1) 在使用 javadoc 时无法正确处理 aar 文件。

My environment is similar to spy, except that I'm using android gradle plugin 7.2.0.我的环境类似于spy,只是我使用的是android gradle plugin 7.2.0。 I've created a custom javadoc task in the "app" module's build.gradle.kts script.我在“app”模块的 build.gradle.kts 脚本中创建了一个自定义 javadoc 任务。 My "app" module is an android application module.我的“应用程序”模块是一个 android 应用程序模块。 The code needs to be place in any module that contains either the plugin "com.android.application" or "com.android.library".代码需要放在任何包含插件“com.android.application”或“com.android.library”的模块中。 Some of the modules that I produce the merged javadoc for are java libraries, and that's okay.我为其生成合并的 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)

    }
}

I understand that you have a project structure like this: app -> module2 -> module1.我了解您的项目结构是这样的:app -> module2 -> module1。

Where -> means the dependency stream.其中->表示依赖 stream。 So I deployed a project with that same dependency flow, but using gradle 7.0.2 (because that's what I'm currently using), and had no problem generating javadoc for module2 and module1所以我部署了一个具有相同依赖流的项目,但使用 gradle 7.0.2(因为这是我目前正在使用的),并且为 module2 和 module1 生成 javadoc 没有问题

Basically it boils down to implementing this in every gradle of every module: https://stackoverflow.com/a/73096187/9902249基本上它归结为在每个模块的每个 gradle 中实现这一点: https://stackoverflow.com/a/73096187/9902249

I hope it works for you.我希望这个对你有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM