Internal Library Dependency
Management
Kelly Shuster
Android Developer, iTriage
Internal Library
Dependency Management
@KellyShuster
@KellyShuster
@KellyShuster
1. Single Repository, Single Gradle Module
1. Single Repository, Single Gradle Module
2. Single Repository, Multiple Gradle Modules
1. Single Repository, Single Gradle Module
2. Single Repository, Multiple Gradle Modules
3. Multiple Repositories, Linked by Git
1. Single Repository, Single Gradle Module
2. Single Repository, Multiple Gradle Modules
3. Multiple Repositories, Linked by Git
4. Multiple Repositories, Linked by Maven
Single Repository,
Single Gradle Module
dependency-sample
app
Team Workflow
Single branch
Pull Request
Pros
Easy to understand
Everything in a central location
Straightforward to obtain code & debug
Cons
Library is not separate component
Can’t be shared w/ another team
Can’t be versioned independently
No explicit separation of concerns.
Single Repository,
Multiple Gradle Modules
dependency-sample
app mylibrary
settings.gradle
include ':app', ':mylibrary'
settings.gradle
include ':app', ':mylibrary'
build.gradle (app)
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile project(':mylibrary')
}
build.gradle (app)
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile project(':mylibrary')
}
Team Workflow
Single branch
Pull Request
Pros
Easy procedure; hard to mess up
Added some separation of concerns
Cons
Library is not separate component
Can’t be shared w/ another team
Can’t be versioned independently
Multiple Repositories,
Linked Using Git
Git Submodules
dependency-sample dependency-sample-lib
app mylibrary
How do you set it up?
git submodule add <lib-repo>
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
78c7046
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
[submodule "dependency-sample-library"]
path = dependency-sample-library
url = https://github.com/KioKrofovitch/dependency-sample-library.git
.gitmodules
Add Gradle References
settings.gradle
include ':app'
include ':dependency-sample-library:mylibrary'
settings.gradle
include ':app'
include ':dependency-sample-library:mylibrary'
build.gradle (app)
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':dependency-sample-library:mylibrary')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
}
build.gradle (app)
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':dependency-sample-library:mylibrary')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
}
Check Submodule Status
git submodule
78c7046
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
How do you get code?
git clone <repo> --recursive
git clone <repo>
git submodule init
git submodule update
git checkout <branch>
git submodule init
git submodule update
git checkout <branch>
git submodule init
git submodule update
Upstream changes
Changing the library
ff07597
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
ff07597
123ff09
fef9878
345f67e
Committing on a Detached Head
How it happens
1bd7125
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
1bd7125
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
177458f
1bd7125
123789d
a2b789d
345a89d
678789d
dependency-sample dependency-sample-lib
177458f
498defd
145458e
1bd7125
177458f
498defd
145458e
How to recover
Removing Submodules
.gitmodules
.git/modules
Team Workflow
Step 1 - Shell & Library
1. Create branch for shell
2. Create branch for library
3. Make and test shell & library changes
simultaneously
Step 2 - Library
1. Pull request / code review lib changes
2. Merge pull request
Step 3 - Shell
1. Update shell branch to point to latest
library master commit
2. Pull request / code review shell changes
3. Merge pull request
Pros
Clear separation of concerns
Pros
Clear separation of concerns
Library is in separate repo! Can be shared!
Pros
Clear separation of concerns
Library is in separate repo! Can be shared!
“Versioning” brought to you by git
Pros
Clear separation of concerns
Library is in separate repo! Can be shared!
“Versioning” brought to you by git
“Version” determined by shell
Pros
One Android Studio Project
Pros
One Android Studio Project
Easily step into code with debugger
Pros
One Android Studio Project
Easily step into code with debugger
Submodule maintains its own git history
Cons
Magic is involved
Cons
Magic is involved
Very easy to mess up, in multiple spots:
Cons
Magic is involved
Very easy to mess up, in multiple spots:
Working with a detached head
Pulling down latest submodule
Adding & tracking submodule reference
Cons
Multi-step PR & merge
Cons
Multi-step PR & merge
Library versions are commit SHAs
Multiple Repositories,
Linked Using Maven
Artifactory
dependency-sample dependency-sample-lib
app
Artifactory
mylibrary
dependency-sample dependency-sample-lib
app mylibrary
Artifactory
Reference
dependency-sample dependency-sample-lib
app
Artifactory
Publish
mylibrary
Artifactory Local Setup
Install Java 8
Download / unzip artifactory
Run bin/artifact.sh
http://localhost:8081/artifactory/webapp/#/home
Publishing
build.gradle (project level)
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1"
// NOTE: Do not place your application dependencies here; they
// belong in the individual module build.gradle files
}
}
build.gradle (project level)
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.0'
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1"
// NOTE: Do not place your application dependencies here; they
// belong in the individual module build.gradle files
}
}
build.gradle (mylibrary)
apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
def packageName = 'com.kiodev.myArtLibrary'
def versionMajor = '1'
def versionMinor = '0'
def versionPatch = '0'
def libraryVersion = "${versionMajor}.${versionMinor}.${versionPatch}"
android { … }
dependencies { … }
publishing { … }
artifactory { … }
build.gradle (mylibrary)
apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
def packageName = 'com.kiodev.myArtLibrary'
def versionMajor = '1'
def versionMinor = '0'
def versionPatch = '0'
def libraryVersion = "${versionMajor}.${versionMinor}.${versionPatch}"
android { … }
dependencies { … }
publishing { … }
artifactory { … }
build.gradle (mylibrary)
apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
def packageName = 'com.kiodev.myArtLibrary'
def versionMajor = '1'
def versionMinor = '0'
def versionPatch = '0'
def libraryVersion = "${versionMajor}.${versionMinor}.${versionPatch}"
android { … }
dependencies { … }
publishing { … }
artifactory { … }
build.gradle (mylibrary)
apply plugin: 'com.android.library'
apply plugin: 'com.jfrog.artifactory'
apply plugin: 'maven-publish'
def packageName = 'com.kiodev.myArtLibrary'
def versionMajor = '1'
def versionMinor = '0'
def versionPatch = '0'
def libraryVersion = "${versionMajor}.${versionMinor}.${versionPatch}"
android { … }
dependencies { … }
publishing { … }
artifactory { … }
build.gradle (mylibrary)
publishing {
publications {
aar(MavenPublication) {
groupId packageName
version = libraryVersion
artifactId project.getName()
// Tell maven to prepare the generated "*.aar" file for publishing
artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
}
}
}
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
publish {
repository {
...
}
defaults {
...
}
}
}
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
publish {
repository {
// The Artifactory repository key to publish to
repoKey = 'libs-release-local'
username = "admin"
password = "password"
}
defaults { … }
}
}
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
publish {
repository {
// The Artifactory repository key to publish to
repoKey = 'libs-release-local'
// More sophistication with gradle.properties
username = artifactory_user
password = artifactory_password
}
defaults { … }
}
}
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
publish {
repository { ... }
defaults {
// Tell the Artifactory Plugin which artifacts to publish
publications('aar')
publishArtifacts = true
// Properties to be attached to the published artifacts.
properties = ['qa.level': 'basic', 'dev.team': 'core']
// Publish generated POM files to Artifactory (true by default)
publishPom = true
}
}
}
gradle assemble artifactoryPublish
Referencing
build.gradle (project level)
allprojects {
repositories {
jcenter()
maven {
url "http://localhost:8081/artifactory/libs-release-local"
}
}
}
build.gradle (project level)
allprojects {
repositories {
jcenter()
maven {
url "http://localhost:8081/artifactory/libs-release-local"
}
}
}
build.gradle (project level)
allprojects {
repositories {
jcenter()
maven {
url "http://localhost:8081/artifactory/libs-release-local"
// More sophistication with gradle.properties
credentials {
username = artifactory_user
password = artifactory_password
}
}
}
}
build.gradle (app)
android {
…
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile(group: 'com.kiodev.myArtLibrary', name: 'mylibrary',
version: '1.0.0', ext: 'aar')
}
build.gradle (app)
android {
…
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile(group: 'com.kiodev.myArtLibrary', name: 'mylibrary',
version: '1.0.0', ext: 'aar')
}
gradle build --refresh-dependencies
Debugging
Sources Jar
Artifactory Sources Jar
Upload sources jar
Artifactory Sources Jar
Upload sources jar
Sources jar download isn’t automatic
Artifactory Sources Jar
Upload sources jar
Sources jar download isn’t automatic
Getting most up to date is confusing
Snapshot
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
publish {
repository {
// The Artifactory repository key to publish to
repoKey = 'libs-release-local'
// More sophistication with gradle.properties
username = artifactory_user
password = artifactory_password
}
defaults { … }
}
}
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
publish {
repository {
// The Artifactory repository key to publish to
repoKey = 'libs-release-local'
// More sophistication with gradle.properties
username = artifactory_user
password = artifactory_password
}
defaults { … }
}
}
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
def repoName = ""
if (project.version.endsWith('-SNAPSHOT')) {
repoName = 'libs-snapshot-local'
} else {
repoName = 'libs-release-local'
}
publish { ... }
}
build.gradle (mylibrary)
artifactory {
contextUrl = 'http://localhost:8081/artifactory'
def repoName = ""
if (project.version.endsWith('-SNAPSHOT')) {
repoName = 'libs-snapshot-local'
} else {
repoName = 'libs-release-local'
}
publish { ... }
}
Publishing Bandit
Github
Code changes
& commits
Github Github
Code changes
& commits
Pull request
& merge
Github Github Artifactory
Code changes
& commits
Pull request
& merge Publish
Github Artifactory
Code changes
& commits
Publish
Github Artifactory
Code changes
Publish
Team Workflow
Step 1 - Library
Create branch
Make & test library changes
Increase version in gradle file
Pull request / code review
Merge pull request
Publish library to artifactory
Step 2 - Shell
Create branch
Make & test shell changes
Increase version in gradle file
Pull request / code review
Merge pull request
Pros
Clear separation of concerns
Pros
Clear separation of concerns
Library is in sep repo! Can be shared!
Pros
Clear separation of concerns
Library is in sep repo! Can be shared!
Versioning is human readable / determined
Pros
Clear separation of concerns
Library is in sep repo! Can be shared!
Versioning is human readable / determined
Benefits of JAR / AAR
Cons
Versioning has zero tie to git!
Easy to lose track of what is where
Cons
Versioning has zero tie to git!
Easy to lose track of what is where
Low security
You can publish anything…
You can wipe out an old version
Cons
Sources jar is difficult to locate and use
Cons
Sources jar is difficult to locate and use
No guarantee your sources jar matches the
artifact you are referencing
Cons
Sources jar is difficult to locate and use
No guarantee your sources jar matches the
artifact you are referencing
Makes stepping through code hard
Your Team
Pick what works for your team
Size of team
Pick what works for your team
Size of team
Frequency of library changes
Pick what works for your team
Size of team
Frequency of library changes
Library reuse or sharing
Pick what works for your team
Size of team
Frequency of library changes
Library reuse or sharing
Importance of aar
Pick what works for your team
Size of team
Frequency of library changes
Library reuse or sharing
Importance of aar
Team knowledge of git
@KellyShuster
https://github.com/KioKrofovitch/
dependency-sample
dependency-sample-library
Resources
Git submodule
https://git-scm.com/docs/git-submodule
https://git-scm.com/book/en/v2/Git-Tools-Submodules
Artifactory Open Source
https://www.jfrog.com/open-source/
Artifactory Professional
https://www.jfrog.com/artifactory/
Artifactory OS Tutorial
https://jeroenmols.github.io/blog/2015/08/06/artifactory/
Photo Credits
Android Robot
https://commons.wikimedia.org/wiki/File:Android_robot.svg
Trinity College Library
https://en.wikipedia.org/wiki/Trinity_College,_Dublin#/media/File:Long_Room_Interior,
_Trinity_College_Dublin,_Ireland_-_Diliff.jpg
Ruby
http://nicholasjohnson.com/ruby/
Clean Desk
http://www.levo.com/articles/career-advice/what-your-desk-says-about-you
Messy Desk
http://www.telegraph.co.uk/news/newstopics/howaboutthat/10225664/Having-a-messy-desk-makes-you-more-
creative.html
Headless Horseman Gif
https://www.lovethisgif.com/tag/headless+horseman
Ghost
http://38.media.tumblr.com/d30fe069cc48e11eeb31ae08293a159e/tumblr_nbtdxg9d6n1szf0nzo1_250.gif
Photo Credits
Atreyu & Horse
http://5cities6women.com/2014/04/06/happy-30th-birthday-neverending-story/
Neverending Story Book
http://www.dailyrecord.co.uk/entertainment/tv-radio/flashback-friday-neverending-story-proves-4948514
Unicorn w/ Rainbows
http://souloftruth.com/the-race-to-nowhere/
Falcor & Atreyu
http://filmconnoisseur.blogspot.com/2010/08/never-ending-story-book-review.html
John Wayne
http://patch.com/california/sanclemente/best-ways-recycle-water-during-californias-dry-spell
Space Pic
http://wallpapershidef.com/outer-space-desktop-wallpaper.html
Computer
https://commons.wikimedia.org/wiki/File:Gnome-computer.svg

Android Internal Library Management