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

Managing Multi-module Android Project with Gradle Plugin and Kotlin

Managing Multi-module Android Project with Gradle Plugin and Kotlin

In this talk, I will discuss how the Gradle plugin works, and how we can write a custom plugin in Kotlin to help us manage an Android multi-module project. I will also present techniques to provide custom configurations in our Gradle plugin so that we can modify our build depending on the module, and further, extend the plugin's capabilities by integrating it with other Gradle plugins; e.g., Jacoco plugin. Lastly, I will share our experience of building a Gradle plugin and explore the benefits and limitations that I've encountered.

Malvin Sutanto

December 15, 2020
Tweet

More Decks by Malvin Sutanto

Other Decks in Programming

Transcript

  1. ©2020 Wantedly, Inc.
    Managing Multi-module Project
    with Gradle Plugin and Kotlin
    .droidcon APAC 2020
    15 Dec 2020 - Malvin Sutanto
    Photo by Jan Antonin Kolar on Unsplash

    View Slide

  2. ©2020 Wantedly, Inc.
    Introduction
    Malvin Sutanto
    Software Engineer - Android
    Twitter/ Medium: @malvinsutanto

    View Slide

  3. ©2020 Wantedly, Inc.
    Multi module setup
    in Android projects

    View Slide

  4. ©2020 Wantedly, Inc.
    BQQ
    MJCOBWJHBUJPO
    QSFGFSFODFT
    MJCBOBMZUJDT
    EBUB
    OFUXPSL
    GFBUVSFTFBSDI
    GFBUVSFVTFS
    Multi module setup in Android

    View Slide

  5. ©2020 Wantedly, Inc.
    BQQ
    MJCOBWJHBUJPO
    QSFGFSFODFT
    MJCBOBMZUJDT
    EBUB OFUXPSL
    GFBUVSFTFBSDI
    GFBUVSFVTFS
    Multi module setup in Android

    View Slide

  6. ©2020 Wantedly, Inc.
    Multi module setup in Android

    View Slide

  7. ©2020 Wantedly, Inc.
    Multi module setup in Android
    • Faster build time

    View Slide

  8. ©2020 Wantedly, Inc.
    Multi module setup in Android
    • Faster build time
    • Easier to manage and work with

    View Slide

  9. ©2020 Wantedly, Inc.
    Multi module setup in Android
    • Faster build time
    • Easier to manage and work with
    • New features
    • Instant apps
    • Dynamic feature modules

    View Slide

  10. ©2020 Wantedly, Inc.
    Multi module setup in Android

    View Slide

  11. ©2020 Wantedly, Inc.
    However
    Multi module setup in Android

    View Slide

  12. ©2020 Wantedly, Inc.
    Multi module setup in Android

    View Slide

  13. ©2020 Wantedly, Inc.
    • Each module need a build.gradle file
    Multi module setup in Android

    View Slide

  14. ©2020 Wantedly, Inc.
    • Each module need a build.gradle file
    • Duplicate build script across modules
    Multi module setup in Android

    View Slide

  15. ©2020 Wantedly, Inc.
    • Each module need a build.gradle file
    • Duplicate build script across modules
    • Build files became hard to maintain
    Multi module setup in Android

    View Slide

  16. ©2020 Wantedly, Inc.
    build.gradle file
    for a library module
    Multi module setup in Android
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }

    View Slide

  17. ©2020 Wantedly, Inc.
    build.gradle file
    for a library module
    Multi module setup in Android
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    • Declares Gradle plugins
    • Sets build parameters
    • Declares dependencies

    View Slide

  18. ©2020 Wantedly, Inc.
    Gradle plugin
    Simplifies build scripts

    View Slide

  19. ©2020 Wantedly, Inc.
    What is Gradle?

    View Slide

  20. ©2020 Wantedly, Inc.
    What is Gradle?

    View Slide

  21. ©2020 Wantedly, Inc.
    What is Gradle?
    • “Generic” build automation tool

    View Slide

  22. ©2020 Wantedly, Inc.
    What is Gradle?
    • “Generic” build automation tool
    • Declares input and output files

    View Slide

  23. ©2020 Wantedly, Inc.
    What is Gradle?
    • “Generic” build automation tool
    • Declares input and output files
    • Tasks as its core

    View Slide

  24. ©2020 Wantedly, Inc.
    Gradle Build phases
    Gradle build phases

    View Slide

  25. ©2020 Wantedly, Inc.
    Gradle Build phases
    Gradle build phases
    *OJUJBMJ[BUJPO

    View Slide

  26. ©2020 Wantedly, Inc.
    Gradle Build phases
    Gradle build phases
    *OJUJBMJ[BUJPO $POpHVSBUJPO

    View Slide

  27. ©2020 Wantedly, Inc.
    Gradle Build phases
    Gradle build phases
    *OJUJBMJ[BUJPO $POpHVSBUJPO &YFDVUJPO

    View Slide

  28. ©2020 Wantedly, Inc.
    build.gradle file
    Domain Specific Language (DSL)
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    • Configuration file
    • Describes build steps
    • Available in Groovy and Kotlin
    Gradle Build.gradle file

    View Slide

  29. ©2020 Wantedly, Inc.
    build.gradle file
    Domain Specific Language (DSL)
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    • Configuration file
    • Describes build steps
    • Available in Groovy and Kotlin
    Extension block
    Gradle Build.gradle file

    View Slide

  30. ©2020 Wantedly, Inc.
    build.gradle file
    Domain Specific Language (DSL)
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    • Configuration file
    • Describes build steps
    • Available in Groovy and Kotlin
    Gradle plugins
    Extension block
    Gradle Build.gradle file

    View Slide

  31. ©2020 Wantedly, Inc.
    Gradle plugin

    View Slide

  32. ©2020 Wantedly, Inc.
    Gradle Plugin

    View Slide

  33. ©2020 Wantedly, Inc.
    Gradle Plugin
    • Extends the Gradle model
    • Adds new configuration block and options

    View Slide

  34. ©2020 Wantedly, Inc.
    Gradle Plugin
    • Extends the Gradle model
    • Adds new configuration block and options
    • Configures project according conventions
    • Adds new tasks
    • Configures sensible defaults

    View Slide

  35. ©2020 Wantedly, Inc.
    Gradle Plugin
    • Extends the Gradle model
    • Adds new configuration block and options
    • Configures project according conventions
    • Adds new tasks
    • Configures sensible defaults
    • Applies specific configuration
    • Enforces standards

    View Slide

  36. ©2020 Wantedly, Inc.
    Types of Gradle Plugin
    Gradle Plugin

    View Slide

  37. ©2020 Wantedly, Inc.
    Script plugin
    • Additional build script that is located separately.
    • Can exist in local filesystem or remote location.
    • Multiple script plugins can be applied.
    • apply from: 'other.gradle'
    Types of Gradle Plugin
    Gradle Plugin

    View Slide

  38. ©2020 Wantedly, Inc.
    Script plugin
    • Additional build script that is located separately.
    • Can exist in local filesystem or remote location.
    • Multiple script plugins can be applied.
    • apply from: 'other.gradle'
    Binary plugin
    • Written programmatically by implementing
    Plugin interface,
    • Applied using unique plugin id
    • plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    Types of Gradle Plugin
    Gradle Plugin

    View Slide

  39. ©2020 Wantedly, Inc.
    Script plugin
    • Additional build script that is located separately.
    • Can exist in local filesystem or remote location.
    • Multiple script plugins can be applied.
    • apply from: 'other.gradle'
    Binary plugin
    • Written programmatically by implementing
    Plugin interface,
    • Applied using unique plugin id
    • plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    Types of Gradle Plugin
    Gradle Plugin

    View Slide

  40. ©2020 Wantedly, Inc.
    Creating a Gradle Plugin

    View Slide

  41. ©2020 Wantedly, Inc.
    Gradle Plugin

    View Slide

  42. ©2020 Wantedly, Inc.
    What will the plugin do?
    Gradle Plugin

    View Slide

  43. ©2020 Wantedly, Inc.
    What will the plugin do?
    For each module, it will:
    Gradle Plugin

    View Slide

  44. ©2020 Wantedly, Inc.
    What will the plugin do?
    Gradle Plugin

    View Slide

  45. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    What will the plugin do?
    Gradle Plugin

    View Slide

  46. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    What will the plugin do?
    Gradle Plugin

    View Slide

  47. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    What will the plugin do?
    Gradle Plugin

    View Slide

  48. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    What will the plugin do?
    Gradle Plugin

    View Slide

  49. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    What will the plugin do?
    Gradle Plugin

    View Slide

  50. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    • Configure Jacoco and custom extensions
    What will the plugin do?
    Gradle Plugin

    View Slide

  51. ©2020 Wantedly, Inc.
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  52. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library") // or .application
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName("debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  53. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library") // or .application
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName(“debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  54. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library") // or .application
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName(“debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  55. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library") // or .application
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName(“debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  56. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library") // or .application
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName(“debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  57. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library")
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName(“debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  58. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library")
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName(“debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  59. ©2020 Wantedly, Inc.
    Gradle plugin
    Setup

    View Slide

  60. ©2020 Wantedly, Inc.
    my-project/
    - buildSrc/
    - build.gradle.kts
    - src/main/kotlin/com/mypackage/
    - MyCustomPlugin.kt
    - app/
    - my-lib/
    Project Structure
    Gradle Plugin

    View Slide

  61. ©2020 Wantedly, Inc.
    my-project/
    - buildSrc/
    - build.gradle.kts
    - src/main/kotlin/com/mypackage
    - MyCustomPlugin.kt
    - app/
    - my-lib/
    Project Structure
    Gradle Plugin

    View Slide

  62. ©2020 Wantedly, Inc.
    buildSrc/src/build.gradle.kts
    plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    }
    repositories {
    google()
    mavenCentral()
    }
    dependencies {
    implementation("com.android.tools.build:gradle:$agpVersion")
    implementation(kotlin("gradle-plugin"))
    }
    Gradle Plugin

    View Slide

  63. ©2020 Wantedly, Inc.
    plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    }
    repositories {
    google()
    mavenCentral()
    }
    dependencies {
    implementation("com.android.tools.build:gradle:$agpVersion")
    implementation(kotlin("gradle-plugin"))
    }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  64. ©2020 Wantedly, Inc.
    plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    }
    repositories {
    google()
    mavenCentral()
    }
    dependencies {
    implementation("com.android.tools.build:gradle:$agpVersion")
    implementation(kotlin("gradle-plugin"))
    }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  65. ©2020 Wantedly, Inc.
    plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    }
    repositories {
    google()
    mavenCentral()
    }
    dependencies {
    implementation("com.android.tools.build:gradle:$agpVersion")
    implementation(kotlin("gradle-plugin"))
    }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  66. ©2020 Wantedly, Inc.
    plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    }
    repositories {
    google()
    mavenCentral()
    }
    dependencies {
    implementation("com.android.tools.build:gradle:$agpVersion")
    implementation(kotlin("gradle-plugin"))
    }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  67. ©2020 Wantedly, Inc.
    plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    }
    repositories {
    google()
    mavenCentral()
    }
    dependencies {
    implementation("com.android.tools.build:gradle:$agpVersion")
    implementation(kotlin("gradle-plugin"))
    }
    https://android-developers.googleblog.com/2020/12/announcing-android-studio-arctic-fox.html
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  68. ©2020 Wantedly, Inc.
    my-project/
    - buildSrc/
    - build.gradle.kts
    - src/main/kotlin/com/mypackage/
    - MyCustomPlugin.kt
    - app/
    - my-lib/
    Project Structure
    Gradle Plugin

    View Slide

  69. ©2020 Wantedly, Inc.
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  70. ©2020 Wantedly, Inc.
    Gradle Plugin
    class MyCustomPlugin : Plugin {
    buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  71. ©2020 Wantedly, Inc.
    Gradle Plugin
    class MyCustomPlugin : Plugin {
    Module
    buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  72. ©2020 Wantedly, Inc.
    Gradle Plugin
    class MyCustomPlugin : Plugin {
    override fun apply(project: Project) {
    // TODO: Write build configurations here.
    }
    }
    Module
    buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  73. ©2020 Wantedly, Inc.
    Gradle plugin
    Implementation

    View Slide

  74. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    • Configure Jacoco and custom extensions
    What will the plugin do?
    Gradle Plugin

    View Slide

  75. ©2020 Wantedly, Inc.
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  76. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  77. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    project.plugins.apply("kotlin-android")
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  78. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    project.plugins.apply("kotlin-android")
    }
    Plugin id
    // build.gradle
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  79. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    • Configure Jacoco and custom extensions
    What will the plugin do?
    Gradle Plugin

    View Slide

  80. ©2020 Wantedly, Inc.
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  81. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    }
    }
    private fun BaseExtension.applyAndroidSettings() {
    compileSdkVersion(30)
    defaultConfig {
    targetSdkVersion(30)
    minSdkVersion(23)
    // etc.
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  82. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    }
    }
    private fun BaseExtension.applyAndroidSettings() {
    compileSdkVersion(30)
    defaultConfig {
    targetSdkVersion(30)
    minSdkVersion(23)
    // etc.
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  83. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    }
    }
    private fun BaseExtension.applyAndroidSettings() {
    compileSdkVersion(30)
    defaultConfig {
    targetSdkVersion(30)
    minSdkVersion(23)
    // etc.
    }
    }
    // build.gradle
    android {
    compileSdkVersion 30
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  84. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    }
    }
    private fun BaseExtension.applyAndroidSettings() {
    compileSdkVersion(30)
    defaultConfig {
    targetSdkVersion(30)
    minSdkVersion(23)
    // etc.
    }
    }
    // build.gradle
    android {
    compileSdkVersion 30
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  85. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    }
    }
    private fun BaseExtension.applyAndroidSettings() {
    compileSdkVersion(30)
    defaultConfig {
    targetSdkVersion(30)
    minSdkVersion(23)
    // etc.
    }
    }
    // build.gradle
    android {
    compileSdkVersion 30
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    }
    }
    Base class for all Android plugin extension classes
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  86. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    }
    }
    private fun BaseExtension.applyAndroidSettings() {
    compileSdkVersion(30)
    defaultConfig {
    targetSdkVersion(30)
    minSdkVersion(23)
    // etc.
    }
    }
    // build.gradle
    android {
    compileSdkVersion 30
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  87. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    }
    }
    private fun BaseExtension.applyAndroidSettings() {
    compileSdkVersion(30)
    defaultConfig {
    targetSdkVersion(30)
    minSdkVersion(23)
    // etc.
    }
    }
    // build.gradle
    android {
    compileSdkVersion 30
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  88. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    • Configure Jacoco and custom extensions
    What will the plugin do?
    Gradle Plugin

    View Slide

  89. ©2020 Wantedly, Inc.
    Types of plugin
    Gradle Plugin

    View Slide

  90. ©2020 Wantedly, Inc.
    Application module Library module
    id("com.android.application") id("com.android.library")
    Types of plugin
    Gradle Plugin

    View Slide

  91. ©2020 Wantedly, Inc.
    Application module
    • Set isMinifyEnabled only on release
    Library module
    id("com.android.application") id("com.android.library")
    Types of plugin
    Gradle Plugin

    View Slide

  92. ©2020 Wantedly, Inc.
    Application module
    • Set isMinifyEnabled only on release
    • Specify proguard files using proguardFiles()
    Library module
    id("com.android.application") id("com.android.library")
    Types of plugin
    Gradle Plugin

    View Slide

  93. ©2020 Wantedly, Inc.
    Application module
    • Set isMinifyEnabled only on release
    • Specify proguard files using proguardFiles()
    Library module
    • Specify proguard files using
    consumerProguardFiles()
    id("com.android.application") id("com.android.library")
    Types of plugin
    Gradle Plugin

    View Slide

  94. ©2020 Wantedly, Inc.
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  95. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName(“android")
    if (androidExtension is BaseExtension) {
    androidExtension.applyAndroidSettings()
    androidExtension.applyProguardSettings()
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  96. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  97. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  98. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    proguard-rules.pro files in each module’s root
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  99. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  100. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    // build.gradle
    plugins {
    id 'com.android.library'
    id 'my-custom-plugin-id'
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  101. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    // build.gradle
    plugins {
    id 'com.android.library'
    id 'my-custom-plugin-id'
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  102. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    // build.gradle
    plugins {
    id 'com.android.library'
    id 'my-custom-plugin-id'
    }
    // build.gradle
    android {
    defaultConfig {
    ...
    consumerProguardFiles "proguard-rules.pro"
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  103. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  104. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    // build.gradle
    plugins {
    id 'com.android.application'
    id 'my-custom-plugin-id'
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  105. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    Enable obfuscation only on "release" build
    // build.gradle
    plugins {
    id 'com.android.application'
    id 'my-custom-plugin-id'
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  106. ©2020 Wantedly, Inc.
    private fun BaseExtension.applyProguardSettings() {
    val proguardFile = "proguard-rules.pro"
    when (this) {
    is LibraryExtension -> defaultConfig {
    consumerProguardFiles(proguardFile)
    }
    is AppExtension -> buildTypes {
    getByName("release") {
    isMinifyEnabled = true
    isShrinkResources = true
    proguardFiles(
    getDefaultProguardFile("proguard-android-optimize.txt"),
    proguardFile
    )
    }
    }
    }
    }
    Enable obfuscation only on "release" build
    // build.gradle
    plugins {
    id 'com.android.application'
    id 'my-custom-plugin-id'
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  107. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    • Configure Jacoco and custom extensions
    What will the plugin do?
    Gradle Plugin

    View Slide

  108. ©2020 Wantedly, Inc.
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  109. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {

    val androidExtension = project.extensions.getByName("android")
    if (androidExtension is BaseExtension) {
    ...
    androidExtension.enableJava8(project)
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  110. ©2020 Wantedly, Inc.
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  111. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.tasks.withType().configureEach {
    kotlinOptions {
    jvmTarget = "1.8"
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  112. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.tasks.withType().configureEach {
    kotlinOptions {
    jvmTarget = "1.8"
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  113. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.tasks.withType().configureEach {
    kotlinOptions {
    jvmTarget = "1.8"
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  114. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.tasks.withType().configureEach {
    kotlinOptions {
    jvmTarget = "1.8"
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  115. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.tasks.withType().configureEach {
    kotlinOptions {
    jvmTarget = "1.8"
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  116. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.tasks.withType().configureEach {
    kotlinOptions {
    jvmTarget = "1.8"
    }
    }
    }
    Java 8 core library desugaring
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  117. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    • Configure Jacoco and custom extensions
    What will the plugin do?
    Gradle Plugin

    View Slide

  118. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.dependencies {
    add("coreLibraryDesugaring", "com.android.tools:desugar_jdk_libs:1.0.9")
    }
    ...
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  119. ©2020 Wantedly, Inc.
    private fun BaseExtension.enableJava8(project: Project) {
    compileOptions {
    isCoreLibraryDesugaringEnabled = true
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    }
    project.dependencies {
    add("coreLibraryDesugaring", "com.android.tools:desugar_jdk_libs:1.0.9")
    }
    ...
    } Configuration name
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  120. ©2020 Wantedly, Inc.
    project.dependencies {
    add("implementation", "androidx.core:core-ktx:1.2.0")
    add("testImplementation", "junit:junit:4.12")
    add("androidTestImplementation", "androidx.test.ext:junit:1.1.1")
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  121. ©2020 Wantedly, Inc.
    • Apply other Gradle plugins
    • Set common build parameters
    • Specify default proguard files
    • Enable Java 8 features
    • Declare dependencies
    • Configure Jacoco and custom extensions
    What will the plugin do?
    Gradle Plugin

    View Slide

  122. ©2020 Wantedly, Inc.
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  123. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library") // or .application
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName("debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  124. ©2020 Wantedly, Inc.
    plugins {
    id("com.android.library") // or .application
    id("my-custom-plugin-id")
    }
    android {
    buildTypes {
    getByName("debug") {
    isTestCoverageEnabled = true
    }
    }
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    dependencies { … }
    my-lib/build.gradle.kts
    Gradle Plugin

    View Slide

  125. ©2020 Wantedly, Inc.
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  126. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    project.extensions.create("myPluginOptions")

    if (androidExtension is BaseExtension) {

    androidExtension.configureJacoco(project)
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  127. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    project.extensions.create("myPluginOptions")

    if (androidExtension is BaseExtension) {

    androidExtension.configureJacoco(project)
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  128. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    project.extensions.create("myPluginOptions")

    if (androidExtension is BaseExtension) {

    androidExtension.configureJacoco(project)
    }
    }
    Extension class
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  129. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    project.extensions.create("myPluginOptions")

    if (androidExtension is BaseExtension) {

    androidExtension.configureJacoco(project)
    }
    }
    Extension class
    // build.gradle.kts
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  130. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  131. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  132. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  133. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  134. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  135. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  136. ©2020 Wantedly, Inc.
    // build.gradle.kts
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    } // build.gradle
    myPluginOptions {
    jacoco {
    enabled true
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  137. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    // build.gradle.kts
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  138. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    // build.gradle.kts
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  139. ©2020 Wantedly, Inc.
    open class MyPluginOptionExtension {
    val jacoco: JacocoOptions = JacocoOptions()
    fun jacoco(action: Action) {
    action.execute(jacoco)
    }
    }
    class JacocoOptions {
    var isEnabled: Boolean = true
    }
    // build.gradle.kts
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    https://docs.gradle.org/current/userguide/custom_gradle_types.html
    https://docs.gradle.org/current/userguide/lazy_configuration.html#lazy_configuration
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyPluginOptionExtension.kt

    View Slide

  140. ©2020 Wantedly, Inc.
    override fun apply(project: Project) {
    project.extensions.create("myPluginOptions")

    if (androidExtension is BaseExtension) {

    androidExtension.configureJacoco(project)
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  141. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  142. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  143. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  144. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  145. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    // build.gradle.kts
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  146. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  147. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  148. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  149. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    "debug"
    "release"
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  150. ©2020 Wantedly, Inc.
    private fun BaseExtension.configureJacoco(project: Project) {
    project.afterEvaluate {
    val jacocoOptions = project.extensions.getByType()
    .jacoco
    if (jacocoOptions.isEnabled) {
    project.plugins.apply("jacoco")
    when (this@configureJacoco) {
    is LibraryExtension -> configureJacocoTasks(project, libraryVariants)
    is AppExtension -> configureJacocoTasks(project, applicationVariants)
    }
    }
    }
    }
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) { ... }
    "debug"
    "release"
    "debug"
    "release"
    "flavorDebug"
    "flavorRelease"
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  151. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  152. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  153. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  154. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    Skip non-debuggable builds
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  155. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  156. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  157. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    "debug"
    "release"
    "flavorDebug"
    "flavorRelease"
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  158. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    "debug"
    "release"
    "flavorDebug"
    "flavorRelease"
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  159. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    ./gradlew :lib:jacocoDebugReport
    ./gradlew :app:jacocoFlavorDebugReport
    "debug"
    "release"
    "flavorDebug"
    "flavorRelease"
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  160. ©2020 Wantedly, Inc.
    private fun configureJacocoTasks(
    project: Project,
    variants: DomainObjectSet
    ) {
    variants.all {
    val variantName = name
    val isDebuggable = buildType.isDebuggable
    if (!isDebuggable) return@all
    project.tasks.register("jacoco${variantName.capitalize()}Report") {
    // Set up the rest of the Jacoco tasks dependency, exec files, etc.
    }
    }
    }
    Gradle Plugin buildSrc/src/main/kotlin/com/mypackage/MyCustomPlugin.kt

    View Slide

  161. ©2020 Wantedly, Inc.
    Apply Gradle plugin
    on other modules

    View Slide

  162. ©2020 Wantedly, Inc.
    plugins { ... }
    gradlePlugin {
    plugins {
    register("my-custom-plugin") {
    id = "my-custom-plugin-id"
    implementationClass = "com.mypackage.MyCustomPlugin"
    }
    }
    }
    repositories { ... }
    dependencies { ... }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  163. ©2020 Wantedly, Inc.
    plugins { ... }
    gradlePlugin {
    plugins {
    register("my-custom-plugin") {
    id = "my-custom-plugin-id"
    implementationClass = "com.mypackage.MyCustomPlugin"
    }
    }
    }
    repositories { ... }
    dependencies { ... }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  164. ©2020 Wantedly, Inc.
    plugins { ... }
    gradlePlugin {
    plugins {
    register("my-custom-plugin") {
    id = "my-custom-plugin-id"
    implementationClass = "com.mypackage.MyCustomPlugin"
    }
    }
    }
    repositories { ... }
    dependencies { ... }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  165. ©2020 Wantedly, Inc.
    plugins { ... }
    gradlePlugin {
    plugins {
    register("my-custom-plugin") {
    id = "my-custom-plugin-id"
    implementationClass = "com.mypackage.MyCustomPlugin"
    }
    }
    }
    repositories { ... }
    dependencies { ... }
    // lib/build.gradle.kts
    plugins {
    id("com.android.library")
    id("my-custom-plugin-id")
    }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  166. ©2020 Wantedly, Inc.
    plugins { ... }
    gradlePlugin {
    plugins {
    register("my-custom-plugin") {
    id = "my-custom-plugin-id"
    implementationClass = "com.mypackage.MyCustomPlugin"
    }
    }
    }
    repositories { ... }
    dependencies { ... }
    // lib/build.gradle.kts
    plugins {
    id("com.android.library")
    id("my-custom-plugin-id")
    }
    class MyCustomPlugin : Plugin { ... }
    buildSrc/src/build.gradle.kts
    Gradle Plugin

    View Slide

  167. ©2020 Wantedly, Inc.
    Gradle plugin
    Benefits

    View Slide

  168. ©2020 Wantedly, Inc.
    Benefits
    Gradle Plugin

    View Slide

  169. ©2020 Wantedly, Inc.
    Benefits
    • Share build logic across modules
    • Reduce maintenance cost when updating build scripts
    Gradle Plugin

    View Slide

  170. ©2020 Wantedly, Inc.
    Benefits
    • Share build logic across modules
    • Reduce maintenance cost when updating build scripts
    • Higher degree of modularization
    • Better organization and comprehensibility
    Gradle Plugin

    View Slide

  171. ©2020 Wantedly, Inc.
    Benefits
    • Share build logic across modules
    • Reduce maintenance cost when updating build scripts
    • Higher degree of modularization
    • Better organization and comprehensibility
    • Encapsulates logic
    • Declarative build scripts
    • Automatically configures tasks and its dependencies
    Gradle Plugin

    View Slide

  172. ©2020 Wantedly, Inc.
    Our experience
    Gradle Plugin

    View Slide

  173. ©2020 Wantedly, Inc.
    • Helped migration to build.gradle.kts
    Our experience
    Gradle Plugin

    View Slide

  174. ©2020 Wantedly, Inc.
    • Helped migration to build.gradle.kts
    • Make use of Gradle API
    • Apply Gradle plugin to build.gradle files written in Groovy
    Our experience
    Gradle Plugin

    View Slide

  175. ©2020 Wantedly, Inc.
    • Helped migration to build.gradle.kts
    • Make use of Gradle API
    • Apply Gradle plugin to build.gradle files written in Groovy
    • Gradually migrate to Kotlin build.gradle.kts files
    Our experience
    Gradle Plugin

    View Slide

  176. ©2020 Wantedly, Inc.
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    Our experience
    Gradle Plugin

    View Slide

  177. ©2020 Wantedly, Inc.
    plugins {
    id 'com.android.library'
    id 'kotlin-android'
    }
    android {
    compileSdkVersion 30
    buildToolsVersion "30.0.2"
    defaultConfig {
    minSdkVersion 23
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
    'proguard-rules.pro'
    }
    }
    compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
    jvmTarget = '1.8'
    }
    }
    dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'com.google.android.material:material:1.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    }
    // build.gradle
    plugin {
    id 'com.android.library'
    id 'my-custom-plugin-id'
    }
    myPluginOptions {
    jacoco {
    enabled true
    }
    }
    Our experience
    Gradle Plugin

    View Slide

  178. ©2020 Wantedly, Inc.
    // build.gradle
    plugin {
    id 'com.android.library'
    id 'my-custom-plugin-id'
    }
    myPluginOptions {
    jacoco {
    enabled true
    }
    }
    Our experience
    Gradle Plugin

    View Slide

  179. ©2020 Wantedly, Inc.
    // build.gradle
    plugin {
    id 'com.android.library'
    id 'my-custom-plugin-id'
    }
    myPluginOptions {
    jacoco {
    enabled true
    }
    }
    // build.gradle.kts
    plugin {
    id("com.android.library")
    id("my-custom-plugin-id")
    }
    myPluginOptions {
    jacoco {
    isEnabled = true
    }
    }
    Our experience
    Gradle Plugin

    View Slide

  180. ©2020 Wantedly, Inc.
    Our experience
    Gradle Plugin

    View Slide

  181. ©2020 Wantedly, Inc.
    • buildSrc vs standalone plugin
    Our experience
    Gradle Plugin

    View Slide

  182. ©2020 Wantedly, Inc.
    • buildSrc vs standalone plugin
    • Plugin is very specific to each project
    Our experience
    Gradle Plugin

    View Slide

  183. ©2020 Wantedly, Inc.
    • buildSrc vs standalone plugin
    • Plugin is very specific to each project
    • But, split the plugins when necessary depending on its purpose
    • e.g., Jacoco as its own plugin
    Our experience
    Gradle Plugin

    View Slide

  184. ©2020 Wantedly, Inc.
    Summary

    View Slide

  185. ©2020 Wantedly, Inc.
    Summary
    Gradle Plugin

    View Slide

  186. ©2020 Wantedly, Inc.
    Summary
    • Maintaining build.gradle files can be tedious
    Gradle Plugin

    View Slide

  187. ©2020 Wantedly, Inc.
    Summary
    • Maintaining build.gradle files can be tedious
    • Gradle plugin can simplify the maintenance
    process
    Gradle Plugin

    View Slide

  188. ©2020 Wantedly, Inc.
    Summary
    • Maintaining build.gradle files can be tedious
    • Gradle plugin can simplify the maintenance
    process
    • Make Gradle plugin configurable using
    extension
    Gradle Plugin

    View Slide

  189. ©2020 Wantedly, Inc.
    Thank you
    @MalvinSutanto

    View Slide