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

Improving your Android Gradle experience with Kotlin

Improving your Android Gradle experience with Kotlin

by Segun Famisa
presented on August 30, 2019 @Kotlin/Everywhere Hamburg

Kotlin User Group Hamburg

August 30, 2019
Tweet

More Decks by Kotlin User Group Hamburg

Other Decks in Programming

Transcript

  1. @segunfamisa

    View full-size slide

  2. 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
    • Custom Plugins
    • Resources

    View full-size slide

  3. Improving your gradle
    experience

    View full-size slide

  4. Small project, single or few modules
    #0

    View full-size slide

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

  6. // 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 full-size 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"
    }
    // 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 full-size slide

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

  9. #0 - solution

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

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

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

    View full-size slide

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

    View full-size slide

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

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

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

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

    View full-size slide

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

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

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

  27. 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 full-size 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
    }
    // 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

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

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

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

  41. Taking it even further with Kotlin
    DSL

    View full-size slide

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

    View full-size slide

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

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

    View full-size slide

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

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

    View full-size slide

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

    View full-size slide

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

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

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

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

  52. Kotlin DSL prerequisites
    • Gradle 5.0
    • Java 8

    View full-size slide

  53. Tips for migrating to Kotlin DSL

    View full-size slide

  54. Tips for migrating to Kotlin DSL
    1. <file.gradle> becomes <file.gradle.kts>
    2. Single quotes become double quotes
    3. Property assignments should have assignment operator ‘=‘
    4. Function calls should have parenthes

    View full-size slide

  55. Migrating an Android project

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  59. // app-level build.gradle

    View full-size slide

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

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

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

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

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

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

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

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

  71. // top-level build.gradle

    View full-size slide

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

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

  74. What changed?

    View full-size slide

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

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

  77. // 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 full-size 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()
    }
    }
    What changed?

    View full-size slide

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

  80. Custom Gradle Plugin

    View full-size slide

  81. Custom Gradle Plugin
    • We could use a custom plugin to apply common configuration
    across multiple modules

    View full-size slide

  82. class AwesomePlugin : Plugin {
    override fun apply(project: Project) {
    ...
    }
    }

    View full-size slide

  83. class AwesomePlugin : Plugin {
    override fun apply(project: Project) {
    with(project) {
    project.plugins.all {
    when (this) {
    is AppPlugin,
    is LibraryPlugin -> extensions.getByType().apply {
    configureAndroidModule(extension = this, project = project)
    }
    }
    }
    }
    }
    }

    View full-size slide

  84. class AwesomePlugin : Plugin {
    override fun apply(project: Project) {
    with(project) {
    project.plugins.all {
    when (this) {
    is AppPlugin,
    is LibraryPlugin -> extensions.getByType().apply {
    configureAndroidModule(extension = this, project = project)
    }
    }
    }
    }
    }
    }

    View full-size slide

  85. class AwesomePlugin : Plugin {
    override fun apply(project: Project) {
    with(project) {
    project.plugins.all {
    when (this) {
    is AppPlugin,
    is LibraryPlugin -> extensions.getByType().apply {
    configureAndroidModule(extension = this, project = project)
    }
    }
    }
    }
    }
    }

    View full-size slide

  86. private fun TestedExtension.configureAndroidModule(project: Project) {
    }

    View full-size slide

  87. private fun TestedExtension.configureAndroidModule(project: Project) {
    setCompileSdkVersion(28)
    defaultConfig.apply {
    minSdkVersion(21)
    targetSdkVersion(28)
    compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    }
    ...
    }

    View full-size slide

  88. Apply new plugin to all modules
    plugins {
    id("com.android.application")
    kotlin("android")
    kotlin("android.extensions")
    }
    apply {
    from("${rootProject.projectDir}/shared-dependencies.gradle")
    }
    apply()
    ...

    View full-size slide

  89. Current pain points with Kotlin DSL

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  92. Current pain points with Kotlin DSL
    • IDE support is not yet at
    • Additional configuration time in your build process
    • Applying config from an external gradle.kts file doesn’t quite work:

    • You either have to leave as .gradle files or follow another work-around
    (see: https://github.com/gradle/kotlin-dsl/issues/1287)

    View full-size slide

  93. Current pain points with Kotlin DSL
    • IDE support is not yet at
    • Additional configuration time in your build process
    • Applying config from an external gradle.kts file doesn’t quite work:

    • You either have to leave as .gradle files or follow another work-around
    (see: https://github.com/gradle/kotlin-dsl/issues/1287)

    • Weird, but sometimes, some things in the plugin show a compiler warning,
    but it actually works

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

  97. 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
    Build Bigger, Better: Gradle for Large Projects (Google I/O'19)

    View full-size slide

  98. Thanks!
    Segun Famisa, Android GDE

    View full-size slide