Slide 1

Slide 1 text

Gradle deep dive Bryan Herbst Android Engineer @ Target

Slide 2

Slide 2 text

The toolchain and you

Slide 3

Slide 3 text

Your Code

Slide 4

Slide 4 text

Your Code (it’s just text)

Slide 5

Slide 5 text

Build tools

Slide 6

Slide 6 text

Gradle

Slide 7

Slide 7 text

IDE

Slide 8

Slide 8 text

Your Code Build tools Gradle IDE

Slide 9

Slide 9 text

Why Gradle?

Slide 10

Slide 10 text

Reproducible builds !

Slide 11

Slide 11 text

Dependency Management "

Slide 12

Slide 12 text

Extensibility #

Slide 13

Slide 13 text

Faster builds $

Slide 14

Slide 14 text

Task automation %

Slide 15

Slide 15 text

Other options Bazel and Buck

Slide 16

Slide 16 text

Gradle intro

Slide 17

Slide 17 text

Projects Every build contains 1+ projects

Slide 18

Slide 18 text

Projects Every build contains 1+ projects compile ':projectB:childC'

Slide 19

Slide 19 text

Tasks Every project contains 1+ tasks

Slide 20

Slide 20 text

Build lifecycle Initialization Configuration Execution

Slide 21

Slide 21 text

Gradle Wrapper It isn’t that special

Slide 22

Slide 22 text

if (gradleIsNotInstalled) { installGradle() } invokeGradle()

Slide 23

Slide 23 text

Why?

Slide 24

Slide 24 text

Why? For consistent builds across machines

Slide 25

Slide 25 text

Tasks Things you can do

Slide 26

Slide 26 text

Android Tasks • androidDependencies - Displays the Android dependencies of the project. • signingReport - Displays the signing info for each variant. • sourceSets - Prints out all the source sets defined in this project. • assemble - Assembles all variants of all applications and secondary packages. • assembleAndroidTest - Assembles all the Test applications. • assembleDebug - Assembles all Debug builds. • assembleRelease - Assembles all Release builds. • build - Assembles and tests this project. • buildDependents - Assembles and tests this project and all projects that depend on it. • buildNeeded - Assembles and tests this project and all projects it depends on. • clean - Deletes the build directory. • cleanBuildCache - Deletes the build cache directory. • compileDebugAndroidTestSources • compileDebugSources • compileDebugUnitTestSources • compileReleaseSources • compileReleaseUnitTestSources • mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests. • init - Initializes a new Gradle build. • wrapper - Generates Gradle wrapper files. • buildEnvironment - Displays all buildscript dependencies declared in root project 'HelloWorld'. • components - Displays the components produced by root project 'HelloWorld'. [incubating] • dependencies - Displays all dependencies declared in root project 'HelloWorld'. • dependencyInsight - Displays the insight into a specific dependency in root project 'HelloWorld'. • dependentComponents - Displays the dependent components of components in root project 'HelloWorld'. [incubating] • help - Displays a help message. • model - Displays the configuration model of root project 'HelloWorld'. [incubating] • projects - Displays the sub-projects of root project 'HelloWorld'. • properties - Displays the properties of root project 'HelloWorld'. • tasks - Displays the tasks runnable from root project 'HelloWorld' (some of the displayed tasks may belong to subprojects). • installDebug - Installs the Debug build. • installDebugAndroidTest - Installs the android (on device) tests for the Debug build. • uninstallAll - Uninstall all applications. • uninstallDebug - Uninstalls the Debug build. • uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build. • uninstallRelease - Uninstalls the Release build. • check - Runs all checks. • connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices. • connectedCheck - Runs all device checks on currently connected devices. • connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices. • deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers. • deviceCheck - Runs all device checks using Device Providers and Test Servers. • lint - Runs lint on all variants. • lintDebug - Runs lint on the Debug build. • lintRelease - Runs lint on the Release build. • test - Run unit tests for all variants. • testDebugUnitTest - Run unit tests for the debug build. • testReleaseUnitTest - Run unit tests for the release build. •

Slide 27

Slide 27 text

(Some) Android Tasks • assembleDebug – Assembles all Debug builds. • assemble – Assembles all variants of all applications and secondary packages. • clean – Deletes the build directory

Slide 28

Slide 28 text

(Some) Android Tasks • assembleDebug – Assembles all Debug builds. • assemble – Assembles all variants of all applications and secondary packages. • clean – Deletes the build directory

Slide 29

