I am trying to include the documentation into maven publication. The publication itself works fine. I can also publish with the setup bellow sources and javadoc to gitlab packages. I can download and open the javadoc.jar and sources.jar which contains those comments/documentation of classes. However when I include that library as a dependency to my android app as a gradle dependency, I can not see the comments on my interfaces/classes with F1 or when I open that class.
Any help would be appreciated.
Using kotlin DSL
id("maven-publish")
id("org.jetbrains.dokka")
tasks {
dokka {
outputFormat = "javadoc"
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.registering(Jar::class) {
archiveClassifier.set("sources")
from(android.sourceSets.getByName("main").java.srcDirs)
}
artifacts {
archives(sourcesJar)
archives(dokkaJar)
}
afterEvaluate {
publishing {
publications {
create<MavenPublication>("snapshot_aar") {
groupId = libGroupId
artifactId = libArticactId
version = getVersionNameForSnapshot()
artifact(tasks.getByName("bundleDebugAar"))
artifact(dokkaJar)
artifact(sourcesJar)
pom.withXml {
fun groovy.util.Node.addDependency(dependency: Dependency) {
appendNode("dependency").apply {
appendNode("groupId", dependency.group)
appendNode("artifactId", dependency.name)
appendNode("version", dependency.version)
}
}
asNode().appendNode("dependencies").let { dependencies ->
configurations.api.get().allDependencies.forEach {
dependencies.addDependency(it)
}
configurations.implementation.get().allDependencies.forEach {
dependencies.addDependency(it)
}
}
}
}
...
Related
I'm using jFrog artifactory to publish an Android Library. The library is getting published fine. But when I try to use it, the gradle dependencies of the library are not loading up.
My pom.xml already has those dependencies.
My library has two modules -
-app
-secondarymod
And this is my code in main project level build.gradle -
artifactoryPublish.skip = true
project('app') {
artifactoryPublish.dependsOn('build')
publishing {
publications {
aar(MavenPublication) {
groupId = "in.mikkel.mainapp"
artifactId = project.getName()
version = "1.0.24"
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
pom.withXml {
def dependencies = asNode().appendNode("dependencies")
configurations.implementation.allDependencies.each {
def dependency = dependencies.appendNode("dependency")
print(it.group)
dependency.appendNode("groupId", it.group)
dependency.appendNode("artifactId", it.name)
dependency.appendNode("version", it.version)
}
}
}
}
}
artifactoryPublish {
publications(publishing.publications.aar)
}
}
project('secondarymod') {
artifactoryPublish.dependsOn('build')
publishing {
publications {
aar(MavenPublication) {
groupId = "in.mikkel.mainapp"
artifactId = project.getName()
version = "1.0.24"
// Tell maven to prepare the generated "*.aar" file for publishing
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
pom.withXml {
def dependencies = asNode().appendNode("dependencies")
configurations.implementation.allDependencies.each {
def dependency = dependencies.appendNode("dependency")
print(it.group)
dependency.appendNode("groupId", it.group)
dependency.appendNode("artifactId", it.name)
dependency.appendNode("version", it.version)
}
}
}
}
}
artifactoryPublish {
publications(publishing.publications.aar)
}
}
artifactory {
contextUrl = 'https://mikkel.jfrog.io/artifactory'
publish {
repository {
repoKey = 'mikkelcl-gradle-release-local'
username = "***"
password = "***"
}
defaults {
publications('aar')
publishArtifacts = true
publishPom = true
}
}
}
Can anyone tell me what's wrong?
Generally speaking, in the package managers world, dependencies are never published. Only Artifacts does. The dependencies should be downloaded in the CI in the same way you download them in your local machine.
If the dependencies are your private code, you should build and publish them separately.
Otherwise, you should configure the dependencies repository on your build.gradle file. In that case, please make sure that the repository is configured in the repositories clause.
Read more about Declaring repositories in Gradle here.
Every time I publish a Kotlin Multiplatform Mobile library to maven central the only I can seem to add/use the Android dependency in an Android app is by adding both the releaseImplementation and debugImplementation
Example
releaseImplementation 'io.github.tyczj.lumberjack:Lumberjack-android:1.0.0#aar'
debugImplementation 'io.github.tyczj.lumberjack:Lumberjack-android-debug:1.0.0#aar'
Instead of the "normal" way where you just have a single implementation
implementation 'io.github.tyczj.lumberjack:Lumberjack-android:1.0.0'
Here is my build.gradle file
plugins {
kotlin("multiplatform") version "1.4.32"
id("com.android.library")
id("io.github.gradle-nexus.publish-plugin") version "1.1.0"
id("maven-publish")
id("signing")
}
group = "io.github.tyczj.lumberjack"
version = "1.0.2"
ext["signing.keyId"] = ""
ext["signing.password"] = ""
ext["signing.secretKeyRingFile"] = ""
repositories {
google()
mavenCentral()
maven {
setUrl("https://plugins.gradle.org/m2/")
}
}
val javadocJar by tasks.registering(Jar::class) {
archiveClassifier.set("javadoc")
}
val emptyJar by tasks.registering(Jar::class) {
archiveAppendix.set("empty")
}
kotlin {
android{
publishLibraryVariants("release", "debug")
}
iosX64("ios") {
binaries {
framework {
baseName = "lumberjack"
}
}
}
sourceSets {
val commonMain by getting
val commonTest by getting
val androidMain by getting
val androidTest by getting
val iosMain by getting
val iosTest by getting
}
}
android {
compileSdkVersion(29)
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdkVersion(24)
targetSdkVersion(29)
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
}
afterEvaluate {
publishing {
repositories {
maven {
name = "sonatype"
url = uri("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = rootProject.ext["ossrhUsername"]?.toString()
password = rootProject.ext["ossrhPassword"]?.toString()
}
}
}
publications.withType<MavenPublication> {
artifact(javadocJar.get())
pom{
name.set("Lumberjack")
description.set("Logging library for Kotlin Multiplatform Mobile applications")
url.set("https://github.com/tyczj/Lumberjack")
licenses {
license {
name.set("MIT")
url.set("https://opensource.org/licenses/MIT")
}
}
developers {
developer {
id.set("tyczj")
name.set("Jeff Tycz")
email.set("tyczj359#gmail.com")
}
}
scm {
url.set("https://github.com/tyczj/Lumberjack")
}
}
}
}
}
ext["signing.keyId"] = rootProject.ext["signing.keyId"]?.toString()
ext["signing.password"] = rootProject.ext["signing.password"]?.toString()
ext["signing.secretKeyRingFile"] = rootProject.ext["signing.secretKeyRingFile"]?.toString()
signing {
sign(publishing.publications)
}
apply(from = "${rootDir}/scripts/publish-root.gradle")
The full source for this library can be found here
What is wrong with how I am building/publishing KMM libraries where I have to specify the release and debug implementations?
You should not specify -android postfix, just use implementation("io.github.tyczj.lumberjack:Lumberjack:1.0.0").
This works because dependency variant resolution is based on Gradle Module Metadata. This metadata is just another file published with your library (it has .module extension) and it contains description of all variants. As you are publishing the library as a whole, the top-level artifact io.github.tyczj.lumberjack:Lumberjack contains the metadata for the whole library, allowing gradle to choose the right variant.
Another option would be to make sure your -android artifact contains proper module metadata with both release and debug variants. I believe publishLibraryVariantsGroupedByFlavor is the way to tell the publisher plugin to make it this way, but I have not tried it.
I've got a few libraries that I want to publish to a local Maven. I want to use a Plugin for this to maximum reuse.
The basic code setup is this:
apply plugin: 'com.android.library'
apply plugin: 'LibraryPlugin'
android {
defaultConfig {
versionCode 1
versionName "1.0q"
}
}
def groupId = "x.y.z"
def artifactId = "LibZ"
project.afterEvaluate {
publishing {
publications {
parseDebugLibraryResources(MavenPublication) {
setGroupId groupId
setArtifactId artifactId
version = android.defaultConfig.versionName
}
}
}
}
After a ./gradlew publishToMavenLocal it is correctly placed there.
I want to move that project.afterEvaluate > publishing > publications stuff into the Plugin so I can reuse it in multiple projects.
Here's the Plugin code:
class LibraryPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.apply("kotlin-android")
project.plugins.apply("maven-publish")
project.dependencies.add("implementation", BuildPlugins.kotlinStandardLibrary)
val extension = project.extensions.getByType<LibraryExtension>()
extension.configureLibrary()
project.afterEvaluate {
// publishing {
// }
}
}
private fun LibraryExtension.configureLibrary() {
setCompileSdkVersion(AndroidSdk.compile)
defaultConfig.apply {
setMinSdkVersion(AndroidSdk.min)
setTargetSdkVersion(AndroidSdk.target)
testInstrumentationRunner = TestLibraries.UI.instrumentationRunner
}
}
}
Now it doesn't know the "publishing" node in Project.afterEvaluate. How can I move that code in to the Plugin?
I needed to get the publishing node like this:
val publishing = project.properties["publishing"] as PublishingExtension
Full example:
class LibraryPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.apply("kotlin-android")
project.plugins.apply("maven-publish")
project.dependencies.add("implementation", BuildPlugins.kotlinStandardLibrary)
val extension = project.extensions.getByType<LibraryExtension>()
extension.configureLibrary()
project.afterEvaluate {
val publishing = project.properties["publishing"] as PublishingExtension
publishing {
}
}
}
private fun LibraryExtension.configureLibrary() {
setCompileSdkVersion(AndroidSdk.compile)
defaultConfig.apply {
setMinSdkVersion(AndroidSdk.min)
setTargetSdkVersion(AndroidSdk.target)
testInstrumentationRunner = TestLibraries.UI.instrumentationRunner
}
}
}
I have Android Studio projects that build AARs or APKs in both release and debug versions. I'd like to publish these to different to different repositories on my Artifactory server. The JFrog examples don't appear to cover this case.
Does this mean that it's considered best practice to simply build either only the release or only the debug version, and choose what and where to upload based on the type of build?
I configured my android library build.gradle file that compiled aar file could be uploaded in different repos, dependent on build type.
For example you want to publish debug artifats to 'libs-debug-local' repository and release artifacts to 'libs-release-local' repository.
//First you should configure all artifacts you want to publish
publishing {
publications {
//Iterate all build types to make specific
//artifact for every build type
android.buildTypes.all { variant ->
//it will create different
//publications ('debugAar' and 'releaseAar')
"${variant.name}Aar"(MavenPublication) {
def manifestParser = new com.android.builder.core.DefaultManifestParser()
//Set values from Android manifest file
groupId manifestParser.getPackage(android.sourceSets.main.manifest.srcFile)
version = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
artifactId project.getName()
// Tell maven to prepare the generated "*.aar" file for publishing
artifact("$buildDir/outputs/aar/${project.getName()}-${variant.name}.aar")
}
}
}
}
//After configuring publications you should
//create tasks to set correct repo key
android.buildTypes.all { variant ->
//same publication name as we created above
def publicationName = "${variant.name}Aar"
//new task name
def taskName = "${variant.name}Publication"
//in execution time setting publications and repo key, dependent on build type
tasks."$taskName" << {
artifactoryPublish {
doFirst {
publications(publicationName)
clientConfig.publisher.repoKey = "libs-${variant.name}-local"
}
}
}
//make tasks assembleDebug and assembleRelease dependent on our new tasks
//it helps to set corrent values for every task
tasks."assemble${variant.name.capitalize()}".dependsOn(tasks."$taskName")
}
//Inside artifactory block just set url and credential, without setting repo key and publications
artifactory {
contextUrl = 'http://artifactory.cooperok.com:8081/artifactory'
publish {
repository {
username = "username"
password = "password"
}
defaults {
publishArtifacts = true
// Properties to be attached to the published artifacts.
properties = ['qa.level': 'basic', 'dev.team': 'core']
}
}
}
That's all. Now if you run command
Win : gradlew assembleRelease artifactoryPublish
Mac : ./gradlew assembleRelease artifactoryPublish
aar file will be uploaded to 'libs-release-local' repository.
And if you ran
Win : gradlew assembleDebug artifactoryPublish
Mac : ./gradlew assembleDebug artifactoryPublish
it will be uploaded to 'libs-debug-local' repository
One minus of this configuration is that you should always run artifactoryPublish task with assembleDebug/Release tasks
try this:-
def runTasks = gradle.startParameter.taskNames
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
if ('assembleRelease' in runTasks)
repoKey = "${artifactory_repository_release}"
else if ('assembleDebug' in runTasks)
repoKey = "${artifactory_repository_debug}"
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
defaults {
publishArtifacts = true
if ('assembleRelease' in runTasks)
publications("${artifactory_publication_release}")
else if ('assembleDebug' in runTasks)
publications("${artifactory_publication_debug}")
publishPom = true
publishIvy = false
}
}
}
where artifactory_repository_release=libs-release-local and artifactory_repository_debug=libs-debug-local
artifactory repo on which you want to publish your library arr.
After a gradle update to 'com.android.tools.build:gradle:3.x.x'
this no longer works for me.
My final solution was:
artifactory {
contextUrl = ARTIFACTORY_URL
//The base Artifactory URL if not overridden by the publisher/resolver
publish {
repository {
File debugFile = new File("$buildDir/outputs/aar/${SDK_NAME}-debug.aar");
if ( debugFile.isFile() )
repoKey = 'libs-snapshot-local'
else
repoKey = 'libs-release-local'
username = ARTIFACTORY_USER
password = ARTIFACTORY_PWD
maven = true
}
defaults {
File debugFile = new File("$buildDir/outputs/aar/${SDK_NAME}-debug.aar");
if ( debugFile.isFile() )
publications("debugAar")
else
publications("releaseAar")
publishArtifacts = true
// Properties to be attached to the published artifacts.
properties = ['qa.level': 'basic', 'dev.team': 'core']
// Is this even necessary since it's TRUE by default?
// Publish generated POM files to Artifactory (true by default)
publishPom = true
}
}
}
publishing {
publications {
//Iterate all build types to make specific
//artifact for every build type
android.buildTypes.all {variant ->
//it will create different
//publications ('debugAar' and 'releaseAar')
"${variant.name}Aar"(MavenPublication) {
writeNewPom(variant.name)
groupId GROUP_NAME
artifactId SDK_NAME
version variant.name.endsWith('debug') ? VERSION_NAME + "-SNAPSHOT" : VERSION_NAME
// Tell maven to prepare the generated "*.aar" file for publishing
artifact("$buildDir/outputs/aar/${SDK_NAME}-${variant.name}.aar")
}
}
}
}
def writeNewPom(def variant) {
pom {
project {
groupId GROUP_NAME
artifactId SDK_NAME
version variant.endsWith('debug') ? VERSION_NAME + "-SNAPSHOT" : VERSION_NAME
packaging 'aar'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
}.withXml {
def dependenciesNode = asNode().appendNode('dependencies')
configurations.api.allDependencies.each {dependency ->
if (dependency.group != null) {
def dependencyNode = dependenciesNode.appendNode('dependency')
dependencyNode.appendNode('groupId', dependency.group)
dependencyNode.appendNode('artifactId', dependency.name)
dependencyNode.appendNode('version', dependency.version)
}
}
}.writeTo("$buildDir/publications/${variant}Aar/pom-default.xml")
}
You do not need to do complex Groovy code to achieve this. I have this for the project build.gradle:
artifactory {
contextUrl = 'https://artifactory.test.com/artifactory'
publish {
repository {
repoKey = 'gradle-testing-local'
username = artifactory_username
password = artifactory_password
}
defaults {
publications('debugAar')
publications('releaseAar')
publishArtifacts = true
properties = ['qa.level': 'basic', 'q.os': 'android', 'dev.team': 'core']
publishPom = true
}
}
}
This is my module build.gradle:
publishing {
publications {
android.buildTypes.all { variant ->
"${variant.name}Aar"(MavenPublication) {
groupId libraryGroupId
version libraryVersion
artifactId "library-${variant.name}"
artifact("$buildDir/outputs/aar/library-${variant.name}.aar")
}
}
}
}
A key to note here, whatever you put in the project build.gradle's artifactory.publish.defaults, under publications() has to match the module build.gradle's loop: "${variant.name}Aar"(MavenPublication).
Another thing is you also set the artifactory_username and artifactory_password
(encrypted version from Artifactory) in ~/.gradle/gradle/gradle.properties.
For snapshots + release versions, you can use sonatype (aka mavencentral). I did up a short guide couple of weeks back which you might find of some use. How to publish Android AARs - snapshots/release to Mavencentral
Can't get publishing work with #cooperok answer otherwise it help me alots.
Here is my code:
apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 9
targetSdkVersion 23
versionCode 1
versionName "0.0.1"
}
publishNonDefault true
buildTypes {
debug {
minifyEnabled false
debuggable true
}
release {
minifyEnabled false
debuggable false
}
snapshot {
minifyEnabled false
debuggable false
}
}
}
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
artifacts {
archives androidSourcesJar
archives androidJavadocsJar
}
publishing {
publications {
android.buildTypes.all { variant ->
"${variant.name}"(MavenPublication) {
def manifestParser = new com.android.builder.core.DefaultManifestParser()
groupId manifestParser.getPackage(android.sourceSets.main.manifest.srcFile)
if("${variant.name}".equalsIgnoreCase("release")){
version = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile)
}else if ("${variant.name}".equalsIgnoreCase("debug")){
version = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile).concat("-${variant.name}".toUpperCase().concat("-SNAPSHOT"))
}else{
version = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile).concat("-${variant.name}".toUpperCase())
}
artifactId project.getName()
artifact("$buildDir/outputs/aar/${project.getName()}-${variant.name}.aar")
artifact androidJavadocsJar
pom.withXml {
def dependencies = asNode().appendNode('dependencies')
configurations.getByName("_releaseCompile").getResolvedConfiguration().getFirstLevelModuleDependencies().each {
def dependency = dependencies.appendNode('dependency')
dependency.appendNode('groupId', it.moduleGroup)
dependency.appendNode('artifactId', it.moduleName)
dependency.appendNode('version', it.moduleVersion)
}
}
}
}
}
}
android.buildTypes.all { variant ->
model {
tasks."generatePomFileFor${variant.name.capitalize()}Publication" {
destination = file("$buildDir/publications/${variant.name}/generated-pom.xml")
}
}
def publicationName = "${variant.name}"
def taskName = "${variant.name}Publication"
task "$taskName"() << {
artifactoryPublish {
doFirst {
tasks."generatePomFileFor${variant.name.capitalize()}Publication".execute()
publications(publicationName)
clientConfig.publisher.repoKey = "${variant.name}".equalsIgnoreCase("release") ? "libs-release-local" :
"libs-snapshot-local"
}
}
}
tasks."assemble${variant.name.capitalize()}".dependsOn(tasks."$taskName")
}
artifactory {
contextUrl = 'http://172.16.32.220:8081/artifactory'
publish {
repository {
username = "admin"
password = "password"
}
defaults {
publishPom = true
publishArtifacts = true
properties = ['qa.level': 'basic', 'dev.team': 'core']
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
}
artifactory {
contextUrl = "${artifactory_contextUrl}"
publish {
repository {
repoKey = 'your repo key'
username = "${artifactory_user}"
password = "${artifactory_password}"
mavenCompatible = true
}
defaults {
publications('mavenJava')
publishBuildInfo = true
publishArtifacts = true
publishPom = true
}
}
resolve {
repository {
repoKey = 'yourrepokey'
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
}
}
publishing {
publications {
mavenJava(MavenPublication) {
groupId = "$group"
artifactId = "$rootProject.name"
version = "${ver}"
from components.java
artifact jar
artifact javadocJar
artifact sourcesJar
}
}
}
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.
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 also: https://developer.android.google.cn/studio/build/maven-publish-plugin
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 and transitive: 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") }
}
}
}
}
}
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
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'
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.
This 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")
}
}
}
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