$30 off During Our Annual Pro Sale. View Details »

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!

Jeroen Mols

April 07, 2016
Tweet

More Decks by Jeroen Mols

Other Decks in Programming

Transcript

  1. MAVEN LIBRARY
    DISTRIBUTION
    @MOLSJEROEN

    View Slide

  2. @MOLSJEROEN
    @MOLSJEROEN

    View Slide

  3. BEFORE SOFTWARE CAN BE REUSABLE
    IT FIRST HAS TO BE USABLE.
    Ralph Johnson

    View Slide

  4. @MOLSJEROEN
    GOAL
    dependencies {


    compile ‘com.jeroenmols:landscapevideocamera:1.1.4'

    }

    View Slide

  5. MAVEN FUNDAMENTALS

    View Slide

  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

    View Slide

  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

    View Slide

  8. @MOLSJEROEN
    HOW MAVEN STORES DEPENDENCIES

    View Slide

  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’
    }

    View Slide

  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’
    }

    View Slide

  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'

    }

    View Slide

  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'

    }

    View Slide

  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'

    }

    View Slide

  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

    View Slide

  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

    View Slide

  16. PUBLIC DISTRIBUTION

    View Slide

  17. THERE IS AN EASY WAY AND A HARD
    WAY. THE HARD PART IS FINDING THE
    EASY WAY.
    Dr. Lloyd

    View Slide

  18. @MOLSJEROEN
    PUBLIC MAVEN REPOSITORIES
    repositories {

    jcenter()

    }
    ‣ Bintray
    ‣ Browse repository
    repositories {

    mavenCentral()

    }
    ‣ Sonatype
    ‣ Browse repository

    View Slide

  19. @MOLSJEROEN
    PUBLIC MAVEN REPOSITORIES
    repositories {

    jcenter()

    }
    ‣ Bintray
    ‣ Browse repository
    repositories {

    mavenCentral()

    }
    ‣ Sonatype
    ‣ Browse repository

    View Slide

  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

    View Slide

  21. @MOLSJEROEN

    View Slide

  22. @MOLSJEROEN

    View Slide

  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 = '[email protected]'

    }
    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'

    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'

    View Slide

  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 = '[email protected]'

    }
    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'

    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'

    View Slide

  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 = '[email protected]'

    }
    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'

    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'

    View Slide

  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 = '[email protected]'

    }
    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'

    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'

    View Slide

  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 = '[email protected]'

    }
    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/installv1.gradle'

    apply from: 'https://raw.githubusercontent.com/attwellBrian/JCenter/master/bintrayv1.gradle'

    View Slide

  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'

    }

    }

    View Slide

  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'

    }

    }

    View Slide

  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'

    }

    }

    View Slide

  31. @MOLSJEROEN
    BINTRAY - UPLOAD ARTIFACTS 3
    ‣ $ ./gradlew assembleRelease bintrayUpload

    View Slide

  32. @MOLSJEROEN

    View Slide

  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

    View Slide

  34. @MOLSJEROEN
    JITPACK.IO - UPLOAD ARTIFACTS
    DO NOTHING

    View Slide

  35. @MOLSJEROEN

    View Slide

  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'

    }

    View Slide

  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'

    }

    View Slide

  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'

    }

    View Slide

  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'

    }

    View Slide

  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‘

    }

    View Slide

  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’

    }

    View Slide

  42. PRIVATE DISTRIBUTION

    View Slide

  43. I THINK, FUNDAMENTALLY, OPEN
    SOURCE DOES TEND TO BE MORE
    STABLE SOFTWARE.
    Linus Torvalds

    View Slide

  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

    View Slide

  45. @MOLSJEROEN

    View Slide

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

    dependencies {
    classpath “org.jfrog.buildinfo:
    build-info-extractor-gradle:3.1.1"

    }

    }

    View Slide

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

    dependencies {
    classpath “org.jfrog.buildinfo:
    build-info-extractor-gradle:3.1.1"

    }

    }

    View Slide

  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")

    } } }

    View Slide

  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")

    } } }

    View Slide

  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")

    } } }

    View Slide

  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")

    } } }

    View Slide

  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")

    } } }

    View Slide

  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

    }

    } }

    View Slide

  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

    }

    } }

    View Slide

  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

    }

    } }

    View Slide

  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

    }

    } }

    View Slide

  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

    View Slide

  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

    }

    } }

    View Slide

  59. @MOLSJEROEN
    ARTIFACTORY - UPLOAD ARTIFACTS 4
    ▸ $ ./gradlew assembleRelease artifactoryPublish

    View Slide

  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'

    }

    View Slide

  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'

    }

    View Slide

  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'

    }

    View Slide

  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

    View Slide

  64. @MOLSJEROEN

    View Slide

  65. @MOLSJEROEN

    View Slide

  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=

    PASSWORD=

    View Slide

  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=

    PASSWORD=

    View Slide

  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=

    PASSWORD=

    View Slide

  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=

    PASSWORD=

    View Slide

  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

    View Slide

  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

    View Slide

  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

    } }

    View Slide

  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

    } }

    View Slide

  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

    } }

    View Slide

  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

    } }

    View Slide

  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

    } }

    View Slide

  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

    } }

    View Slide

  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

    } }

    View Slide

  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

    } }

    View Slide

  80. @MOLSJEROEN
    CONSUME ARTIFACTS
    ‣ PROJECT_HOME/build.gradle
    allprojects {

    repositories {

    maven {

    credentials {

    username ''

    password ‘'

    }

    url "https://api.bitbucket.org/1.0/repositories/"
    + “//raw/releases"

    } } }
    ‣ MODULE_HOME/build.gradle
    dependencies {

    compile "com.jeroenmols:landscapevideocamera:"

    }

    View Slide

  81. @MOLSJEROEN
    CONSUME ARTIFACTS
    ‣ PROJECT_HOME/build.gradle
    allprojects {

    repositories {

    maven {

    credentials {

    username ''

    password ‘'

    }

    url "https://api.bitbucket.org/1.0/repositories/"
    + “//raw/releases"

    } } }
    ‣ MODULE_HOME/build.gradle
    dependencies {

    compile “com.jeroenmols:landscapevideocamera:"

    }

    View Slide

  82. @MOLSJEROEN
    CONSUME ARTIFACTS
    ‣ PROJECT_HOME/build.gradle
    allprojects {

    repositories {

    maven {

    credentials {

    username ''

    password ‘'

    }

    url "https://api.bitbucket.org/1.0/repositories/"
    + “//raw/releases"

    } } }
    ‣ MODULE_HOME/build.gradle
    dependencies {

    compile “com.jeroenmols:landscapevideocamera:"

    }

    View Slide

  83. @MOLSJEROEN
    CONSUME ARTIFACTS
    ‣ PROJECT_HOME/build.gradle
    allprojects {

    repositories {

    maven {

    credentials {

    username ''

    password ‘'

    }

    url "https://api.bitbucket.org/1.0/repositories/"
    + “//raw/releases"

    } } }
    ‣ MODULE_HOME/build.gradle
    dependencies {

    compile "com.jeroenmols:landscapevideocamera:"

    }

    View Slide

  84. WRAP UP

    View Slide

  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

    View Slide

  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

    View Slide

  87. @MOLSJEROEN
    GITHUB SAMPLES
    ▸ Bintray example @attwellbrian
    ▸ Artifactory example @molsjeroen
    ▸ Wagon-git example @molsjeroen

    View Slide

  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

    View Slide

  89. @MOLSJEROEN
    MANY THANKS
    ▸ Jeroen Mols (Belgium)
    ▸ @MolsJeroen
    ▸ http://jeroenmols.com/blog

    View Slide

  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

    View Slide