Slide 29 text

(Some) Android Tasks • assembleDebug – Assembles all Debug builds. • assemble – Assembles all variants of all applications and secondary packages. • clean – Deletes the build directory

Slide 30

Slide 30 text

task hello { doLast { println 'Hello world!' } }

Slide 31

Slide 31 text

doFirst() doLast()

Slide 32

Slide 32 text

doFirst() Add to the beginning of the action list doLast()

Slide 33

Slide 33 text

doFirst() Add to the beginning of the action list doLast() Add to the end of the action list

Slide 34

Slide 34 text

task hello { description 'Says hello' group 'Useless tasks' doLast { println 'Hello world!' } }

Slide 35

Slide 35 text

Hot off the presses (Gradle 4.2) task hello { description 'Says hello' group 'Useless tasks' doLast('Print greeting') { println 'Hello world!' } }

Slide 36

Slide 36 text

task taskX(dependsOn: 'taskY') { doLast { println 'taskX' } } Will run first

Slide 37

Slide 37 text

class GreetingTask: DefaultTask { @TaskAction fun greet() { println("Hello!") } }

Slide 38

Slide 38 text

Shortcuts ./gradlew tDUT = testDebugUnitTest

Slide 39

Slide 39 text

Shortcuts ./gradlew tDUT = testDebugUnitTest ./gradlew t = test

Slide 40

Slide 40 text

Shortcuts ./gradlew tDUT = testDebugUnitTest ./gradlew t = test test? tasks?

Slide 41

Slide 41 text

Shortcuts ./gradlew tDUT = testDebugUnitTest ./gradlew t = test ./gradlew te = test

Slide 42

Slide 42 text

Task Outcomes • EXECUTED- Task was fully executed

Slide 43

Slide 43 text

Task Outcomes • EXECUTED- Task was fully executed • UP-TO-DATE- Task inputs/outputs did not change

Slide 44

Slide 44 text

Task Outcomes • EXECUTED- Task was fully executed • UP-TO-DATE- Task inputs/outputs did not change • FROM-CACHE- Output pulled from cache

Slide 45

Slide 45 text

Task Outcomes • EXECUTED- Task was fully executed • UP-TO-DATE- Task inputs/outputs did not change • FROM-CACHE- Output pulled from cache • SKIPPED- Task was skipped

Slide 46

Slide 46 text

Task Outcomes • EXECUTED- Task was fully executed • UP-TO-DATE- Task inputs/outputs did not change • FROM-CACHE- Output pulled from cache • SKIPPED- Task was skipped • NO-SOURCE- Task wasn’t needed

Slide 47

Slide 47 text

Task Outcomes • EXECUTED - BAD • UP-TO-DATE - GOOD • FROM-CACHE - OKAY • SKIPPED - GOOD • NO-SOURCE - GOOD

Slide 48

Slide 48 text

Plugins

Slide 49

Slide 49 text

class GreetingPlugin implements Plugin { void apply(Project project) { project.task('hello') { doLast { println "Hello from the GreetingPlugin" } } } }

Slide 50

Slide 50 text

class GreetingPlugin implements Plugin { void apply(Project project) { project.task('hello') { doLast { println "Hello from the GreetingPlugin" } } } }

Slide 51

Slide 51 text

class GreetingPlugin implements Plugin { void apply(Project project) { project.task('hello') { doLast { println "Hello from the GreetingPlugin" } } } }

Slide 52

Slide 52 text

Anatomy of a build script

Slide 53

Slide 53 text

