Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Distribute your libraries via Maven, even priva...

Distribute your libraries via Maven, even privately

Slides from my talk at Droidcon Italy and Big Android BBQ Amsterdam 2016
video: not recorded

In order to remain cost effective reusing code is one of the most essentials skills of a modern Android developer. Using open source libraries is one thing, but what if there isn't a library available that suits your need? How would you go about to develop and distribute this library yourself?

This talk aims at providing a complete solution for library distribution, either within your own organisation or with the entire open source community. You will learn how to setup your own private Maven repository, configure an account for Maven Central or JCenter and that even BitBucket/Github can be used as a Maven repository! Fully functional Gradle scripts will be provided for each alternative, taking important aspects like security and nested dependencies into account.

After this talk, there will be no more excuse to ramp up your game and start reusing your own code!

Jeroen Mols

April 07, 2016
Tweet

More Decks by Jeroen Mols

Other Decks in Programming

Transcript

  1. @MOLSJEROEN WHAT IS MAVEN …a build automation tool used primarily

    for Java projects. 1. Describes how software is built ▸ Build system (like Ant) 2. Reuse/version dependencies ▸ Adopted by Gradle
  2. @MOLSJEROEN HOW MAVEN HANDLES DEPENDENCIES ▸ Release identified by ▸

    GroupId com.jeroenmols ▸ ArtifactId landscapevideocamera ▸ Version 1.1.4 ▸ Multiple artifacts possible ▸ Library landscapevideocamera.aar ▸ Documentation javadoc.jar ▸ Sources sources.jar
  3. @MOLSJEROEN DEPENDENCY MANAGEMENT ADOPTED BY ANDROID/GRADLE ▸ Define Maven repositories

    ▸ Local Maven repository in SDK ▸ Dependency configurations dependencies { compile ‘com.jeroenmols:landscapevideocamera:1.1.4’
 testCompile ‘org.mockito:mockito-core:2.0.54-beta’ androidTestCompile ‘com.android.support.test:runner:0.4’ }
  4. @MOLSJEROEN DEPENDENCY MANAGEMENT ADOPTED BY ANDROID/GRADLE ▸ Define Maven repositories

    ▸ Local Maven repository in SDK ▸ Dependency configurations dependencies { compile ‘com.jeroenmols:landscapevideocamera:1.1.4’
 testCompile ‘org.mockito:mockito-core:2.0.54-beta’ androidTestCompile ‘com.android.support.test:runner:0.4’ }
  5. @MOLSJEROEN GRADLE - USE MAVEN ARTIFACTS allprojects {
 repositories {


    jcenter()
 maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jeroenmols:landscapevideocamera:1.1.4'
 }
  6. @MOLSJEROEN GRADLE - USE MAVEN ARTIFACTS allprojects {
 repositories {


    jcenter()
 maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jeroenmols:landscapevideocamera:1.1.4'
 }
  7. @MOLSJEROEN GRADLE - USE MAVEN ARTIFACTS allprojects {
 repositories {


    jcenter()
 maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jeroenmols:landscapevideocamera:1.1.4'
 }
  8. @MOLSJEROEN GRADLE - USE MAVEN ARTIFACTS allprojects {
 repositories {


    jcenter()
 maven { url “http://mywebsite.com/mavenrepository" }
 }
 } dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile ‘com.android.support:appcompat-v7:23.1.0’ 
 compile ‘com.jeroenmols:landscapevideocamera:1.1.4’
 } GroupId ArtifactId Version
  9. @MOLSJEROEN IMPLICIT ASSUMPTIONS USING MAVEN 1. Repository reachable and online

    forever 2. Existing artifacts never modified 3. New versions come from same developer ▸ Code must always build immediately after checkout ▸ When doubt: add artifacts to version control
  10. THERE IS AN EASY WAY AND A HARD WAY. THE

    HARD PART IS FINDING THE EASY WAY. Dr. Lloyd
  11. @MOLSJEROEN PUBLIC MAVEN REPOSITORIES repositories {
 jcenter()
 } ‣ Bintray

    ‣ Browse repository repositories {
 mavenCentral()
 } ‣ Sonatype ‣ Browse repository
  12. @MOLSJEROEN PUBLIC MAVEN REPOSITORIES repositories {
 jcenter()
 } ‣ Bintray

    ‣ Browse repository repositories {
 mavenCentral()
 } ‣ Sonatype ‣ Browse repository
  13. @MOLSJEROEN 1. PUBLIC DISTRIBUTION - BINTRAY ▸ Attractive UI ▸

    Simple to use (no signing) ▸ Integrates with Github, Bitbucket, Twitter,… ▸ Download statistics ▸ Gradle/manual upload to staging ▸ Manually release to JCenter ▸ One click/automated sync to Maven Central
  14. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ LIBRARY_HOME/build.gradle ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = ‘LandscapeVideoCamera’ libraryVersion = ‘1.1.4' 
 artifact = ‘library' 
 libraryDescription = 'Powerful custom Android Camera.’
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = '[email protected]'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  15. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ LIBRARY_HOME/build.gradle ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera' libraryVersion = ‘1.1.4’ artifact = 'library' 
 libraryDescription = 'Powerful custom Android Camera.’ 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = '[email protected]'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  16. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ LIBRARY_HOME/build.gradle ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera' libraryVersion = ‘1.1.4’ artifact = 'library' 
 libraryDescription = 'Powerful custom Android Camera.’ 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = '[email protected]'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  17. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ LIBRARY_HOME/build.gradle ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = ‘LandscapeVideoCamera' libraryVersion = '1.1.4'
 
 artifact = 'library' 
 libraryDescription = 'Powerful custom Android Camera.’ 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = '[email protected]'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  18. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 1 ‣ LIBRARY_HOME/build.gradle ext {


    bintrayRepo = 'maven'
 bintrayName = 'LandscapeVideoCamera'
 
 publishedGroupId = 'com.github.jeroenmols'
 libraryName = 'LandscapeVideoCamera' libraryVersion = ‘1.1.4’ artifact = ‘library' 
 libraryDescription = 'Powerful custom Android Camera.’ 
 developerId = 'JeroenMols'
 developerName = 'Jeroen Mols'
 developerEmail = '[email protected]'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  19. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties bintray.user=jeroenmols
 bintray.apikey=n1c3try

    ‣ PROJECT_HOME/build.gradle buildscript {
 dependencies {
 classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
 classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
 }
 }
  20. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties bintray.user=jeroenmols
 bintray.apikey=n1c3try

    ‣ PROJECT_HOME/build.gradle buildscript {
 dependencies {
 classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
 classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
 }
 }
  21. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 2 ‣ PROJECT_HOME/local.properties bintray.user=jeroenmols
 bintray.apikey=n1c3try

    ‣ PROJECT_HOME/build.gradle buildscript {
 dependencies {
 classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6'
 classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
 }
 }
  22. @MOLSJEROEN 2. PUBLIC DISTRIBUTION - JITPACK.IO ▸ Zero configuration ▸

    Download statistics, API, Badges,… ▸ Snapshot support ▸ No need to upload artifacts ▸ Builds any GitHub project (and more) ▸ Git tag to create a ‘formal’ release (optional) ▸ Add Jitpack repository
  23. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile 'com.github.JeroenMols:LandscapeVideoCamera:1.1.4'
 }
  24. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile 'com.github.JeroenMols:LandscapeVideoCamera:1.1.4'
 }
  25. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile 'com.github.JeroenMols:LandscapeVideoCamera:1.1.4'
 }
  26. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile ‘com.github.JeroenMols:LandscapeVideoCamera: 3f900ec00b302f75f3d377cff0bdca37145fc89d'
 }
  27. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile ‘com.github.JeroenMols:LandscapeVideoCamera: develop-SNAPSHOT‘
 }
  28. @MOLSJEROEN JITPACK.IO - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 jcenter()
 maven { url "https://jitpack.io" }
 } } ‣ MODULE_HOME/build.gradle dependencies {
 compile ‘com.jeroenmols:LandscapeVideoCamera:1.1.4’
 }
  29. @MOLSJEROEN ▸ Easy to set up Maven repository ▸ Cache

    remote repository artifacts ▸ Open source (free) ▸ Gradle plugin to do the upload ▸ Advanced features ▸ Backups? ▸ Cost/hassle of running a server? 1. PRIVATE DISTRIBUTION - ARTIFACTORY RELATED BLOGPOSTS
  30. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/build.gradle buildscript {


    dependencies { classpath “org.jfrog.buildinfo: build-info-extractor-gradle:3.1.1"
 }
 }
  31. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/build.gradle buildscript {


    dependencies { classpath “org.jfrog.buildinfo: build-info-extractor-gradle:3.1.1"
 }
 }
  32. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ LIBRARY_HOME/build.gradle apply plugin:

    'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  33. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ LIBRARY_HOME/build.gradle apply plugin:

    'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  34. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ LIBRARY_HOME/build.gradle apply plugin:

    'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  35. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ LIBRARY_HOME/build.gradle apply plugin:

    'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  36. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 2 ‣ LIBRARY_HOME/build.gradle apply plugin:

    'maven-publish' def packageName = 'com.jeroenmols.awesomelibrary'
 def libraryVersion = '1.0.0' publishing {
 publications {
 aar(MavenPublication) {
 groupId = packageName
 version = libraryVersion
 artifactId = project.getName()
 artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
 } } }
  37. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ LIBRARY_HOME/build.gradle apply plugin:

    ‘com.jfrog.artifactory' artifactory {
 contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  38. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ LIBRARY_HOME/build.gradle apply plugin:

    ‘com.jfrog.artifactory' artifactory {
 contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  39. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ LIBRARY_HOME/build.gradle apply plugin:

    ‘com.jfrog.artifactory' artifactory {
 contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  40. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ LIBRARY_HOME/build.gradle apply plugin:

    ‘com.jfrog.artifactory' artifactory {
 contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  41. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ LIBRARY_HOME/build.gradle apply plugin:

    ‘com.jfrog.artifactory' artifactory {
 contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } } to gradle.properties
  42. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 3 ‣ LIBRARY_HOME/build.gradle apply plugin:

    ‘com.jfrog.artifactory' artifactory {
 contextUrl = 'http://localhost:8081/artifactory'
 publish {
 repository {
 repoKey = 'libs-release-local'
 username = "admin"
 password = "password"
 }
 defaults {
 publications('aar')
 publishArtifacts = true
 publishPom = true
 }
 } }
  43. @MOLSJEROEN ARTIFACTORY - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 maven { url “http://localhost:8081/artifactory/libs-release-local" } } } ‣ PROJECT_HOME/build.gradle dependencies {
 compile 'com.jeroenmols.awesomelibrary:1.0.0'
 }
  44. @MOLSJEROEN ARTIFACTORY - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 maven { url “http://localhost:8081/artifactory/libs-release-local" } } } ‣ PROJECT_HOME/build.gradle dependencies {
 compile 'com.jeroenmols.awesomelibrary:1.0.0'
 }
  45. @MOLSJEROEN ARTIFACTORY - CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories

    {
 maven { url “http://localhost:8081/artifactory/libs-release-local" } } } ‣ PROJECT_HOME/build.gradle dependencies {
 compile 'com.jeroenmols.awesomelibrary:1.0.0'
 }
  46. @MOLSJEROEN 2. PRIVATE DISTRIBUTION - WAGON-GIT ▸ Git as a

    Maven repository ▸ Supports GitHub and BitBucket (public or private) ▸ Open source (free) ▸ Maven plugin to do the upload ▸ Inherent backups and remote access RELATED BLOGPOST
  47. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ LIBRARY_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository ▸ PROJECT_HOME/gradle.properties USERNAME=<username_here>
 PASSWORD=<password_here>
  48. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ LIBRARY_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository ▸ PROJECT_HOME/gradle.properties USERNAME=<username_here>
 PASSWORD=<password_here>
  49. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ LIBRARY_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository ▸ PROJECT_HOME/gradle.properties USERNAME=<username_here>
 PASSWORD=<password_here>
  50. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 1 ▸ LIBRARY_HOME/gradle.properties ARTIFACT_VERSION=1.0.0
 ARTIFACT_NAME=landscapevideocamera


    ARTIFACT_PACKAGE=com.jeroenmols.landscapevideocamera ARTIFACT_PACKAGING=aar
 
 BITBUCKET_TEAM=jmolsmobile
 REPOSITORY_NAME=maven_repository ▸ PROJECT_HOME/gradle.properties USERNAME=<username_here>
 PASSWORD=<password_here>
  51. @MOLSJEROEN WAGON-GIT - UPLOAD ARTIFACTS 2 ▸ LIBRARY_HOME/build.gradle apply from:

    'https://raw.githubusercontent.com/JeroenMols/ GitAsMaven/master/publish-bitbucket.gradle' ▸ $ gradle assembleRelease uploadArchives
  52. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT ▸ Dramatically simplifies configuration ▸ Check for

    existing artifacts ▸ Bitbucket authentication ▸ Source: https://github.com/JeroenMols/GitAsMaven/blob/master/publish- bitbucket.gradle
  53. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 1 uploadArchives.dependsOn lookForArtifacts task

    lookForArtifacts {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  54. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 1 uploadArchives.dependsOn lookForArtifacts task

    lookForArtifacts {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  55. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 1 uploadArchives.dependsOn lookForArtifacts task

    lookForArtifacts {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  56. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 1 uploadArchives.dependsOn lookForArtifacts task

    lookForArtifacts {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  57. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 1 uploadArchives.dependsOn lookForArtifacts task

    lookForArtifacts {
 doLast {
 def libraryName = ARTIFACT_NAME + '-' + ARTIFACT_VERSION + '.aar'
 def repoPath = ARTIFACT_PACKAGE.replace(".", "/") + "/" + ARTIFACT_NAME + "/" + ARTIFACT_VERSION + "/" + libraryName
 def repositoryUrl = 'https://api.bitbucket.org/1.0/repositories/' + COMPANY + '/' + REPOSITORY_NAME + '/raw/releases/' + repoPath
 if (urlExists(repositoryUrl)) {
 throw new RuntimeException(“Artifact exists:" + ARTIFACT_VERSION)
 }
 return true
 } }
  58. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 2 def urlExists(String repositoryUrl)

    {
 try {
 def conn = (HttpURLConnection) new URL(repositoryUrl).openConnection()
 
 conn.setRequestProperty("Authorization","Basic " + getBase64EncodedCredentials())
 conn.setConnectTimeout(10000)
 conn.setReadTimeout(10000)
 conn.setRequestMethod("HEAD")
 
 def responseCode = connection.getResponseCode()
 println("responseCode: " + responseCode)
 
 return (200 == responseCode) 
 } catch (IOException ignored) {
 return false
 } }
  59. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 2 def urlExists(String repositoryUrl)

    {
 try {
 def conn = (HttpURLConnection) new URL(repositoryUrl).openConnection()
 
 conn.setRequestProperty("Authorization","Basic " + getBase64EncodedCredentials())
 conn.setConnectTimeout(10000)
 conn.setReadTimeout(10000)
 conn.setRequestMethod("HEAD")
 
 def responseCode = connection.getResponseCode()
 println("responseCode: " + responseCode)
 
 return (200 == responseCode) 
 } catch (IOException ignored) {
 return false
 } }
  60. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT - EXISTING ARTIFACTS 2 def urlExists(String repositoryUrl)

    {
 try {
 def conn = (HttpURLConnection) new URL(repositoryUrl).openConnection()
 
 conn.setRequestProperty("Authorization","Basic " + getBase64EncodedCredentials())
 conn.setConnectTimeout(10000)
 conn.setReadTimeout(10000)
 conn.setRequestMethod("HEAD")
 
 def responseCode = connection.getResponseCode()
 println("responseCode: " + responseCode)
 
 return (200 == responseCode) 
 } catch (IOException ignored) {
 return false
 } }
  61. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile "com.jeroenmols:landscapevideocamera:<version>"
 }
  62. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile “com.jeroenmols:landscapevideocamera:<version>"
 }
  63. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile “com.jeroenmols:landscapevideocamera:<version>"
 }
  64. @MOLSJEROEN CONSUME ARTIFACTS ‣ PROJECT_HOME/build.gradle allprojects {
 repositories {
 maven

    {
 credentials {
 username '<bitbucket_username>'
 password ‘<bitbucket_password>'
 }
 url "https://api.bitbucket.org/1.0/repositories/" + “<bitbucket_team>/<repository>/raw/releases"
 } } } ‣ MODULE_HOME/build.gradle dependencies {
 compile "com.jeroenmols:landscapevideocamera:<version>"
 }
  65. @MOLSJEROEN CONCLUSION ▸ Use Gradle to simplify Maven uploads ▸

    Public distribution ▸ Use Jitpack initially ▸ Scale to Bintray once usage grows ▸ Private distirbution ▸ Use Artifactory when possible ($$$, infrastructure,…) ▸ Fallback to Git for limited usage
  66. @MOLSJEROEN CREDITS ▸ Distributing Android Libraries via jCenter for Gradle

    Importing @attwellbrian ▸ A private Maven repository in 30 min @molsjeroen ▸ Getting the most out of Artifactory @molsjeroen ▸ Git as a secure private Maven repository @molsjeroen
  67. @MOLSJEROEN IMAGE CREDITS ▸ Philips Hue living room
 http://www.philips.de ▸

    Pouring concrete
 http://www.precisionpouredconcrete.com/images/concrete-being-poured.jpg ▸ Flying drones
 https://s3.amazonaws.com/digitaltrends-uploads-prod/2014/12/Drones-packages.jpg ▸ Pneumatic tubes
 https://41.media.tumblr.com/107ae958bff7ce2261c55e7a4de8f79e/tumblr_nlt2wfG8gr1t3cxt2o1_500.jpg ▸ Judge hammer
 http://www.quickhr.biz/wp-content/uploads/2015/03/Judges-hammer.jpg
  68. @MOLSJEROEN OTHER INTERESTING ARTICLES ▸ Gradle dependency and local repository

    @turhanoz ▸ Creating and publishing an Android library @Etienne_Lawlor ▸ Publish with Gradle on BitBucket @mul0w ▸ Gradle Maven Push script @chrisbanes