2016-03-07 48 views
5

Ho un progetto di libreria Android che dipende da altri progetti di libreria Android. Ho bisogno di generare javadoc per la libreria, ma fallisce perché gradle mette su javadoc classpath path in posizioni .aar ma javadoc si aspetta file .jar.Come generare javadoc per la libreria Android quando ha dipendenze che sono anche librerie di aar?

semplificata di file 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 possibili soluzioni:

1) in qualche modo da aggiungere al classes.jar percorso classpath da ogni biblioteca AAR dipende costruire/intermidiates/esplosa-AAR/library /version/jars/classes.jar Non so come includere questi percorsi nell'attività javadoc.

2) decomprimere manualmente classes.jar da file AAR e aggiungerli al classpath di javadoc compito

3) molto sporchi Hack - hardcoded percorsi mediante la libreria - ma penso che questo è così sbagliato.

Come ottenere 1 o 2 con gradle dsl?

+0

Stai usando Android Studio? C'è in Strumenti> Genera JavaDoc uno strumento utile per selezionare ciò che la javadoc deve fare. – xiaomi

+0

Io uso Android Studio ma questa operazione deve essere eseguita automaticamente sull'istanza di jenkins remota. Questa attività è stata utilizzata per caricare la libreria su jcenter/mavenCentral – curioushikhov

risposta

4

La soluzione da @rve è ora interrotta su Android Studio 2.3/Gradle 3.3 in quanto lo exploded-aar non esiste più (senza alternative all'interno della directory di build).

Se l'aar da cui si dipende non è un modulo nel progetto, sarà necessario prima estrarre il classes.jar prima di fare riferimento nel percorso di classe (in pratica ricreare manualmente intermediates/exploded-aar manualmente).

Se l'aar di cui si dipende è solo un altro modulo nel progetto, è possibile anche eseguire il task javadoc in base all'attività di compilazione di quel modulo e fare riferimento allo intermediates/classes/release di quel modulo (se si fa in modo che javadoc dipenda da assembleRelease) . Un esempio di questa soluzione alternativa: https://github.com/Microsoft/mobile-center-sdk-android/pull/345/files

Vorrei davvero che qualcuno fornisse una soluzione migliore.

5

Questo funziona solo per Android Studio di età superiore a 2,3 e/o Gradle di età superiore a 3,3

Per aggiungere i JAR dalla RAA è possibile aggiungere il seguente doFirst al compito javadoc:

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

Aggiungerà tutti i file .jar da tutti gli AAR al percorso di classe javadoc. (opzione 1 delle soluzioni proposte)

+4

Questo è stato risolto con Android Studio 2.3/Gradle 3.3. La directory esplosa-aar non esiste più. –

+0

una nota a margine: questo non funziona per i progetti di libreria con il plugin gradle android 2.3.3 – NemoOudeis

6

sono riuscito a automatizzare la soluzione del Guillaume Perrot estraendo il classes.jar contenute in ogni file AAR, e l'aggiunta al classpath del compito javadoc.

Sembra funzionare per le dipendenze AAR e moduli AAR su Android Studio 2.3 e 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

Ottimo lavoro! Questo sembra funzionare bene per me! Utilizzando gradle 3.3. –

+0

Questo non ha funzionato per me, ma sto utilizzando il plugin gradle 3.0 nel canale canarino (Android Studio 3.0-beta 7). Ho dovuto rimuovere la configurazione "fornita" per farlo compilare, ma il risultato è come prima - la generazione di javadoc fallisce perché le dipendenze esterne non vengono risolte. – JHH

+0

Con com.android.tools.build:gradle:3.0.0-beta7 e quindi gradle-4.1, ottengo diversi problemi. Prima di tutto, alcune delle classi java.nio non sono disponibili, quindi ho riscritto il tuo codice senza 'Paths' e' Files'. Il problema successivo è stato che le nuove configurazioni 'api' e' implementation' non sono risolvibili, quindi ho dovuto ricorrere all'uso delle dipendenze 'compile'. Dopo aver fatto ciò, fallisce ancora perché non riesce a trovare la sua classe R. Dopo aver aggiunto/build/generated/source/r/debug manualmente, ho ottenuto un javadoc funzionante. Ma ho davvero bisogno che le nuove direttive funzionino .. – JHH

1

Sono in esecuzione il nuovo Android Studio 3.0-beta7, e ha cercato di usare @ risposta di nicopico, ma non è riuscito con un numero di errori diversi, quindi ecco un suo adattamento che non si basa sulle inesistenti utilità 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() 
} 

Mi da fastidio che abbiamo bisogno di tutto questo codice per produrre un javadoc impazzendo per una libreria, ma almeno ho ottenuto questo lavoro. Tuttavia, ho bisogno di trovare una soluzione alternativa per configuration.api e configuration.implementation non risolvibili.

+0

Domanda anche separata: https://stackoverflow.com/questions/46810769/how-to-get-dependencies-from-a-gradle-plugin-using-api-or-implementation-dir – JHH