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

Playing nice with Gradle - droidcon KE

Playing nice with Gradle - droidcon KE

Presentation given at droidcon KE, Nairobi, 2019

Abstract:
Gradle is the most popular build system in use today for building Android projects. It is an amazing tool that has improved how we build projects especially when we compare to the previous build systems used for Android development.

As your project starts to scale, so does the Gradle setup start to get complicated - from build performance, to configuring plugins, to managing dependencies, to managing multiple modules. Gradle by default makes use of Groovy language, which often does not provide the full features of static typing - hence making it more difficult to customize.

If like me, you’re in a love-hate relationship with Gradle, then, this talk is for you.

In this talk, we will go through top tips to make Gradle work for us as Android developers.

We will talk about different quick wins to make maintaining our Gradle configuration easy by:
avoiding repetitive code as your project modules continue to grow, and
writing your build configuration partly or fully in Kotlin, hence taking advantage of the Kotlin DSL feature.
You will leave this talk with a lot of ideas of how to improve the Gradle setup of your project.

Most of these ideas will be something you can immediately implement while some may require a little more effort. Ultimately we will be able to make Gradle work for you to achieve the best results.

Resource links in the slides:
https://handstandsam.com/2019/03/12/sharing-gradle-configuration-in-multi-module-android-projects/
https://segunfamisa.com/posts/android-gradle-extra-properties
https://gradle.com/blog/getting-started-with-gradle-kotlin-dsl/
https://github.com/gradle/kotlin-dsl
https://blog.codinghorror.com/rule-of-three/

Segun Famisa

August 09, 2019
Tweet

More Decks by Segun Famisa

Other Decks in Programming

