Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Gradle Deep Dive

Bryan Herbst
October 03, 2017

Gradle Deep Dive

All about Gradle!

Bryan Herbst

October 03, 2017
Tweet

More Decks by Bryan Herbst

Other Decks in Programming

Transcript

  1. Gradle deep dive
    Bryan Herbst
    Android Engineer @ Target

    View Slide

  2. The toolchain and you

    View Slide

  3. Your Code

    View Slide

  4. Your Code
    (it’s just text)

    View Slide

  5. Build tools

    View Slide

  6. Gradle

    View Slide

  7. IDE

    View Slide

  8. Your Code Build tools Gradle IDE

    View Slide

  9. Why Gradle?

    View Slide

  10. Reproducible builds
    !

    View Slide

  11. Dependency Management
    "

    View Slide

  12. Extensibility
    #

    View Slide

  13. Faster builds
    $

    View Slide

  14. Task automation
    %

    View Slide

  15. Other options
    Bazel and Buck

    View Slide

  16. Gradle intro

    View Slide

  17. Projects
    Every build contains 1+ projects

    View Slide

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

    View Slide

  19. Tasks
    Every project contains 1+ tasks

    View Slide

  20. Build lifecycle
    Initialization Configuration Execution

    View Slide

  21. Gradle Wrapper
    It isn’t that special

    View Slide

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

    View Slide

  23. Why?

    View Slide

  24. Why?
    For consistent builds across machines

    View Slide

  25. Tasks
    Things you can do

    View Slide

  26. 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.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. doFirst() doLast()

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  38. Shortcuts
    ./gradlew tDUT = testDebugUnitTest

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  42. Task Outcomes
    • EXECUTED- Task was fully executed

    View Slide

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

    View Slide

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

    View Slide

  45. 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

    View Slide

  46. 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

    View Slide

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

    View Slide

  48. Plugins

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  52. Anatomy of a build script

    View Slide

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

    View Slide

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

    View Slide

  55. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  61. android {
    compileSdkVersion 26
    }
    android.compileSdkVersion 26
    =

    View Slide

  62. Configurations
    Dependency configurations

    View Slide

  63. Configurations (Android)
    • debugCompile

    View Slide

  64. Configurations (Android)
    • debugCompile
    • releaseCompile

    View Slide

  65. Configurations (Android)
    • debugCompile
    • releaseCompile
    • testCompile

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  71. Gradle Kotlin DSL

    View Slide

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

    View Slide

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

    View Slide

  74. Autocompletion + content assist

    View Slide

  75. And more!
    (but it is a little rough)

    View Slide

  76. Organizing scripts

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  81. buildSrc
    Re-usable and testable buildscript code

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  85. See Also:
    github.com/android/platform_frameworks_support

    View Slide

  86. Getting Build Information
    Knowledge is power

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  91. Build Scans Demo

    View Slide

  92. Improving Build Performance

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  98. Gradle Daemon
    Enabled by default as of Gradle 3.0

    View Slide

  99. Parallel Builds

    View Slide

  100. Parallel Builds
    org.gradle.parallel=true

    View Slide

  101. Don’t compile if you don’t need to

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  105. Android Plugin 3.0.0
    & Gradle 4.x
    Parallel & cacheable

    View Slide

  106. Configurations
    compile

    View Slide

  107. Configurations
    compile
    testCompile

    View Slide

  108. Configurations
    compile
    testCompile
    debugCompile

    View Slide

  109. Configurations
    compile
    testCompile
    debugCompile
    apk

    View Slide

  110. Configurations
    compile
    testCompile
    debugCompile
    apk
    provided

    View Slide

  111. Configurations
    compile
    testCompile
    debugCompile
    apk
    provided

    View Slide

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

    View Slide

  113. Configurations
    implementation
    api
    Available at compile time and
    run time

    View Slide

  114. Configurations
    implementation
    api
    compileOnly
    Only available at compile time

    View Slide

  115. Configurations
    implementation
    api
    compileOnly
    runtimeOnly
    Only available at runtime

    View Slide

  116. Lib B Lib A App

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  121. 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

    View Slide

  122. Build cache

    View Slide

  123. Build cache
    (not Android’s)

    View Slide

  124. Has input
    changed?

    View Slide

  125. Has input
    changed?
    UP-TO-DATE

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide