Publishing Android Library Artifacts to Amazon S3 Buckets

I’ve been playing around with JitPack as a quick solution for hosting public and private repositories with decent success. I say decent because on a few occasions it’s failed to build for a private GitHub repository and I was left stranded without any quick solutions for a fallback that I was comfortable with.

So I set out on a search for something better, something I had more control over, something so that when problems arise I need only look in the mirror to place the blame. I’ve used Sonatype Nexus and JFrog’s Artifactory before, but my requirements don’t really necessitate a full blown repository manager with all the bells and whistles that I’m now on the hook to manage. I just need a place to store some private artifacts (in the cloud) for smallish projects that have the lifespan of a mouse. If they live longer than 2 years, you know what, I’ll cross that bridge if I get there.

I stumbled on a few posts that mentioned publishing to an Amazon S3 bucket and a light bulb clicked on. I’ve used the MavenLocal task from the maven-publish plugin for some quick and dirty iterations and this S3 route started feeling like some fabled yellow brick road.

Without further ado, let’s get cracking!


Creating an Amazon User and S3 Bucket

First up it’s recommended you create a different user to access the S3 bucket so there’s limited exposure in case something goes wrong. Head on over to the IAM console and create a new user.

Enable Programmatic Access
Grant full access to S3

Review the information and proceed.

Before going further you need to read this.

The next screen is going to show you your Access Key and Secret Access Key. We need these for all future steps so save them off somewhere nice and safe and close the screen.

Now let’s setup an Amazon S3 bucket. Head on over to your Amazon S3 console and create a bucket.

The name needs to be unique
The defaults LGTM
Create bucket!

Congratulations! Your bucket is all setup and ready to serve up some dependencies.


Gradle Time

Add this code to the build.gradle file for the module you’re going to publish.

Run the publish task and you should see a bunch of lines where files are being uploaded to your S3 bucket. This is truncated snippet.

./gradlew library:publish

...
Upload s3://my.maven.repo.s3.amazonaws.com/com/sample/library/1.0/library-1.0.pom
Upload s3://my.maven.repo.s3.amazonaws.com/com/sample/library/1.0/library-1.0.pom.sha1
Upload s3://my.maven.repo.s3.amazonaws.com/com/sample/library/1.0/library-1.0.pom.md5
Upload s3://my.maven.repo.s3.amazonaws.com/com/sample/library/1.0/library-1.0-source.jar
Upload s3://my.maven.repo.s3.amazonaws.com/com/sample/library/1.0/library-1.0-source.jar.sha1
Upload s3://my.maven.repo.s3.amazonaws.com/com/sample/library/1.0/library-1.0-source.jar.md5
Upload s3://my.maven.repo.s3.amazonaws.com/com/sample/library/1.0/library-1.0-release.aar
...

BUILD SUCCESSFUL in 5s

Using Your New Dependency

At this point it’s time to use the uploaded dependency in some other project.

Root build.gradle

allprojects {
repositories {
google()
jcenter()
maven {
url "s3://MY-BUCKET-NAME.s3.amazonaws.com"
credentials(AwsCredentials) {
accessKey "MY-ACCESS-KEY"
secretKey "MY-SECRET-KEY"
}
}
}
}

Submodule build.gradle

dependencies {
compile group: 'com.sample.library', name: 'library', version: '1.0', ext: 'aar', classifier: 'debug'
}

Sync your project either via the IDE or command line and you’re now able to use S3 as an artifact repository.

Concluding Remarks

There’s a couple of things I want to say before ending this:

  • This example shows publishing and resolving dependencies using classifiers (e.g. debug, release). If you don’t need or want this, change it…
  • Access keys are embedded in the build.gradle file. I shouldn’t have to say this, but you probably shouldn’t do this. Instead source them from either environment variables or a gradle.properties file that you don’t check in.
  • If you want to change the artifact name (artifactId) it’s just another parameter. This setup assumes the submodule and artifact name is library .
  • If you want to package a proguard-rules.pro file check out this link

This isn’t a production grade solution that’s going to send a rocket to Mars, so be conscious of what you are, or aren’t, putting into your codebase.