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 full-size slide

  2. The toolchain and you

    View full-size slide

  3. Your Code
    (it’s just text)

    View full-size slide

  4. Your Code Build tools Gradle IDE

    View full-size slide

  5. Reproducible builds
    !

    View full-size slide

  6. Dependency Management
    "

    View full-size slide

  7. Extensibility
    #

    View full-size slide

  8. Faster builds
    $

    View full-size slide

  9. Task automation
    %

    View full-size slide

  10. Other options
    Bazel and Buck

    View full-size slide

  11. Gradle intro

    View full-size slide

  12. Projects
    Every build contains 1+ projects

    View full-size slide

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

    View full-size slide

  14. Tasks
    Every project contains 1+ tasks

    View full-size slide

  15. Build lifecycle
    Initialization Configuration Execution

    View full-size slide

  16. Gradle Wrapper
    It isn’t that special

    View full-size slide

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

    View full-size slide

  18. Why?
    For consistent builds across machines

    View full-size slide

  19. Tasks
    Things you can do

    View full-size slide

  20. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  25. doFirst() doLast()

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  32. Shortcuts
    ./gradlew tDUT = testDebugUnitTest

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  36. Task Outcomes
    • EXECUTED- Task was fully executed

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  39. 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 full-size slide

  40. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  45. Anatomy of a build script

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  48. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  54. android {
    compileSdkVersion 26
    }
    android.compileSdkVersion 26
    =

    View full-size slide

  55. Configurations
    Dependency configurations

    View full-size slide

  56. Configurations (Android)
    • debugCompile

    View full-size slide

  57. Configurations (Android)
    • debugCompile
    • releaseCompile

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  64. Gradle Kotlin DSL

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  67. Autocompletion + content assist

    View full-size slide

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

    View full-size slide

  69. Organizing scripts

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  74. buildSrc
    Re-usable and testable buildscript code

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  79. Getting Build Information
    Knowledge is power

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  84. Build Scans Demo

    View full-size slide

  85. Improving Build Performance

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  91. Gradle Daemon
    Enabled by default as of Gradle 3.0

    View full-size slide

  92. Parallel Builds

    View full-size slide

  93. Parallel Builds
    org.gradle.parallel=true

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  99. Configurations
    compile

    View full-size slide

  100. Configurations
    compile
    testCompile

    View full-size slide

  101. Configurations
    compile
    testCompile
    debugCompile

    View full-size slide

  102. Configurations
    compile
    testCompile
    debugCompile
    apk

    View full-size slide

  103. Configurations
    compile
    testCompile
    debugCompile
    apk
    provided

    View full-size slide

  104. Configurations
    compile
    testCompile
    debugCompile
    apk
    provided

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  107. Configurations
    implementation
    api
    compileOnly
    Only available at compile time

    View full-size slide

  108. Configurations
    implementation
    api
    compileOnly
    runtimeOnly
    Only available at runtime

    View full-size slide

  109. Lib B Lib A App

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  114. 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 full-size slide

  115. Build cache
    (not Android’s)

    View full-size slide

  116. Has input
    changed?

    View full-size slide

  117. Has input
    changed?
    UP-TO-DATE

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide