Android libraries and how to distribute one to jCenter or mavenCentral
Each time I used a good Android library I had thought about and decided to do some search and publish my own good Android library too. And it never happened until I needed to republish a deprecated library, created and distributed by a brave android developer. As soon as I noticed in the README that the library is deprecated, I cloned the repo and tested the project. And as soon as I did, I decided this work shouldn’t be lost. So I finally did “the some search” and published ” a copy of ” the Paralloid library , and I am sharing with you in this post a summary so that you can go through the process faster than I did. But first, we’ll learn a bit more Android librarires and how they work.
How does Android libraries work
I believe all of you know from where does Android studio fetch the libraries you define in gradle file, yet I will re-state the answer to such question. Android Studio downloads the library from Maven Repository Server we defined in build.gradle. Here is an example where we define maven and jcenter repositories in our build configurations.
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() google() } dependencies { classpath 'com.android.tools.build:gradle:3.0.1' //FireBase module classpath 'com.google.gms:google-services:3.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() mavenCentral() google() } }
It exists two standard servers used to host Android librairies:
• jCenter: a Maven Repository hosted by bintray.com. You could find the whole repository here.
• mavenCentral: is a Maven Repository hosted by sonatype.org. You could find the whole repository here.
Apart from these two standard servers, you can define the specific Maven Repository Server where a certain developers hosted their libraries on their own server. Twitter’s Fabric.io falls in this case where they hosted their own Maven Repository at https://maven.fabric.io/public. Here is how this repository gets defined in build.gradle :
repositories { maven { url 'https://maven.fabric.io/public' } }
Note: It exists another type of repository besides Maven repositories which works with gradle on Android Studio. It is called Ivy Repository. Yet it’s not that much used by developers.
About the second question after ‘where does these libraries come from is “how does gradle pull these libraries ?“. Answer is simple too: when you add a new library dependency to your build.gradle like the following:
compile 'com.github.AmalLibs:Paralloid:1.0.0'
Gradle will ask Maven Repository Server weather the library exists or not, if yes, it gets a path of the requested library, mostly in the form of GROUP_ID/ARTIFACT_ID/VERSION_ID (knowing that the library dependency string has a GROUP_ID:ARTIFACT_ID:VERSION format) then Android Studio would download the files from that path to your machine and compile with your project.
About the path, for example, for the Paralloid library in com.github.AmalLibs:Paralloid:1.0.0, gradle will get the follwing path: http://jcenter.bintray.com/com/github/AmalLibs/Paralloid/1.0.0/ .
How to publish an Android library
Prepare the library
To be able to publish your project as a library to Maven Central, you will need to set a few modifications on it:
- Separate library code to code that shows the usage of the library. I suggest you create a library module and a sample module.
- In the sample module’s build.gradle file, add the following:
apply plugin: 'com.android.application' dependencies { compile project(':library') }
- In the library module’s build.gradle file, add the following:
apply plugin: 'com.android.library apply from: 'maven-push.gradle'
- In the library module, add a gradle.properties file, add the following:
POM_NAME=ProjectName POM_ARTIFACT_ID=projectname POM_PACKAGING=aar
- In the library module, add a maven-push.gradle file containing the following:
apply plugin: 'maven' apply plugin: 'signing' def isReleaseBuild() { return VERSION_NAME.contains("SNAPSHOT") == false } def getReleaseRepositoryUrl() { return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" } def getSnapshotRepositoryUrl() { return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL : "https://oss.sonatype.org/content/repositories/snapshots/" } def getRepositoryUsername() { return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" } def getRepositoryPassword() { return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" } 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) { //source = android.sourceSets.main.allJava //} //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 } }
- Edit the settings.gradle file at the root level of your project as follows:
include ':sample', ':library'
- Edit the gradle.properties file located at the root level of your project as follows:
# Project-wide Gradle settings.# IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true VERSION_NAME=0.0.1 VERSION_CODE=1 GROUP=com.github.github_username POM_DESCRIPTION=A library that does X, Y, and Z POM_URL=https://github.com/github_username/ProjectName POM_SCM_URL=https://github.com/github_username/ProjectName POM_SCM_CONNECTION=scm:git@github.com:github_username/ProjectName.git POM_SCM_DEV_CONNECTION=scm:git@github.com:github_username/ProjectName.git POM_LICENCE_NAME=The Apache Software License, Version 2.0 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENCE_DIST=repo POM_DEVELOPER_ID=github_username POM_DEVELOPER_NAME=GitHub FullName
- Finally, add a README.md to explain your library’s purpose and usages.
The software repository hosting
For your project to make it to maven central it has to pass by the Sonatype Open Source Software Repository Hosting (OSSRH) . We’ll use this hosted deployment of Sonatype Nexus Professional with the Nexus Staging Suite used for the deployment process and validation. To start with :
- When creating the issue, the fields should be filled this way:
Group Id : com.github.<github_username>
Project URL : https://github.com/<github_username>/<project_name>
SCM url : https://github.com/<github_username>/<project_name>.git
Username : <sonatype_username>
Already Synced to Central : No
After you submit, it can take up to 2 business days to process your issue. Then you will receive a confirmation that your configuration has been prepared and you can publish your library. Do not deploy until after you have received an e-mail notice indicating that the ticket is Resolved.
We are almost there, what’s left is to provide your encrypted NEXUS authentication in gradle.properties file located at the root level of your project as follows:
NEXUS_USERNAME=sonatype_username NEXUS_PASSWORD=sonatype_password signing.keyId=gpg_key_id signing.password=gpg_password signing.secretKeyRingFile=/Users/username/.gnupg/secring.gpg org.gradle.daemon=true
At this level, we’ll go through how to encrypt your data using the GPG (GNU Privacy Guard) encryption software: you will obviously need to install GPG, then:
[ $ gpg --gen-key ] ,
• and publish it
$ gpg --keyserver hkp://keyserver.ubuntu.com --send-keys YYYYYYYY || $ gpg --keyserver hkp://pgp.mit.edu --send-keys YYYYYYYY
+ To check your created keys :
$ gpg --list-keys
+ To get sure your keys were published:
$ gpg --keyserver hkp://pgp.mit.edu --search-keys youremail@example.com
Now you can add the values of your keyId, gpg_password and secring.gpg file path to your gradle.properties file.
Ready to publish
- Once all previous steps are done, you are ready to publish your library.
In Android Studio open the Gradle View on the right side. Under Tasks > upload click on uploadArchives. This will upload your library to the Sonatype Staging Repositories .
- In the Sonatype Staging Repositories page, login with your Sonatype account.
- Look for your staging library at the end of the list, select it and click Close button. Closing a library actually means that you’re ready to release it.
- Closing errors might occur (I had signed key / authentication problems when closing my published library), fix them and click Release button.
- If this is the first library that you are publishing then get back to JIRA and post a comment there that you promoted your library. After that you should get a response from Sonatype that your library will be available in about ten minutes and it will be synced with the Maven Central in the next few hours.
That’s all programmers ! I am looking forward to your comments with links for your own libraries ! Never think twice to contribute and leave a trace . And feel free to leave your questions if you have any in comments.
Recent Comments