One day I said: enough. This was the day when I tried to copy my MVP code, yet again, to another project. On that day I thought, “how about applying the best practices to this MVP code, like reusability?”. And then my library journey began. It involved, and still does, building artifacts, releasing and uploading repositories, and all that jazz.
If you’re thinking about releasing a library to the public, this article is for you. Here, I will describe my attempts to prepare and share code with the public successfully. As a kind of foreword: It will be about the Android library, with the Gradle build system. The target release audience will be both private via VSTS (Visual Studio Team Services) and public via jcenter and Bintray.
This Android library, the leading star of this article, is the result of my effort to improve the quality of my code and my work by eliminating repetition. This is a Kotlin-powered MVP pattern, responsible for structuring the activities and fragments in your app (the basic components, for those non-android folks out there). To read about the MVP itself, I suggest this article. But enough about the library, let’s get to the real content of this article.
Picking the release target. Vol. 1: Private
Well, this private release thing came about by accident. I was asking around for some method to publish my library. So someone suggested VSTS as a way to release it. So I went there, had no idea what to do, then stumbled onto this neat aid. It explained some things, like that I needed to create a feed (also called a repository). The feed is a collection of packages. The package, on the other hand, is a collection of versions. While version is a collection of… erm, seems fairly simple, right? Let’s complement this with an example from KotlinMVP.
Feed is kinda less visible on the client’s side. It is called SHMaven. So my KotlinMVP is located in SHMaven.
The package is KotlinMVP. So SHMaven has several packages, one of them being KotlinMVP.
And finally, the KotlinMVP package has several versions, like
SHMaven -> KotlinMVP ->
While digging more into the VSTS and that guide, I noticed the private key.
So I realised that this is only for people who provide such a key, along with the proper URL. Not so convenient, but in the end, I kept this configuration on a separate branch just as a way to get a private version, not released to the public.
Proceeding to config
The very first thing I did was creating the above feed. Package and version will be provided by the actual publish.
So far so good. In this neat aid, I’ve copied the gradle code and pasted it into my project, just as suggested. Later, I rearranged what needed rearranging and filled out the blanks with my data, so for example, the publication information was like this:
So it becomes clear right now. The `groupId` is, most preferably, your company address (java-package-esque), while the `artifactId` is your library name, and `version` is, erm, version name 😊 . Here we also point to the location of the release’s aar (which is just a fancy java jar, with some additional stuff from Android added).
All the above makes up the most important thing from the client-side point of view: this line of code
And the target publishing information was
Then, all I needed was, seemingly, to invoke this little Gradle task called
publish just like this:
But it did not work. It is a good command. So why didn’t it work for me? Well, let’s get somewhat in-depth on the issue. A typical computer of an Android developer has two gradles in it: The global one and the project one, also known as the wrapper. The global one has to be configured to work as a global command in the Windows environment, and mine wasn’t. I ended up using `gradlew` , that is, the gradle wrapper.
Moreover, after I invoked that (it kinda, sort of, worked), I got yet another error. This time, it was a 404 from the service. I was baffled, checked everything twice or more.
After an extended period of searching and checking code I noticed, that the feed has the Connect to feed option.
As a result, I received some code to paste here and there:
And after that, I just ran this simple command:
And voila! Library published. Or is it? Problem solved, right? Apparently not. I had to combine the connect to feed code with the above code from that help source. Of course, in the meantime, Icommented out the help source code and put only the above. That didn’t work either.
As the 404 was coming from a URL, I figured out that only the URL was wrong, so I got the one from connect to feed. And it worked. Really!
gradlew publish in the SHMaven repository (the feed), the KotlinMVP package appeared with its version of
I imported it by adding this to the other project’s Gradle:
And it worked, my project read the dependency, and it was smooth and good and great. Well, I got a big fat NO. This was the beginning of even more trouble.
Publishing. Vol. 1: Private edition – dependency problems
As you can see, my project had this pretty little dependency
And dependencies in gradle/maven publishing do not go to the release’s aar package (the
mvp-release.aar jar). It would be a bad idea, really, to include all the binaries in your binary. But most importantly, the generated pom file (gradle generates maven’s pom file with release information in the process) did not have the information to download all the necessary dependencies, like
Turns out you have to provide that manually. Edit the artifact publishing info like this:
With this, the package (via pom file) will have the information to download the necessary dependencies.
That got the job done. The package was released as requested, and Gradle downloaded all dependencies.
The final config
And you need to declare in your
The client-side config
Moreover, you need to specify that token in the
Conclusion of vol. 1: Private publish
There are a few problems with the above, namely:
There is some kind of token requested, the privacy needs it.
It’s quite a lot of lines for a single dependency.
It is private, I can’t show it to the public in this state.
Now, it’s time for vol. 2.
Vol. 2: Public publish – jcenter and Bintray
This time, I had no help from the outside because no one I know has done this before.To register on jcenter, one needs to get an account on Bintray. The journey there is similar to the one on VSTS.
You need to create a repository (instead of feed), then a package, and finally a version. There are two options to do this: manually, via a website and via a plugin.
I tried to do it via a website. It was nice, up until uploading the files. There, I needed to modify my publishing code because Bintray requires a generated pom file.
So the pom file will be generated in a
repo folder. Having both aar and pom files, I proceeded to upload these to the website. The upload was successful, along with the publish. Well, only the publish operation was successful, the effect was not. My other project did not find the dependency.
Also, the dependency code changed:
The public release continues
After a long search, with many errors, I gave up on releasing the version manually and set up the official plugin. In the end, all I needed to do was to change the command to:
publish, and fill this with my info:
My publication, in this case, was the publishing code above in the
publications container. And that was it. Files were uploaded properly, I clicked the magical publish button, and the other project could then access the dependency through Maven. Time for the final step!
Releasing to jcenter
The jcenter needs one more thing: the source code jar artifact, so it complies to open-sourceness. To do this, I had to add this gradle task:
and change the
myPublication so it includes
artifact sourcesJar, and that was it. Now the jar was generated and put as an additional artifact into the release’s aar.
After all the above, all I needed was to link my newest release to the jcenter on the Bintray website. This can be done by clicking Maven Central. The request will be sent immediately. In about 30 or so minutes, it should be approved. Now users can access the library via
After a very long trial and error process, I was successful in my publishing efforts. Now I internally have two branches – one with private publish and private dependencies, and one with everything public. Just as I wanted.