Android Internal Library Management

197
Internal Library Dependency Management Kelly Shuster Android Developer, iTriage

Transcript of Android Internal Library Management

Internal Library Dependency Management

Kelly ShusterAndroid 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 WorkflowSingle branch

Pull Request

ProsEasy to understand

Everything in a central location

Straightforward to obtain code & debug

ConsLibrary 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.gradleinclude ':app', ':mylibrary'

settings.gradleinclude ':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 WorkflowSingle branch

Pull Request

ProsEasy procedure; hard to mess up

Added some separation of concerns

ConsLibrary 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

78c7046123789d

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.gradleinclude ':app'include ':dependency-sample-library:mylibrary'

settings.gradleinclude ':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

78c7046123789d

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

ff07597123789d

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

1bd7125123789d

a2b789d

345a89d

678789d

dependency-sample dependency-sample-lib

1bd7125123789d

a2b789d

345a89d

678789d

dependency-sample dependency-sample-lib

177458f

1bd7125123789d

a2b789d

345a89d

678789d

dependency-sample dependency-sample-lib

177458f498defd

145458e

1bd7125

177458f

498defd

145458e

How to recover

Removing Submodules

.gitmodules.git/modules

Team Workflow

Step 1 - Shell & Library1. Create branch for shell

2. Create branch for library

3. Make and test shell & library changes

simultaneously

Step 2 - Library1. Pull request / code review lib changes

2. Merge pull request

Step 3 - Shell1. Update shell branch to point to latest

library master commit

2. Pull request / code review shell changes

3. Merge pull request

ProsClear separation of concerns

ProsClear separation of concerns

Library is in separate repo! Can be shared!

ProsClear separation of concerns

Library is in separate repo! Can be shared!

“Versioning” brought to you by git

ProsClear separation of concerns

Library is in separate repo! Can be shared!

“Versioning” brought to you by git

“Version” determined by shell

ProsOne Android Studio Project

ProsOne Android Studio Project

Easily step into code with debugger

ProsOne Android Studio Project

Easily step into code with debugger

Submodule maintains its own git history

ConsMagic is involved

ConsMagic is involved

Very easy to mess up, in multiple spots:

ConsMagic is involved

Very easy to mess up, in multiple spots:

Working with a detached head

Pulling down latest submodule

Adding & tracking submodule reference

ConsMulti-step PR & merge

ConsMulti-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 - LibraryCreate branch

Make & test library changes

Increase version in gradle file

Pull request / code review

Merge pull request

Publish library to artifactory

Step 2 - ShellCreate branch

Make & test shell changes

Increase version in gradle file

Pull request / code review

Merge pull request

ProsClear separation of concerns

ProsClear separation of concerns

Library is in sep repo! Can be shared!

ProsClear separation of concerns

Library is in sep repo! Can be shared!

Versioning is human readable / determined

ProsClear separation of concerns

Library is in sep repo! Can be shared!

Versioning is human readable / determined

Benefits of JAR / AAR

ConsVersioning has zero tie to git!

Easy to lose track of what is where

ConsVersioning 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

ConsSources jar is difficult to locate and use

ConsSources jar is difficult to locate and use

No guarantee your sources jar matches the

artifact you are referencing

ConsSources 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 teamSize of team

Pick what works for your teamSize of team

Frequency of library changes

Pick what works for your teamSize of team

Frequency of library changes

Library reuse or sharing

Pick what works for your teamSize of team

Frequency of library changes

Library reuse or sharing

Importance of aar

Pick what works for your teamSize of team

Frequency of library changes

Library reuse or sharing

Importance of aar

Team knowledge of git

@KellyShuster

https://github.com/KioKrofovitch/

dependency-sampledependency-sample-library

ResourcesGit submodulehttps://git-scm.com/docs/git-submodule https://git-scm.com/book/en/v2/Git-Tools-Submodules

Artifactory Open Sourcehttps://www.jfrog.com/open-source/

Artifactory Professionalhttps://www.jfrog.com/artifactory/

Artifactory OS Tutorialhttps://jeroenmols.github.io/blog/2015/08/06/artifactory/

Photo CreditsAndroid Robothttps://commons.wikimedia.org/wiki/File:Android_robot.svg

Trinity College Libraryhttps://en.wikipedia.org/wiki/Trinity_College,_Dublin#/media/File:Long_Room_Interior,_Trinity_College_Dublin,_Ireland_-_Diliff.jpg

Rubyhttp://nicholasjohnson.com/ruby/

Clean Deskhttp://www.levo.com/articles/career-advice/what-your-desk-says-about-you

Messy Deskhttp://www.telegraph.co.uk/news/newstopics/howaboutthat/10225664/Having-a-messy-desk-makes-you-more-creative.html

Headless Horseman Gifhttps://www.lovethisgif.com/tag/headless+horseman

Ghosthttp://38.media.tumblr.com/d30fe069cc48e11eeb31ae08293a159e/tumblr_nbtdxg9d6n1szf0nzo1_250.gif

Photo CreditsAtreyu & Horsehttp://5cities6women.com/2014/04/06/happy-30th-birthday-neverending-story/

Neverending Story Bookhttp://www.dailyrecord.co.uk/entertainment/tv-radio/flashback-friday-neverending-story-proves-4948514

Unicorn w/ Rainbowshttp://souloftruth.com/the-race-to-nowhere/

Falcor & Atreyuhttp://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 Pichttp://wallpapershidef.com/outer-space-desktop-wallpaper.html

Computerhttps://commons.wikimedia.org/wiki/File:Gnome-computer.svg