Can somebody give me a hint on how to use the maven-publish
Gradle plugin to publish a com.android.library
project/module with AAR and source jar? I am able to do this with the old maven
plugin - but I would like to use the new maven-publish
plugin.
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
classifier "source"
with classifier "sources"
. –
Irrelievable Invalid publication 'library': multiple artifacts with the identical extension and classifier ('aar', 'null').
message as well. @mudit_sen, did you find a way to resolve this? –
Drape repositories
block in publishing
files are not generated even though tasks ends with a success message. What I wonder is then how jitpack.io is able to do it with the same codebase on their platform. Do they inject additional tasks or script files? Strange. –
Epizootic :generateMetadataFileForReleasePublication FAILED
with the latest Studio and gradle plugin version –
Yellowish With Android Gradle Plugin 7.1 it is now very simple to do this without needing any complicated scripts. AGP now also handles creating source and javadocs jar.
You don't need any separate scripts, just write everything into your build.gradle
file of your module:
plugins {
...
id 'maven-publish'
}
android {
...
publishing {
singleVariant("release") {
// if you don't want sources/javadoc, remove these lines
withSourcesJar()
withJavadocJar()
}
}
}
afterEvaluate {
publishing {
publications {
release(MavenPublication) {
from components.release
groupId 'com.example'
artifactId 'mylibrary'
version '1.0.0'
}
}
}
}
See official docs: https://developer.android.com/build/publish-library
Old answer
Since release of Android Studio 3.6 the support for building AAR (or even APK and AAB) is implemented in Android Gradle plugin 3.6.0 (and newer).
We don't need to handle the XML dependencies and stuff ourselves anymore.
Here is my updated Gist for Android Studio 3.6.0: https://gist.github.com/Robyer/a6578e60127418b380ca133a1291f017
Code from gist:
apply plugin: 'maven-publish'
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
}
}
exclude '**/R.html', '**/R.*.html', '**/index.html'
}
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
}
// Because the components are created only during the afterEvaluate phase, you must
// configure your publications using the afterEvaluate() lifecycle method.
afterEvaluate {
publishing {
publications {
// Creates a Maven publication called "release".
release(MavenPublication) {
// Applies the component for the release build variant.
from components.release
// Adds javadocs and sources as separate jars.
artifact androidJavadocsJar
artifact androidSourcesJar
// You can customize attributes of the publication here or in module's build.gradle file (if you save this as script and include it build.gradle file, then you can just replicate this whole block there only with changed fields).
//groupId = 'com.example'
//artifactId = 'custom-artifact'
version = android.defaultConfig.versionName // or just '1.0'
}
}
}
}
Original answer:
Here is my improved solution, based on other answers.
Gist: https://gist.github.com/Robyer/a6578e60127418b380ca133a1291f017
Changes from other answers:
- Changed
classifier
- it must be"sources"
(not"source"
) - Handles dependencies
Supports also
@aar
andtransitive: false
. In that case we set exclusion in POM to ignore all transitive dependencies of this dependency.Supports also custom exclude rules on dependencies, e.g.:
compile('com.example:something:1.0', { exclude group: 'com.exclude.this', module: 'some-module' })
- Doesn't need to specify artifact path manually.
apply plugin: 'maven-publish'
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.javaCompile.classpath
}
}
exclude '**/R.html', '**/R.*.html', '**/index.html'
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
project.afterEvaluate {
publishing {
publications {
maven(MavenPublication) {
//groupId 'cz.example'
//artifactId 'custom-artifact'
//version = android.defaultConfig.versionName
artifact bundleReleaseAar
artifact androidJavadocsJar
artifact androidSourcesJar
pom.withXml {
final dependenciesNode = asNode().appendNode('dependencies')
ext.addDependency = { Dependency dep, String scope ->
if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified")
return // ignore invalid dependencies
final dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dep.group)
dependencyNode.appendNode('artifactId', dep.name)
dependencyNode.appendNode('version', dep.version)
dependencyNode.appendNode('scope', scope)
if (!dep.transitive) {
// If this dependency is transitive, we should force exclude all its dependencies them from the POM
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
exclusionNode.appendNode('groupId', '*')
exclusionNode.appendNode('artifactId', '*')
} else if (!dep.properties.excludeRules.empty) {
// Otherwise add specified exclude rules
final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
dep.properties.excludeRules.each { ExcludeRule rule ->
exclusionNode.appendNode('groupId', rule.group ?: '*')
exclusionNode.appendNode('artifactId', rule.module ?: '*')
}
}
}
// List all "compile" dependencies (for old Gradle)
configurations.compile.getDependencies().each { dep -> addDependency(dep, "compile") }
// List all "api" dependencies (for new Gradle) as "compile" dependencies
configurations.api.getDependencies().each { dep -> addDependency(dep, "compile") }
// List all "implementation" dependencies (for new Gradle) as "runtime" dependencies
configurations.implementation.getDependencies().each { dep -> addDependency(dep, "runtime") }
}
}
}
}
}
def dependencyNode = dependenciesNode.appendNode('dependency')
throws an exception Could not get unknown property 'dependenciesNode' for object of type org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication.
–
Baptista Could not get unknown property 'bundleRelease' for object of type org.gradle.api.publish.maven.internal.publication.DefaultMavenPublication.
any ideas? –
Guntar bundleRelease
is now called bundleReleaseAar
. Thanks to this answer by Artem Zinnatullin –
Animality bundleReleaseAar
, but it seems we just have to wrap whole publishing
block into project.afterEvaluate { publishing { ... } }
. Then it works again. (I updated the answer just now) –
Kolkhoz project.afterEvaluate
I get the error "Could not get unknown property 'bundleReleaseAar'". I wonder if another update messed things up? –
Anachronistic pom.withXml
. E. g. for release
flavor: configurations.releaseImplementation.getDependencies().each { dep -> addDependency(dep, "runtime") }
–
Mira publishToMavenLocal
). If you want to upload it to some remote maven repository, you need a bit more code. You can see example of such usage (in this case for Bintray repository) here: github.com/adaptech-cz/Tesseract4Android/blob/master/… –
Kolkhoz > Javadoc generation failed. Generated Javadoc options file (useful for troubleshooting): '...\build\tmp\androidJavadocs\javadoc.options'
. Is it related to that I wrote the entire code in Kotlin and not in Java? –
Llovera androidJavadocs
creates the javadocs and androidJavadocsJar
creates a *.jar file from it for publishing. This probably doesn't work with Kotlin code, but someone forked my gist to add some support for it. See there: gist.github.com/Robyer/… –
Kolkhoz afterEvaluate
when publishing? It seems to be working fine for me without it –
Millian Because the components are created only during the afterEvaluate phase, you must configure your publications using the afterEvaluate() lifecycle method.
–
Kolkhoz module.json
and pom-default.xml
in build/publications/release
path. Nothing else. But once a local repository is added in publishing
block's repositories
with name and url all the .aar/.pom/hash files are generated without any problem. Is there something missing? –
Epizootic Direct local .aar file dependencies are not supported when building an AAR. The resulting AAR would be broken because the classes and Android resources from any local .aar file dependencies would not be packaged in the resulting AAR. Previous versions of the Android Gradle Plugin produce broken AARs in this case too (despite not throwing this error). The following direct local .aar file dependencies of the :MyProject project caused this error
–
Goyette 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
classifier "source"
with classifier "sources"
. –
Irrelievable Invalid publication 'library': multiple artifacts with the identical extension and classifier ('aar', 'null').
message as well. @mudit_sen, did you find a way to resolve this? –
Drape repositories
block in publishing
files are not generated even though tasks ends with a success message. What I wonder is then how jitpack.io is able to do it with the same codebase on their platform. Do they inject additional tasks or script files? Strange. –
Epizootic :generateMetadataFileForReleasePublication FAILED
with the latest Studio and gradle plugin version –
Yellowish A little tweak to dskinners answer with correct dependency generation:
apply plugin: 'maven-publish'
task sourceJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier "source"
}
publishing {
publications {
bar(MavenPublication) {
groupId 'com.foo'
artifactId 'bar'
version '0.1'
artifact(sourceJar)
artifact("$buildDir/outputs/aar/bar-release.aar")
pom.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
//Iterate over the compile dependencies (we don't want the test ones), adding a <dependency> node for each
configurations.compile.allDependencies.each {
if(it.group != null && (it.name != null || "unspecified".equals(it.name)) && it.version != null)
{
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', it.group)
dependencyNode.appendNode('artifactId', it.name)
dependencyNode.appendNode('version', it.version)
}
}
}
}
}
repositories {
maven {
url "$buildDir/repo"
}
}
}
And you can change version
and groupId
by defining:
version = '1.0.0'
group = 'foo.bar'
artifact bundleRelease
. Also the condition (it.name != null || "unspecified".equals(it.name))
does not look correct. Did you mean (it.name != null && "unspecified" != it.name)
? –
Cimbri If you want to avoid boilerplate codes, because the maven-publish
plugin do not write dependencies into pom.xml
Try this plugin: android-maven-publish
publishing {
publications {
mavenAar(MavenPublication) {
groupId 'com.example'
artifactId 'mylibrary'
version '1.0.0'
from components.android
}
}
repositories {
maven {
url "$buildDir/releases"
}
}
}
Update:
android-maven-publish plugin is deprecated, since maven-publish is officially supported by AGP.
bundleReleaseAar
command will allow you to upload a completed build with the bintrayUpload
gradle task. Does android-maven-plugin
allow the same thing? Or do you have to build the .aar
file first and then publish? –
Anachronistic bundleReleaseAar
task builds the artifact. The android-maven-plugin
uses this task under the hood. When you set components.android on your publication it will pass the output of bundleReleaseAar
task to the publication (artifacts and deps) –
Paoting android-maven-publish
plugin is deprecated, since maven-publish
is officially supported by AGP. Use AGP 3.6.0 or newer. –
Paoting Here is how I included Dokka (view it online) and sources JARs for my Android Kotlin library using Kotlin DSL (build.gradle.kts):
plugins {
// ...
id("org.jetbrains.dokka") version "1.4.32"
id("maven-publish")
}
lateinit var sourcesArtifact: PublishArtifact
lateinit var javadocArtifact: PublishArtifact
tasks {
val sourcesJar by creating(Jar::class) {
archiveClassifier.set("sources")
from(android.sourceSets["main"].java.srcDirs)
}
val dokkaHtml by getting(org.jetbrains.dokka.gradle.DokkaTask::class)
val javadocJar by creating(Jar::class) {
dependsOn(dokkaHtml)
archiveClassifier.set("javadoc")
from(dokkaHtml.outputDirectory)
}
artifacts {
sourcesArtifact = archives(sourcesJar)
javadocArtifact = archives(javadocJar)
}
}
publishing {
// ...
publications {
create<MavenPublication>("MyPublication") {
from(components["release"])
artifact(sourcesArtifact)
artifact(javadocArtifact)
// ...
}
}
}
Using Kotlin build.gradle.kts
:
publishing.publications {
register<MavenPublication>("aar") {
groupId = "com.foo"
artifactId = "bar"
version = "0.1"
artifact("$buildDir/outputs/aar/bar-release.aar")
pom.withXml {
val dependencies = asNode().appendNode("dependencies")
val addNode = { groupId: String, artifactId: String, version: String ->
val dependency = dependencies.appendNode("dependency")
dependency.appendNode("groupId", groupId)
dependency.appendNode("artifactId", artifactId)
dependency.appendNode("version", version)
}
addNode("com.example", "dependency-name", "1.0")
}
}
}
artifactory { ... }
in the build file. This may help: jfrog.com/help/r/jfrog-integrations-documentation/… –
Hypnology You can also use the android maven plugin. It creates the .aar, javadoc.jar, sources.jar and .pom and updates the maven-metadata.xml after uploading the files to the maven repository. I also put the script on GitHub.
apply plugin: 'com.android.library'
apply plugin: 'maven'
//Your android configuration
android {
//...
}
//maven repository info
group = 'com.example'
version = '1.0.0'
ext {
//Specify your maven repository url here
repositoryUrl = 'ftp://your.maven.repository.com/maven2'
//Or you can use 'file:\\\\C:\\Temp' or 'maven-temp' for a local maven repository
}
//Upload android library to maven with javadoc and android sources
configurations {
deployerJars
}
//If you want to deploy to an ftp server
dependencies {
deployerJars "org.apache.maven.wagon:wagon-ftp:2.2"
}
// custom tasks for creating source/javadoc jars
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
destinationDir = file("../javadoc/")
failOnError false
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
//Creating sources with comments
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
//Put the androidSources and javadoc to the artifacts
artifacts {
archives androidSourcesJar
archives javadocJar
}
uploadArchives {
repositories {
mavenDeployer {
configuration = configurations.deployerJars
repository(url: repositoryUrl) {
//if your repository needs authentication
authentication(userName: "username", password: "password")
}
}
}
}
Call it with
./gradlew uploadArchives
© 2022 - 2024 — McMap. All rights reserved.