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

C67d4b2a0b74214c56b23969177e743c?s=128

Kotlin User Group Hamburg

August 30, 2019
Tweet

Transcript

  1. None
  2. @segunfamisa

  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 • Custom Plugins • Resources
  4. Improving your gradle experience

  5. #0

  6. Small project, single or few modules #0

  7. // <app> 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
  8. // <networking-lib> build.gradle apply plugin: 'kotlin' ... dependencies { ...

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31" implementation "io.reactivex.rxjava2:rxjava:2.2.5" } // <app> 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
  9. // <app> 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" } // <networking-lib> 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
  10. #0 // <app> 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" } // <networking-lib> 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
  11. #0 - solution

  12. #0 - solution Solving the duplication problem with Gradle extra

    (ext) properties feature
  13. // dependencies.gradle ext { ... libraries = [ rxJavaVersion :

    '2.2.5' rxAndroidVersion : '2.1.0' kotlinVersion : '1.3.31' ] } 1. Externalize dependencies
  14. 1. Externalize dependencies 2. Apply dependencies.gradle to root project //

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

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

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

    Reference the dependencies in the build.gradle files // <app> build.gradle dependencies { implementation "org.jetbrains.kotlin:...:$libs.kotlinVersion" implementation "io.reactivex.rxjava2:rxjava:$libs.rxJavaVersion" } // <networking-lib> build.gradle dependencies { ... def libs = rootProject.ext.libraries implementation "org.jetbrains.kotlin:...:$libs.kotlinVersion" implementation "io.reactivex.rxjava2:...:$libs.rxJavaVersion" }
  18. • Managing/updating versions of dependencies is now easier - just

    need to change in one place • Still has the problem of duplication of dependencies
  19. #1

  20. #1 • Fairly complex projects • Multiple modules • You

    will find a lot of repetitions in the dependencies
  21. #1 // <login> 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 }
  22. #1 // <login> 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 } // <profile> 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 }
  23. #1 // <login> 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 } // <profile> 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 } // <search> 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 }
  24. #1 // <login> 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 } // <profile> 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 } // <search> 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 } // <core> 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 }
  25. #1 // <login> 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 } // <profile> 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 } // <search> 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 } // <core> 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
  26. #1 Solution: extract common/shared dependencies and apply to the modules

  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' }
  28. 1. Extract common dependencies 2. Apply common dependencies to respective

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

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

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

    modules // <login> build.gradle apply from: “relative/path/to/shared-dependencies.gradle" ... dependencies { ... // other dependencies } // <profile> build.gradle apply from: “relative/path/to/shared-dependencies.gradle" ... dependencies { ... // other dependencies } // <search> build.gradle apply from: “relative/path/to/shared-dependencies.gradle" ... dependencies { ... // other dependencies } // <core> build.gradle apply from: “relative/path/to/shared-dependencies.gradle" ... dependencies { ... // other dependencies }
  32. • Managing shared dependencies becomes easier • Eliminates repeated declaration

    of dependencies
  33. #2

  34. #2 • Fairly complex projects • Multiple modules • You

    will find a lot of repetitions in the configurations of the modules
  35. #2

  36. #2 // <login> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion

    defaultConfig {...} buildTypes {...} }
  37. #2 // <login> 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 {...} }
  38. #2 // <login> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion

    defaultConfig {...} buildTypes { debug { minifyEnabled ... proguardFiles ... } release { minifyEnabled ... proguardFiles ... } } }
  39. #2 // <login> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion

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

    defaultConfig {...} buildTypes {...} } // <profile> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion defaultConfig {...} buildTypes {...} }
  41. #2 // <login> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion

    defaultConfig {...} buildTypes {...} } // <profile> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion defaultConfig {...} buildTypes {...} } // <search> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion defaultConfig {...} buildTypes {...} }
  42. #2 // <login> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion

    defaultConfig {...} buildTypes {...} } // <profile> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion defaultConfig {...} buildTypes {...} } // <search> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion defaultConfig {...} buildTypes {...} } Problem: Repeated configuration in so many modules
  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:
  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 // <login> build.gradle apply from: "$rootProject.projectDir/common-android-config.gradle" ...
  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:
  46. Taking it even further with Kotlin DSL

  47. Why Kotlin DSL? • Kotlin is now really popular •

    Same language for code & build logic
  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
  49. buildSrc • Gradle allows us create a module to add

    complex build related logic - like plugins, custom tasks, etc.
  50. 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
  51. Adding dependencies versions to buildSrc Anatomy of the buildSrc module

    for dependencies versioning
  52. dependencies.gradle -> dependencies.kt // build.gradle.kts plugins { `kotlin-dsl` } repositories

    { jcenter() }
  53. 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" } ... }
  54. 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" } ... }
  55. 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 ... }
  56. 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” ✅
  57. Kotlin DSL prerequisites • Gradle 5.0 • Java 8

  58. Tips for migrating to Kotlin DSL

  59. 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
  60. Migrating an Android project

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

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

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

    ":domain") ’:app’ becomes “:app” include becomes include()
  64. // app-level build.gradle

  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" }
  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") }
  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" }
  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" }
  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" }
  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" }
  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" }
  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" }
  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" }
  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") }
  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") }
  76. // top-level build.gradle

  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() } }
  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() } }
  79. What changed?

  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?
  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() } }
  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?
  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?
  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() } }
  85. Custom Gradle Plugin

  86. Custom Gradle Plugin • We could use a custom plugin

    to apply common configuration across multiple modules
  87. class AwesomePlugin : Plugin<Project> { override fun apply(project: Project) {

    ... } }
  88. class AwesomePlugin : Plugin<Project> { override fun apply(project: Project) {

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

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

    with(project) { project.plugins.all { when (this) { is AppPlugin, is LibraryPlugin -> extensions.getByType<TestedExtension>().apply { configureAndroidModule(extension = this, project = project) } } } } } }
  91. private fun TestedExtension.configureAndroidModule(project: Project) { }

  92. 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 } } ... }
  93. Apply new plugin to all modules plugins { id("com.android.application") kotlin("android")

    kotlin("android.extensions") } apply { from("${rootProject.projectDir}/shared-dependencies.gradle") } apply<AwesomePlugin>() ...
  94. Current pain points with Kotlin DSL

  95. Current pain points with Kotlin DSL • IDE support is

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

    not yet at • Additional configuration time in your build process
  97. 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)
  98. 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
  99. Final words

  100. Final words • Keep it DRY (Don’t Repeat Yourself) -

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

    rule of three applies here • Modular code rocks
  102. 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
  103. 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)
  104. Thanks! Segun Famisa, Android GDE