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

Improving your Android Gradle Experience with K...

Improving your Android Gradle Experience with Kotlin

The talk was given at Kotlin Everywhere Hamburg, August 2019 - https://www.eventbrite.co.uk/e/kotlineverywhere-hamburg-tickets-64993039932

The talk involved sharing tips about how we can optimize Gradle for our Android projects. The talk shares some approaches using the standard Groovy DSL for customizing Gradle build system, and takes it into using Kotlin DSL and also writing custom Gradle plugins in Kotlin.

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) - https://www.youtube.com/watch?v=sQC9-Rj2yLI

Segun Famisa

August 30, 2019
Tweet

More Decks by Segun Famisa

Other Decks in Programming

Transcript

  1. 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
  2. #0

  3. // <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
  4. // <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
  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" } // <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
  6. #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
  7. // dependencies.gradle ext { ... libraries = [ rxJavaVersion :

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

    root build.gradle buildScript {...} allprojects {...} apply from: 'relative/path/to/dependencies.gradle'
  9. 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" }
  10. 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" }
  11. 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" }
  12. • Managing/updating versions of dependencies is now easier - just

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

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

    will find a lot of repetitions in the dependencies
  15. #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 }
  16. #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 }
  17. #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 }
  18. #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 }
  19. #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
  20. 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' }
  21. 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 }
  22. 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 }
  23. 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 }
  24. 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 }
  25. #2

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

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

  28. #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 {...} }
  29. #2 // <login> build.gradle android { compileSdkVersion sdk.compileSdkVersion buildToolsVersion sdk.buildToolsVersion

    defaultConfig {...} buildTypes { debug { minifyEnabled ... proguardFiles ... } release { minifyEnabled ... proguardFiles ... } } }
  30. #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 {...} }
  31. #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 {...} }
  32. #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
  33. 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:
  34. 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" ...
  35. • 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:
  36. Why Kotlin DSL? • Kotlin is now really popular •

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

    complex build related logic - like plugins, custom tasks, etc.
  39. 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
  40. 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" } ... }
  41. 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" } ... }
  42. 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 ... }
  43. 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” ✅
  44. 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
  45. // settings.gradle include ':app', ':data', ':domain' // settings.gradle.kts include(":app", ":data",

    ":domain") ’:app’ becomes “:app” include becomes include()
  46. // 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" }
  47. // 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") }
  48. 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" }
  49. 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" }
  50. 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" }
  51. 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" }
  52. 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" }
  53. 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" }
  54. 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" }
  55. 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") }
  56. // 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") }
  57. // 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() } }
  58. // 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() } }
  59. // 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?
  60. 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() } }
  61. // 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?
  62. // 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?
  63. // 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() } }
  64. Custom Gradle Plugin • We could use a custom plugin

    to apply common configuration across multiple modules
  65. 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) } } } } } }
  66. 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) } } } } } }
  67. 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) } } } } } }
  68. 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 } } ... }
  69. 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>() ...
  70. Current pain points with Kotlin DSL • IDE support is

    not yet at • Additional configuration time in your build process
  71. 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)
  72. 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
  73. Final words • Keep it DRY (Don’t Repeat Yourself) -

    rule of three applies here • Modular code rocks
  74. 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