Distribute your libraries via Maven, even privately

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!

5f57d2d205e77e185986459c1b89a874?s=128

Jeroen Mols

April 07, 2016
Tweet

Transcript

  1. MAVEN LIBRARY DISTRIBUTION @MOLSJEROEN

  2. @MOLSJEROEN @MOLSJEROEN

  3. BEFORE SOFTWARE CAN BE REUSABLE IT FIRST HAS TO BE

    USABLE. Ralph Johnson
  4. @MOLSJEROEN GOAL dependencies {
 … compile ‘com.jeroenmols:landscapevideocamera:1.1.4'
 }

  5. MAVEN FUNDAMENTALS

  6. @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
  7. @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
  8. @MOLSJEROEN HOW MAVEN STORES DEPENDENCIES

  9. @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’ }
  10. @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’ }
  11. @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'
 }
  12. @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'
 }
  13. @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'
 }
  14. @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
  15. @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
  16. PUBLIC DISTRIBUTION

  17. THERE IS AN EASY WAY AND A HARD WAY. THE

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

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

    ‣ Browse repository repositories {
 mavenCentral()
 } ‣ Sonatype ‣ Browse repository
  20. @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
  21. @MOLSJEROEN

  22. @MOLSJEROEN

  23. @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 = 'jmolsmobile@gmail.com'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  24. @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 = 'jmolsmobile@gmail.com'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  25. @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 = 'jmolsmobile@gmail.com'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  26. @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 = 'jmolsmobile@gmail.com'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  27. @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 = 'jmolsmobile@gmail.com'
 } apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'
 apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'
  28. @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'
 }
 }
  29. @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'
 }
 }
  30. @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'
 }
 }
  31. @MOLSJEROEN BINTRAY - UPLOAD ARTIFACTS 3 ‣ $ ./gradlew assembleRelease

    bintrayUpload
  32. @MOLSJEROEN

  33. @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
  34. @MOLSJEROEN JITPACK.IO - UPLOAD ARTIFACTS DO NOTHING

  35. @MOLSJEROEN

  36. @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'
 }
  37. @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'
 }
  38. @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'
 }
  39. @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'
 }
  40. @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‘
 }
  41. @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’
 }
  42. PRIVATE DISTRIBUTION

  43. I THINK, FUNDAMENTALLY, OPEN SOURCE DOES TEND TO BE MORE

    STABLE SOFTWARE. Linus Torvalds
  44. @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
  45. @MOLSJEROEN

  46. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 1 ‣ PROJECT_HOME/build.gradle buildscript {


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


    dependencies { classpath “org.jfrog.buildinfo: build-info-extractor-gradle:3.1.1"
 }
 }
  48. @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")
 } } }
  49. @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")
 } } }
  50. @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")
 } } }
  51. @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")
 } } }
  52. @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")
 } } }
  53. @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
 }
 } }
  54. @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
 }
 } }
  55. @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
 }
 } }
  56. @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
 }
 } }
  57. @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
  58. @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
 }
 } }
  59. @MOLSJEROEN ARTIFACTORY - UPLOAD ARTIFACTS 4 ▸ $ ./gradlew assembleRelease

    artifactoryPublish
  60. @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'
 }
  61. @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'
 }
  62. @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'
 }
  63. @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
  64. @MOLSJEROEN

  65. @MOLSJEROEN

  66. @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>
  67. @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>
  68. @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>
  69. @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>
  70. @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
  71. @MOLSJEROEN PUBLISH-BITBUCKET SCRIPT ▸ Dramatically simplifies configuration ▸ Check for

    existing artifacts ▸ Bitbucket authentication ▸ Source: https://github.com/JeroenMols/GitAsMaven/blob/master/publish- bitbucket.gradle
  72. @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
 } }
  73. @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
 } }
  74. @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
 } }
  75. @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
 } }
  76. @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
 } }
  77. @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
 } }
  78. @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
 } }
  79. @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
 } }
  80. @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>"
 }
  81. @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>"
 }
  82. @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>"
 }
  83. @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>"
 }
  84. WRAP UP

  85. @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
  86. @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
  87. @MOLSJEROEN GITHUB SAMPLES ▸ Bintray example @attwellbrian ▸ Artifactory example

    @molsjeroen ▸ Wagon-git example @molsjeroen
  88. @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
  89. @MOLSJEROEN MANY THANKS ▸ Jeroen Mols (Belgium) ▸ @MolsJeroen ▸

    http://jeroenmols.com/blog
  90. @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