Publish an Android Library to Maven with Aar and Sources Jar

Publish an Android library to Maven with AAR and sources JAR

Here's a sample using the new maven-publish plugin.

apply plugin: 'maven-publish'

task sourceJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier "sources"
}

publishing {
publications {
bar(MavenPublication) {
groupId 'com.foo'
artifactId 'bar'
version '0.1'
artifact(sourceJar)
artifact("$buildDir/outputs/aar/bar-release.aar")
}
}
repositories {
maven {
url "$buildDir/repo"
}
}
}

Publish with ./gradlew clean build publish

How to publish in my maven local repository an existing aar with gradle?

I used an rxbinding aar for this example.

  1. As you correctly mentioned, there has to be a subproject in the "publisher" project, which must contain the aar, and a build file with the following content:

    // rxbinding/build.gradle
    apply plugin: "maven-publish"

    configurations.maybeCreate("default")
    def publishArtifact = artifacts.add("default", file('rxbinding-2.1.1.aar'))

    publishing {
    publications {
    aar(MavenPublication) {
    groupId = 'my.sample.artifact'
    artifactId = 'somerandomname'
    version = '1.0.0'
    artifact publishArtifact
    }
    }
    }

    You can apply the maven-publish plugin to any project, but then you have to define the artifacts manually, like we've just done here. Some plugins (like the java-library plugin) are integrated with the maven-publish plugin to automatically publish the default artifacts of the project.

  2. Now run ./gradlew rxbinding:publishToMavenLocal - This should place the artifact into your local repo

  3. Add implementation 'my.sample.artifact:somerandomname:1.0.0' to the consumer app, in any project on your machine.

It is very important to mention any aar published this way, will not bring it's dependencies, so you have to know what libs are needed to actually use the published aar.

I have also created an example project, where you can try this.

How do I publish an AAR to Maven Local With JavaDocs

Ok, after much research I found a solution, so I'm going to share it here if anyone will need this.
(I don't want you to be frustrated like I was).

1) Create an android library as a new module inside your project.

2) Inside the build gradle of your library place this code:

plugins {
id 'com.android.library'
id 'maven-publish'
}

android {
nothing special here...
}

This is the code for creating the Javadocs(still inside build.gradle):

task androidJavadocs(type: Javadoc){
source = android.sourceSets.main.java.srcDirs

classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
android.libraryVariants.all{ variant->
if (variant.name == 'release'){
owner.classpath += variant.javaCompileProvider.get().classpath
}
}
// excluding a specific class from being documented
exclude '**/NameOfClassToExclude.java'

title = null

options{
doclet = "com.google.doclava.Doclava"
docletpath = [file("libs/doclava-1.0.6.jar")]
noTimestamp = false

// show only Protected & Public
memberLevel = JavadocMemberLevel.PROTECTED
}

}

task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs){
archiveClassifier.set('javadoc')
from androidJavadocs.destinationDir
}

task androidSourcesJar(type: Jar){
archiveClassifier.set('sources')
from android.sourceSets.main.java.srcDirs
}

This is to publish the library to MavenLocal(still inside build.gradle):

   afterEvaluate {
publishing{
publications{
release(MavenPublication){
groupId = "com.example.mylibrary"
artifactId = "mycoollibrary"
version = "1.0"
// Applies the component for the release build variant
from components.release
// Adds javadocs and sources as separate jars.
artifact androidSourcesJar
artifact androidJavadocsJar
}
}
}
}

Your default dependencies block:

dependencies {
your dependencies...
}

3) Now you can download the doclava doclet:
Extract the zip, copy the doclava-1.0.6.jar and paste it into your LibraryName/libs folder (can be found using the project view).
You only need doclava if you want to be able to use @hide.
With this annotation, you can exclude specific methods from your Javadocs.

4) Build and publish your library:
Find the gradle tab at the top right side of android studio, or find it from the toolbar View->Tool Windows->Gradle.

Now find your library -> tasks -> publishing -> publishReleasePublicationToMavenLocal.

5) To consume the library from another project:
Go to the settings.gradle file (of the consuming project) and add MavenLocal() as the first repository in the the dependencyResolutionManagement block.

And inside the module build gradle add your library as a dependency:

dependencies{
implementation 'com.example.mylibrary:mycoollibrary:1.0'
}

