Android Library Publishing Maven Artifacts via gradle
apply plugin: 'maven'
apply plugin: 'signing'
def isReleaseBuild() {
return !VERSION_NAME.contains("SNAPSHOT");
}
def getReleaseRepositoryUrl() {
println "Reading Maven repository Release URL from gradle.properties 'RELEASE_REPOSITORY_URL'"
if (hasProperty('RELEASE_REPOSITORY_URL')) {
return RELEASE_REPOSITORY_URL;
}
throw new InvalidUserDataException("RELEASE_REPOSITORY_URL is not defined");
}
def getSnapshotRepositoryUrl() {
println "Reading Maven repository Snapshot URL from gradle.properties 'SNAPSHOT_REPOSITORY_URL'"
if (hasProperty('SNAPSHOT_REPOSITORY_URL')) {
return SNAPSHOT_REPOSITORY_URL;
}
throw new InvalidUserDataException("SNAPSHOT_REPOSITORY_URL is not defined");
}
def getRepositoryUsername() {
println "Reading Maven repository username from gradle.properties 'mavenRepositoryUsername'"
if (hasProperty('mavenRepositoryUsername')) {
return mavenRepositoryUsername;
}
throw new InvalidUserDataException("mavenRepositoryUsername is not defined, check your user ~/.gradle/gradle.properties file");
}
def getRepositoryPassword() {
println "Reading Maven repository password from gradle.properties 'mavenRepositoryPassword'"
if (hasProperty('mavenRepositoryPassword')) {
return mavenRepositoryPassword;
}
throw new InvalidUserDataException("mavenRepositoryPassword is not defined, check your user ~/.gradle/gradle.properties file");
}
afterEvaluate { project ->
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
pom.groupId = GROUP
pom.artifactId = POM_ARTIFACT_ID
pom.version = VERSION_NAME
repository(url: getReleaseRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
snapshotRepository(url: getSnapshotRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
pom.project {
name POM_NAME
packaging POM_PACKAGING
description POM_DESCRIPTION
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEV_CONNECTION
}
licenses {
license {
name POM_LICENCE_NAME
url POM_LICENCE_URL
distribution POM_LICENCE_DIST
}
}
developers {
developer {
id POM_DEVELOPER_ID
name POM_DEVELOPER_NAME
}
}
}
}
}
}
signing {
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
}
task androidJavadocs(type: Javadoc) {
// execute only if I'm publishing on maven
onlyIf { gradle.taskGraph.hasTask(uploadArchives) }
// all the sources of the current module
source = android.sourceSets.main.java.srcDirs
// the Android SDK classpath
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
// all the dependencies classpaths
classpath += configurations.compile
// Honestly I do not remember why it's a good idea to exclude these
exclude '**/BuildConfig.class'
exclude '**/R.class'
exclude '**/R$*.class'
options {
// Java reference
links("http://docs.oracle.com/javase/8/docs/api/");
// dependencies API references (I should probably move these in the project or something)
links("http://reactivex.io/RxJava/javadoc/");
links("https://google.github.io/gson/apidocs/");
// Android reference is not standard javadoc so I need to use offline directory
linksOffline("http://d.android.com/reference/", "${android.sdkDirectory}/docs/reference")
// Java 8 javadoc is more strict, This disable that strictness
if (JavaVersion.current().isJava8Compatible()) {
addStringOption('Xdoclint:none', '-quiet')
}
}
// uncomment to avoid failing the build if javadoc fails
// failOnError false
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.sourceFiles
}
artifacts {
archives androidSourcesJar
archives androidJavadocsJar
}
}
This gitst contains a script to push Android libraries as artifacts on a maven repository using the gradle build system.
It is somewhate a fork of Chris Banes gradle push script.
This was me while trying to understand how to setup maven publishing with gradle:
Documentation is absent or very lacking and I found no script handling javadoc properly for Android. When I figured it out I decided to write this.
This script is not thought for libraries with variants.
Copy the maven_push_library.gradle
in your repository root.
set these properties in your project gradle.properties
file:
RELEASE_REPOSITORY_URL=<uri-to-deploy-your-releases-artifacts>
SNAPSHOT_REPOSITORY_URL=<uri-to-deploy-your-snapshots-artifacts>
VERSION_NAME=1.0.0
VERSION_CODE=1
GROUP=<your-group-id>
POM_LICENCE_NAME=
POM_LICENCE_URL=
POM_LICENCE_DIST=
POM_DEVELOPER_ID=
POM_DEVELOPER_NAME=
POM_URL=https://<url-to-your-project-home>
POM_SCM_URL=https://<url-to-your-repository-web-browsable>
POM_SCM_CONNECTION=scm:git@<your-repository-remote>
POM_SCM_DEV_CONNECTION=scm:git@<your-development-repository-remote>
this assume the group and version name are the same for all your modules;
feel free to override them in each module gradle.properties
file
set these properties in each module gradle.properties
file:
POM_NAME=<your-module-name>
POM_ARTIFACT_ID=<your-module-artifact-id>
POM_PACKAGING=aar
POM_DESCRIPTION=<an-optional-description>
set these properties in your USER ~/.gradle/gradle.properties
file:
mavenRepositoryUsername=<your-maven-repo-username>
mavenRepositoryPassword=<your-maven-repo-password>
add this to your root project build.gradle
script file:
subprojects {
group = GROUP
version = VERSION_NAME
}
this is needed for dependencies between modules. You can also set it for each module
add this line at the bottom of the Android library modules you want to publish:
apply from: '../maven_push_library.gradle'
You need to sign your artifacts if you need/want to deploy your modules in a public maven repository (mavenCentral, jCenter, ...).
I never needed it because I publish my company modules in a private repository, there are detailed instruction on how to setup for signing here.
Basically you need to create a key file using gpg
, then set it up to sign your artifacts.
This is a security measure to make sure no one else can release stuff on your behalf, provided you keep the key safely.
I've experimented a little in using Amazon S3 as maven server.
To do so you need to add this to your maven_push_library.gradle
file:
configurations {
mavenWagons
}
dependencies {
mavenWagons 'org.springframework.build:aws-maven:5.0.0.RELEASE'
}
afterEvaluate { project ->
uploadArchives {
repositories {
mavenDeployer {
configuration = configurations.mavenWagons
// keep whats here
}
}
}
}
This tell gradle maven plugin script to use a different wagon to publish on maven, specifically the aws-maven wagon.
Then you have to change your REPO Urls to something like:
RELEASE_REPOSITORY_URL=s3://<bucket-name>/releases
SNAPSHOT_REPOSITORY_URL=s3://<bucket-name>/snapshots
Be carefule tough: the aws-maven
wagon is a bit outdated and does not know about some new AWS Regions
(example: Frankfurt - eu-central-1) and will fail if your bucket is not in one of the
supported regions.
To setup the S3 repository you just need to create a bucket, a IAM user that can write and read from that bucket and set the AWS Access Key as username and the AWS Secret Key as password. I'm not going into details here cause this is basic AWS knowledge you can find anywhere.
Playing with IAM Roles and Groups you can also manage to get some manual user management.
Check out Square maven push script.
Have a look at this guide on how to publish on jcenter.
To setup AWS S3 for maven there are different guides: 1, 2. Many fail in suggesting the policy for the S3 user which is missing a non-intuitive permission.
At some point gradle introduced a new maven-publish plugin that is meant to replace the old maven plugin.
I found very few scripts for android using this new plugin.
None say anything about the Javadoc artifact generation or more complex behavior.
Furthermore I've read there are
issues
with the dependencies generation in the pom.xml
.
The documentation is very lacking for both maven and maven-publish plugin on Android so I'll stick on the most used one for now.