Anatomy of a Gradle build script buildscript { // ... } allprojects { // ... } apply plugin: 'kotlin' android { // ... } dependencies { // ... }

Slide 54

Slide 54 text

buildscript { // ... } Configuration for the Gradle build script itself allprojects { // ... } apply plugin: 'kotlin' android { // ... } dependencies { // ... }

Slide 55

Slide 55 text

buildscript { repositories { google() jcenter() } dependencies { classpath ’com.foo:bar:1.0.0' } } Dependency repos for the build script allprojects { // ... } apply plugin: 'kotlin' android { // ... } dependencies { // ... } Dependencies for the build script

Slide 56

Slide 56 text

allprojects { // ... } Configuration for this and all child projects apply plugin: 'kotlin' android { // ... } dependencies { // ... } buildscript { // ... }

Slide 57

Slide 57 text

allprojects { repositories { google() jcenter() } } Common dependency repo definition apply plugin: 'kotlin' android { // ... } dependencies { // ... } buildscript { // ... }

Slide 58

Slide 58 text

apply plugin: 'kotlin' Apply plugins android { // ... } dependencies { // ... } buildscript { // ... } allprojects { // ... }

Slide 59

Slide 59 text

android { compileSdkVersion 26 buildToolsVersion "26.0.1" } Plugin configuration DSL dependencies { // ... } buildscript { // ... } allprojects { // ... } apply plugin: 'kotlin'

Slide 60

Slide 60 text

dependencies { compile 'com.foo:bar:2.1.3' testCompile 'junit:junit:4.12' } Project dependencies buildscript { // ... } allprojects { // ... } apply plugin: 'kotlin' android { // ... }

Slide 61

Slide 61 text

android { compileSdkVersion 26 } android.compileSdkVersion 26 =

Slide 62

Slide 62 text

Configurations Dependency configurations

Slide 63

Slide 63 text

Configurations (Android) • debugCompile

Slide 64

Slide 64 text

Configurations (Android) • debugCompile • releaseCompile

Slide 65

Slide 65 text

Configurations (Android) • debugCompile • releaseCompile • testCompile

Slide 66

Slide 66 text

Configurations (Android) • debugCompile • releaseCompile • testCompile • testDebugCompile

Slide 67

Slide 67 text

Configurations (Android) • debugCompile • releaseCompile • testCompile • testDebugCompile • testDebugFreeBlueArmv7Compile

Slide 68

Slide 68 text

Custom Configurations configurations { internalCompile debugCompile.extendsFrom(internalCompile) dogfoodCompile.extendsFrom(internalCompile) } dependencies { internalCompile '...' }

Slide 69

Slide 69 text

Custom Configurations configurations { internalCompile debugCompile.extendsFrom(internalCompile) dogfoodCompile.extendsFrom(internalCompile) } dependencies { internalCompile '...' }

Slide 70

Slide 70 text

Custom Configurations configurations { internalCompile debugCompile.extendsFrom(internalCompile) dogfoodCompile.extendsFrom(internalCompile) } dependencies { internalCompile '...' }

Slide 71

Slide 71 text

Gradle Kotlin DSL

Slide 72

Slide 72 text

Static typing defaultConfig { versionCode "abc" versionName 123 multiDexEnabled "10" }

Slide 73

Slide 73 text

Static typing defaultConfig { versionCode "abc" versionName 123 multiDexEnabled "10" }

Slide 74

Slide 74 text

Autocompletion + content assist

Slide 75

Slide 75 text

And more! (but it is a little rough)

Slide 76

Slide 76 text

Organizing scripts

Slide 77

Slide 77 text

buildscript { // ... } ext.isCi = System.getenv().containsKey("IS_CI") task foo { doLast { if (isCi) { // ... } } }

Slide 78

Slide 78 text

buildscript { // ... } ext.isCi = System.getenv().containsKey("IS_CI") task foo { doLast { if (isCi) { // ... } } }

Slide 79

Slide 79 text

ext.supportLibVersion = "26.0.1" dependencies { compile "[…]:appcompat-v7:$supportLibVersion" compile "[…]:design:$supportLibVersion" }

Slide 80

Slide 80 text

Organizing scripts- include versions.gradle ext.buildTools = "26.0.1" ext.compileVersion = 26 build.gradle apply from: 'versions.gradle' android { buildToolsVersion buildTools // ... }

Slide 81

Slide 81 text

buildSrc Re-usable and testable buildscript code

Slide 82

Slide 82 text

{project}/buildSrc/ src/main/java - Plugins, tasks, etc.

Slide 83

Slide 83 text

{project}/buildSrc/ src/main/java - Plugins, tasks, etc. build.gradle – Dependencies and configuration

Slide 84

Slide 84 text

{project}/buildSrc/ src/main/java - Plugins, tasks, etc. build.gradle – Dependencies and configuration src/test/java – Tests!

Slide 85

Slide 85 text

See Also: github.com/android/platform_frameworks_support

Slide 86

Slide 86 text

Getting Build Information Knowledge is power

Slide 87

Slide 87 text

apply plugin: 'project-report' ./gradlew projectReport Provides: • Task report • dependency report • property report

Slide 88

Slide 88 text

apply plugin: 'build-dashboard' ./gradlew buildDashboard Provides: • All reports implementing the reporting interface

Slide 89

Slide 89 text

./gradlew [task] --profile Provides: • Build profile by step

Slide 90

Slide 90 text

apply plugin: 'com.gradle.build-scan' ./gradlew assembleDebug --scan Provides: • Shareable, centralized build record

Slide 91

Slide 91 text

Build Scans Demo

Slide 92

Slide 92 text

Improving Build Performance

Slide 93

Slide 93 text

def gitSha = 'git rev-parse --short HEAD’ .execute([], project.rootDir).text.trim()

Slide 94

Slide 94 text

def gitSha = 'git rev-parse --short HEAD’ .execute([], project.rootDir).text.trim() timestamp = new Date().format('yyyyMMddHHmmss')

Slide 95

Slide 95 text

def gitSha = 'git rev-parse --short HEAD’ .execute([], project.rootDir).text.trim() timestamp = new Date().format('yyyyMMddHHmmss') &

Slide 96

Slide 96 text

def gitSha = 'git rev-parse --short HEAD’ .execute([], project.rootDir).text.trim() timestamp = new Date().format('yyyyMMddHHmmss') versionNameSuffix = new Date().format('yyyyMMddHHmmss')

Slide 97

Slide 97 text

def gitSha = 'git rev-parse --short HEAD’ .execute([], project.rootDir).text.trim() timestamp = new Date().format('yyyyMMddHHmmss') versionNameSuffix = new Date().format('yyyyMMddHHmmss') '

Slide 98

Slide 98 text

Gradle Daemon Enabled by default as of Gradle 3.0

Slide 99

Slide 99 text

Parallel Builds

Slide 100

Slide 100 text

Parallel Builds org.gradle.parallel=true

Slide 101

Slide 101 text

Don’t compile if you don’t need to

Slide 102

Slide 102 text

Don’t compile if you don’t need to taskX.onlyIf { !project.hasProperty('skipX') }

Slide 103

Slide 103 text

Don’t compile if you don’t need to class TaskX extends DefaultTask { @Input def inputProperty }

Slide 104

Slide 104 text

Don’t compile if you don’t need to class TaskX extends DefaultTask { @Input def inputProperty } Task is now incremental!

Slide 105

Slide 105 text

Android Plugin 3.0.0 & Gradle 4.x Parallel & cacheable

Slide 106

Slide 106 text

Configurations compile

Slide 107

Slide 107 text

Configurations compile testCompile

Slide 108

Slide 108 text

Configurations compile testCompile debugCompile

Slide 109

Slide 109 text

Configurations compile testCompile debugCompile apk

Slide 110

Slide 110 text

Configurations compile testCompile debugCompile apk provided

Slide 111

Slide 111 text

Configurations compile testCompile debugCompile apk provided

Slide 112

Slide 112 text

Configurations implementation Available at compile time, Only available to consumers at runtime

Slide 113

Slide 113 text

Configurations implementation api Available at compile time and run time

Slide 114

Slide 114 text

Configurations implementation api compileOnly Only available at compile time

Slide 115

Slide 115 text

Configurations implementation api compileOnly runtimeOnly Only available at runtime

Slide 116

Slide 116 text

Lib B Lib A App

Slide 117

Slide 117 text

Lib B Lib A App Old configurations Change (recompile)

Slide 118

Slide 118 text

Lib B Lib A App Old configurations Change (recompile) recompile

Slide 119

Slide 119 text

Lib B Lib A App Old configurations Change (recompile) recompile recompile

Slide 120

Slide 120 text

Lib B Lib A App New configurations Change (recompile) recompile implementation

Slide 121

Slide 121 text

Plugin 2.2.0 Gradle 2.14.1 Plugin 3.0 Gradle 4.0 Configuration ~2 mins ~2.5 s 1-line Java change ~2 mins 15 s ~6.4 s

Slide 122

Slide 122 text

Build cache

Slide 123

Slide 123 text

Build cache (not Android’s)

Slide 124

Slide 124 text

Has input changed?

Slide 125

Slide 125 text

Has input changed? UP-TO-DATE

Slide 126

Slide 126 text

Has input changed? UP-TO-DATE In cache?

Slide 127

Slide 127 text

Has input changed? UP-TO-DATE In cache? Yes FROM-CACHE

Slide 128

Slide 128 text

Has input changed? UP-TO-DATE In cache? Yes FROM-CACHE Execute task

Slide 129

Slide 129 text

Build cache org.gradle.caching=true Or ./gradlew [task] --build-cache

Slide 130

Slide 130 text

Resources • google.github.io/android-gradle-dsl • github.com/android/platform_frameworks_support • gradle.org/docs