How to make aar the default artifact in your library

I've solved it. The problem wasn't in the pom or in the way I am packging the library. It was in the way I define it in Gradle. I used to define the custom maven repository in the root Gradle this way.

allprojects {
repositories {
google()
mavenCentral()
maven {
url "http://localhost:8081/repository/maven-releases/"
credentials {
username = "username"
password = "password"
}
allowInsecureProtocol(true)
metadataSources{
mavenPom()
}
}
}
}

However, the documentation stated that

"Since Gradle 5.3, when parsing a metadata file, be it, Ivy or Maven, Gradle will look for a marker indicating that a matching Gradle Module Metadata files exist. If it is found, it will be used instead of the Ivy or Maven file.

Starting with Gradle 5.6, you can disable this behavior by adding ignoreGradleMetadataRedirection() to the metadataSources declaration."

so I've edited it as following.

allprojects {
repositories {
google()
mavenCentral()
maven {
url "http://localhost:8081/repository/maven-releases/"
credentials {
username = "username"
password = "password"
}
allowInsecureProtocol(true)
metadataSources{
mavenPom()
ignoreGradleMetadataRedirection()
}
}
}
}

How can I add docstrings to android maven-publish .aar files in build.gradle.kts?

While I've read about other devs being able to cram the javadocs into the .aar file, this is not explicitly necessary at all to gain documentation and source code inspection from inside IDEs like Android Studio. In fact, looking at the way a typical java library works, it creates files like:

  • foo-ver.jar
  • foo-ver-sources.jar
  • foo-ver-javadoc.jar

The only difference with an Android library would be having these files:

  • foo-ver.aar
  • foo-ver-sources.jar
  • foo-ver-javadoc.jar

Which means that the sources and javadoc jars can still be copied along the .aar and the IDE will load them. Having said that, the publish example code only creates the .aar file, looking at other questions like this one I was able to modify the script to create the .aar plus the two other .jar packages:

import org.jetbrains.kotlin.config.KotlinCompilerVersion

plugins {
id("com.android.library")
kotlin("android")
`maven-publish`
id("org.jetbrains.dokka") version "0.9.17"
}

group = "com.wavelt.libs"
version = "1.0.0"

android {
compileSdkVersion(30)
buildToolsVersion = "30.0.2"
defaultConfig {
minSdkVersion(16)
targetSdkVersion(30)
versionCode = 1
versionName = "1.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xinline-classes")
}
}

dependencies {
//implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
implementation(kotlin("stdlib-jdk7", KotlinCompilerVersion.VERSION))
implementation("androidx.core:core-ktx:1.3.2")
implementation("androidx.appcompat:appcompat:1.2.0")
implementation("com.google.android.material:material:1.3.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.2")
androidTestImplementation("androidx.test.espresso:espresso-core:3.3.0")
androidTestImplementation("com.android.support.test:runner:1.0.2")
androidTestImplementation("com.android.support.test:rules:1.0.2")
}

tasks.dokka {
outputFormat = "html"
outputDirectory = "$buildDir/javadoc"
moduleName = rootProject.name
}

val dokkaJar by tasks.creating(Jar::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles Kotlin docs with Dokka"
archiveClassifier.set("javadoc")
from(tasks.dokka)
dependsOn(tasks.dokka)
}

val sourcesJar by tasks.creating(Jar::class) {
group = JavaBasePlugin.DOCUMENTATION_GROUP
description = "Assembles sources JAR"
archiveClassifier.set("sources")
from(android.sourceSets.getByName("main").java.srcDirs)
}

artifacts {
archives(sourcesJar)
archives(dokkaJar)
}

// https://developer.android.com/studio/build/maven-publish-plugin
afterEvaluate {
publishing {
repositories {
maven {
// https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:repositories
url = uri("$buildDir/repository")
}
}
publications {
create<MavenPublication>("debug") {
// Applies the component for the release build variant.
from(components["debug"])
artifactId = "wavelt-android-debug"
artifact(sourcesJar)
artifact(dokkaJar)
}
create<MavenPublication>("release") {
// Applies the component for the release build variant.
from(components["release"])
artifactId = "wavelt-android"
}
}
}
}

With these modifications the ./gradlew publish task will generate all files, and despite one of them having .aar they work the same as .jar when copied together into another project.



Related Topics



Leave a reply



Submit