Transcript

  1. Playing nice with Gradle
    the elephant in the room
    Segun Famisa, Android GDE
    droidcon KE
    August, 2019

    View Slide

  2. @segunfamisa

    View Slide

  3. Outline
    • Introduction
    • Scenarios & improvements #0, #1, #2
    • Taking it a step further with Kotlin DSL
    • buildSrc
    • Migrating build scripts to Kotlin DSL from Groovy DSL
    • Kotlin DSL improvements
    • Resources

    View Slide

  4. Improving your gradle
    experience

    View Slide

  5. #0

    View Slide

  6. Small project, single or few modules
    #0

    View Slide

  7. // build.gradle
    apply plugin: 'com.android.application'
    ...
    dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "io.reactivex.rxjava2:rxjava:2.2.5"
    }
    #0

    View Slide

  8. // build.gradle
    apply plugin: 'kotlin'
    ...
    dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "io.reactivex.rxjava2:rxjava:2.2.5"
    }
    // build.gradle
    apply plugin: 'com.android.application'
    ...
    dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "io.reactivex.rxjava2:rxjava:2.2.5"
    }
    #0

    View Slide

  9. // build.gradle
    apply plugin: 'com.android.application'
    ...
    dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "io.reactivex.rxjava2:rxjava:2.2.5"
    }
    // build.gradle
    apply plugin: 'kotlin'
    ...
    dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "io.reactivex.rxjava2:rxjava:2.2.5"
    }
    #0

    View Slide

  10. #0
    // build.gradle
    apply plugin: 'com.android.application'
    ...
    dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "io.reactivex.rxjava2:rxjava:2.2.5"
    }
    // build.gradle
    apply plugin: 'kotlin'
    ...
    dependencies {
    ...
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "io.reactivex.rxjava2:rxjava:2.2.5"
    }
    Managing dependencies versions becomes tedious

    View Slide

  11. #0 - solution

    View Slide

  12. #0 - solution
    Solving the duplication problem with Gradle extra (ext) properties feature

    View Slide

  13. // dependencies.gradle
    ext {
    ...
    libraries = [
    rxJavaVersion : '2.2.5'
    rxAndroidVersion : '2.1.0'
    kotlinVersion : '1.3.31'
    ]
    }
    1. Externalize dependencies

    View Slide

  14. 1. Externalize dependencies
    2. Apply dependencies.gradle to root project
    // root build.gradle
    buildScript {...}
    allprojects {...}
    apply from: 'relative/path/to/dependencies.gradle'

    View Slide

  15. 1. Externalize dependencies
    2. Apply dependencies.gradle to root project
    3. Reference the dependencies in the build.gradle files
    // build.gradle
    dependencies {
    ...
    def libs = rootProject.ext.libraries
    implementation "org.jetbrains.kotlin:...:$libs.kotlinVersion"
    implementation "io.reactivex.rxjava2:rxjava:$libs.rxJavaVersion"
    }

    View Slide

  16. 1. Externalize dependencies
    2. Apply dependencies.gradle to root project
    3. Reference the dependencies in the build.gradle files
    // build.gradle
    dependencies {
    implementation "org.jetbrains.kotlin:...:$libs.kotlinVersion"
    implementation "io.reactivex.rxjava2:rxjava:$libs.rxJavaVersion"
    }
    // build.gradle
    dependencies {
    ...
    def libs = rootProject.ext.libraries
    implementation "org.jetbrains.kotlin:...:$libs.kotlinVersion"
    implementation "io.reactivex.rxjava2:...:$libs.rxJavaVersion"
    }

    View Slide

  17. 1. Externalize dependencies
    2. Apply dependencies.gradle to root project
    3. Reference the dependencies in the build.gradle files
    // build.gradle
    dependencies {
    implementation "org.jetbrains.kotlin:...:$libs.kotlinVersion"
    implementation "io.reactivex.rxjava2:rxjava:$libs.rxJavaVersion"
    }
    // build.gradle
    dependencies {
    ...
    def libs = rootProject.ext.libraries
    implementation "org.jetbrains.kotlin:...:$libs.kotlinVersion"
    implementation "io.reactivex.rxjava2:...:$libs.rxJavaVersion"
    }

    View Slide

  18. • Managing/updating versions of dependencies is now easier - just
    need to change in one place
    • Still has the problem of duplication of dependencies

    View Slide

  19. #1

    View Slide

  20. #1
    • Fairly complex projects
    • Multiple modules
    • You will find a lot of repetitions in the
    dependencies

    View Slide

  21. #1
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }

    View Slide

  22. #1
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }

    View Slide

  23. #1
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }

    View Slide

  24. #1
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }

    View Slide

  25. #1
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    // build.gradle
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    testImplementation "junit:junit:$libs.jUnitVersion"
    ...
    // other dependencies
    }
    Problem: Repeated declarations of dependencies in so many modules

    View Slide

  26. #1
    Solution: extract common/shared dependencies and apply to the modules

    View Slide

  27. 1. Extract common dependencies
    // shared-dependencies.gradle - contains all shared dependncies
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
    ...
    testImplementation 'junit:junit:4.12'
    }

    View Slide

  28. 1. Extract common dependencies
    2. Apply common dependencies to respective modules
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }

    View Slide

  29. 1. Extract common dependencies
    2. Apply common dependencies to respective modules
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }

    View Slide

  30. 1. Extract common dependencies
    2. Apply common dependencies to respective modules
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }

    View Slide

  31. 1. Extract common dependencies
    2. Apply common dependencies to respective modules
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }
    // build.gradle
    apply from: “relative/path/to/shared-dependencies.gradle"
    ...
    dependencies {
    ...
    // other dependencies
    }

    View Slide

  32. • Managing shared dependencies becomes easier
    • Eliminates repeated declaration of dependencies

    View Slide

  33. #2

    View Slide

  34. #2
    • Fairly complex projects
    • Multiple modules
    • You will find a lot of repetitions in the
    configurations of the modules

    View Slide

  35. #2

    View Slide

  36. #2
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }

    View Slide

  37. #2
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {
    minSdkVersion sdk.minSdkVersion
    targetSdkVersion sdk.targetSdkVersion
    versionCode 198828
    versionName "1.5.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles 'consumer-rules.pro'
    ...
    }
    buildTypes {...}
    }

    View Slide

  38. #2
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {
    debug {
    minifyEnabled ...
    proguardFiles ...
    }
    release {
    minifyEnabled ...
    proguardFiles ...
    }
    }
    }

    View Slide

  39. #2
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }

    View Slide

  40. #2
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }

    View Slide

  41. #2
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }

    View Slide

  42. #2
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }
    // build.gradle
    android {
    compileSdkVersion sdk.compileSdkVersion
    buildToolsVersion sdk.buildToolsVersion
    defaultConfig {...}
    buildTypes {...}
    }
    Problem: Repeated configuration in so many modules

    View Slide

  43. 1. Extract common configuration into separate file
    https://handstandsam.com/2019/03/12/sharing-gradle-configuration-in-multi-module-android-projects/
    // common-android-config.gradle
    apply plugin: 'kotlin-android'
    android {
    compileSdkVersion sdk.compileSdkVersion
    defaultConfig {
    minSdkVersion sdk.minSdkVersion
    targetSdkVersion sdk.targetSdkVersion
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    }
    Further reading:

    View Slide

  44. 1. Extract common configuration into separate file
    https://handstandsam.com/2019/03/12/sharing-gradle-configuration-in-multi-module-android-projects/
    Further reading:
    2. Apply config to android modules
    // build.gradle
    apply from: "$rootProject.projectDir/common-android-config.gradle"
    ...

    View Slide

  45. • Eliminates repeated configuration of common build logic
    • Same applies to other common configuration you may have across
    multiple modules.
    https://handstandsam.com/2019/03/12/sharing-gradle-configuration-in-multi-module-android-projects/
    Further reading:

    View Slide

  46. Taking it even further with Kotlin
    DSL

    View Slide

  47. Why Kotlin DSL?
    • Kotlin is now really popular
    • Same language for code & build logic

    View Slide

  48. Why Kotlin DSL?
    • Kotlin is now really popular
    • Same language for code & build logic
    • Better IDE support for build scripts in Kotlin.
    • Jump to declaration, syntax highlighting, etc

    View Slide

  49. Kotlin DSL prerequisites
    • Gradle 5.0
    • Java 8

    View Slide

  50. Tips for migrating to Kotlin DSL

    View Slide

  51. Tips for migrating to Kotlin DSL
    1. becomes
    2. Single quotes become double quotes
    3. Property assignments should have assignment operator ‘=‘
    4. Function calls should have parenthes

    View Slide

  52. buildSrc
    • Gradle allows us create a module to add complex build related logic - like
    plugins, custom tasks, etc.

    View Slide

  53. buildSrc
    • Gradle allows us create a module to add complex build related logic - like
    plugins, custom tasks, etc.
    • It’s a regular module with it’s own:
    • build.gradle.kts
    • src/main/java or src/main/kotlin

    View Slide

  54. Adding dependencies versions to buildSrc
    Anatomy of the buildSrc module for dependencies versioning

    View Slide

  55. dependencies.gradle -> dependencies.kt
    // build.gradle.kts
    plugins {
    `kotlin-dsl`
    }
    repositories {
    jcenter()
    }

    View Slide

  56. dependencies.gradle -> dependencies.kt
    // Dependencies.kt
    object SdkVersions {
    const val compileSdkVersion = 28
    const val minSdkVersion = 21
    const val targetSdkVersion = 28
    }
    object Deps {
    const val kotlinStdLib = “org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41"
    const val gson = “com.google.code.gson:gson:2.8.5"
    ...
    object Rx {
    const val rxJava2 = "io.reactivex.rxjava2:rxjava:2.2.10"
    const val rxAndroid = "io.reactivex.rxjava2:rxandroid:2.1.1"
    }
    ...
    }

    View Slide

  57. dependencies.gradle -> dependencies.kt
    // Dependencies.kt
    object SdkVersions {
    const val compileSdkVersion = 28
    const val minSdkVersion = 21
    const val targetSdkVersion = 28
    }
    object Deps {
    const val kotlinStdLib = “org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41"
    const val gson = “com.google.code.gson:gson:2.8.5"
    ...
    object Rx {
    const val rxJava2 = "io.reactivex.rxjava2:rxjava:2.2.10"
    const val rxAndroid = "io.reactivex.rxjava2:rxandroid:2.1.1"
    }
    ...
    }

    View Slide

  58. dependencies.gradle -> dependencies.kt
    // Dependencies.kt
    object Deps {
    const val kotlinStdLib = “org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41"
    const val gson = “com.google.code.gson:gson:2.8.5"
    }
    // Usage in build.gradle
    dependencies {
    implementation Deps.kotlinStdLib
    implementation Deps.gson
    ...
    }

    View Slide

  59. dependencies.gradle -> dependencies.kt
    // Dependencies.kt
    object Deps {
    const val kotlinStdLib = “org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41"
    const val gson = “com.google.code.gson:gson:2.8.5"
    }
    // Usage in build.gradle
    dependencies {
    implementation Deps.kotlinStdLib
    implementation Deps.gson
    ...
    }
    Syntax highlighting ✅
    “Jump to declaration” ✅

    View Slide

  60. Migrating an Android project

    View Slide

  61. // settings.gradle
    include ':app', ':data', ':domain'

    View Slide

  62. // settings.gradle
    include ':app', ':data', ':domain'
    // settings.gradle.kts
    include(":app", ":data", ":domain")

    View Slide

  63. // settings.gradle
    include ':app', ':data', ':domain'
    // settings.gradle.kts
    include(":app", ":data", ":domain")
    ’:app’ becomes “:app”
    include becomes include()

    View Slide

  64. // app-level build.gradle

    View Slide

  65. // app-level build.gradle
    apply plugin: 'com.android.application'
    apply plugin: 'kotlin-android'
    android {
    compileSdkVersion 28
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion 21
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    release {
    minifyEnabled true
    proguardFiles ...
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  66. // app-level build.gradle.kts
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion(28)
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion(21)
    targetSdkVersion(28)
    versionCode = 1
    versionName = "1.0"
    }
    buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    proguardFiles(getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro')
    }
    }
    }
    dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31")
    implementation("androidx.appcompat:appcompat:1.0.2")
    }

    View Slide

  67. What changed?
    apply plugin: 'com.android.application'
    apply plugin: 'kotlin-android'
    android {
    compileSdkVersion 28
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion 21
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    release {
    minifyEnabled true
    proguardFiles ...
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  68. What changed?
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion 28
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion 21
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    release {
    minifyEnabled true
    proguardFiles ...
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  69. What changed?
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion 28
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion 21
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    release {
    minifyEnabled true
    proguardFiles ...
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  70. What changed?
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion(28)
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion(21)
    targetSdkVersion(28)
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    release {
    minifyEnabled true
    proguardFiles ...
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  71. What changed?
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion(28)
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion(21)
    targetSdkVersion(28)
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    release {
    minifyEnabled true
    proguardFiles ...
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  72. What changed?
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion(28)
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion(21)
    targetSdkVersion(28)
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    proguardFiles(getDefaultProguardFile(‘...’), 'proguard-rules.pro')
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  73. What changed?
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion(28)
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion(21)
    targetSdkVersion(28)
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    proguardFiles(getDefaultProguardFile(‘...’), 'proguard-rules.pro')
    }
    }
    }
    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31"
    implementation "androidx.appcompat:appcompat:1.0.2"
    }

    View Slide

  74. What changed?
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion(28)
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion(21)
    targetSdkVersion(28)
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    proguardFiles(getDefaultProguardFile(‘...’), 'proguard-rules.pro')
    }
    }
    }
    dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31")
    implementation("androidx.appcompat:appcompat:1.0.2")
    }

    View Slide

  75. // app-level build.gradle.kts
    apply(plugin = "com.android.application")
    apply(plugin = "kotlin-android")
    android {
    compileSdkVersion(28)
    defaultConfig {
    applicationId "com.segunfamisa.kotlindsl"
    minSdkVersion(21)
    targetSdkVersion(28)
    versionCode = 1
    versionName = "1.0"
    }
    buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    proguardFiles(getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro')
    }
    }
    }
    dependencies {
    implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31")
    implementation("androidx.appcompat:appcompat:1.0.2")
    }

    View Slide

  76. // top-level build.gradle

    View Slide

  77. // top-level build.gradle
    buildscript {
    ext.kotlin_version = '1.3.31'
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath 'com.android.tools.build:gradle:3.4.1'
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
    }
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }

    View Slide

  78. // top-level build.gradle.kts
    buildscript {
    extra.apply {
    set("kotlin_version", "1.3.31")
    }
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath("com.android.tools.build:gradle:3.4.1")
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${extras.get("kotlin_version")})
    }
    }
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }

    View Slide

  79. What changed?

    View Slide

  80. // top-level build.gradle
    buildscript {
    ext.kotlin_version = '1.3.31'
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath 'com.android.tools.build:gradle:3.4.1'
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
    }
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }
    What changed?

    View Slide

  81. What changed?
    // top-level build.gradle.kts
    buildscript {
    extra.apply {
    set("kotlin_version", "1.3.31")
    }
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath("com.android.tools.build:gradle:3.4.1")
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${extras.get("kotlin_version")})
    }
    }
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }

    View Slide

  82. // top-level build.gradle
    buildscript {
    extra.apply {
    set("kotlin_version", "1.3.31")
    }
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath 'com.android.tools.build:gradle:3.4.1'
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
    }
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }
    What changed?

    View Slide

  83. // top-level build.gradle.kts
    buildscript {
    extra.apply {
    set("kotlin_version", "1.3.31")
    }
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath("com.android.tools.build:gradle:3.4.1")
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${extras.get("kotlin_version")})
    }
    }
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }
    What changed?

    View Slide

  84. // top-level build.gradle.kts
    buildscript {
    extra.apply {
    set("kotlin_version", "1.3.31")
    }
    repositories {
    google()
    jcenter()
    }
    dependencies {
    classpath("com.android.tools.build:gradle:3.4.1")
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${extras.get("kotlin_version")})
    }
    }
    allprojects {
    repositories {
    google()
    jcenter()
    }
    }

    View Slide

  85. Current pain points with Kotlin DSL

    View Slide

  86. Current pain points with Kotlin DSL
    • IDE support is not yet at

    View Slide

  87. Current pain points with Kotlin DSL
    • IDE support is not yet at
    • Additional configuration time in your build process

    View Slide

  88. Final words

    View Slide

  89. Final words
    • Keep it DRY (Don’t Repeat Yourself) - rule of three applies here

    View Slide

  90. Final words
    • Keep it DRY (Don’t Repeat Yourself) - rule of three applies here
    • Modular code rocks

    View Slide

  91. Final words
    • Keep it DRY (Don’t Repeat Yourself) - rule of three applies here
    • Modular code rocks
    • Take advantage of IDE support with Kotlin DSL

    View Slide

  92. Resources
    https://handstandsam.com/2019/03/12/sharing-gradle-configuration-in-multi-module-android-projects/
    https://segunfamisa.com/posts/android-gradle-extra-properties
    https://gradle.com/blog/getting-started-with-gradle-kotlin-dsl/
    https://github.com/gradle/kotlin-dsl
    https://blog.codinghorror.com/rule-of-three/

    View Slide

  93. Thanks!
    Segun Famisa, Android GDE

    View Slide