Androidアプリ開発探求記（その５）

# 概要
今回は、*build.gradle* について探求してみたいと思います。

# やること
*build.gradle* を一通り確認してみようと思います。

# 現行コード

## ◆ build.gradle
[source](https://github.com/beyondseeker/chrono0015/blob/d3cba524c8ac6dcc3b9b393c9fb6fe8645ef1395/build.gradle)

```groovy
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = "1.3.72"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}
```

## ◆ app/build.gradle
[source](https://github.com/beyondseeker/chrono0015/blob/d3cba524c8ac6dcc3b9b393c9fb6fe8645ef1395/app/build.gradle)

```groovy
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29

    defaultConfig {
        applicationId "com.objectfanatics.chrono0015"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.1'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

}
```

# コードを読み解く
一通り内容を確認して、コメントを入れてみます。

考察が必要な個所には `TODO: 要考察` というコメントを入れておきます。

## ◆ build.gradle
[source](https://github.com/beyondseeker/chrono0015/blob/fb3ea176d9f141c51d9cb7266a58200bf7b102ca/build.gradle)

```groovy
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    // 『この位置』でのバージョン情報定義は、結構他の多くのプロジェクトでも踏襲してるっぽい。
    //
    // - mockk(https://github.com/mockk/mockk/blob/master/build.gradle)の場合は結構愚直にやってる。
    //
    // - picasso(https://github.com/square/picasso/blob/master/build.gradle)の場合は
    //   ext.versions = [..] と ext.deps = [..] に分けている。
    //
    // - kotlinpoet(https://github.com/square/kotlinpoet/blob/master/buildSrc/src/main/java/Dependencies.kt)の場合は
    //   buildSrc を利用して version, deps を定義している。picasso の方式を buildSrc に移行しただけっぽい感じですね。
    //
    ext.kotlin_version = "1.3.72"

    // repositories は特に問題無し。
    // https://developer.android.com/studio/build/dependencies#remote-repositories
    repositories {
        google()
        jcenter()
    }
    dependencies {
        // com.android.application plugin 等のために必要。
        // https://developer.android.com/studio/build
        classpath "com.android.tools.build:gradle:4.0.1"


        // kotlin-android plugin 等のために必要。
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

// 全プロジェクトに下記 repositories を適用するのに問題はなさげ。
allprojects {
    // repositories は特に問題無し。
    // https://developer.android.com/studio/build/dependencies#remote-repositories
    repositories {
        google()
        jcenter()
    }
}

// root project には clean という default のタスクは存在しない。
// そのため、この場に clean タスクを記述している。
task clean(type: Delete) {
    delete rootProject.buildDir
}
```

## ◆ app/build.gradle
[source](https://github.com/beyondseeker/chrono0015/blob/fb3ea176d9f141c51d9cb7266a58200bf7b102ca/app/build.gradle)

```groovy
// android の build のために必要
apply plugin: 'com.android.application'

// kotlin で書かれた android project を build するには kotlin-android plugin が必要
// https://kotlinlang.org/docs/reference/using-gradle.html#targeting-android
apply plugin: 'kotlin-android'

// TODO: 要考察(1): org.jetbrains.kotlin:kotlin-stdlib への依存があれば、削除しても動作する。しかし、そうでなければビルド時にエラーになる。
// https://developer.android.com/kotlin/ktx
apply plugin: 'kotlin-android-extensions'

android {
    // お約束なので問題無し。
    compileSdkVersion 29

    // お約束なので問題無し。
    defaultConfig {
        applicationId "com.objectfanatics.chrono0015"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        // JUnit 4 のテストクラス群を利用するため、AndroidJUnitRunner をデフォルトの test instrumentation runner としてセットしている。
        // instrumented unit test とは実機(やエミュレータ)上で実行される unit test のこと。
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    // Androidアプリ開発探求記（その２）で追加した。
    // https://qiita.com/beyondseeker/items/2b1fba123efbab6c04ae#-jdk%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])

    // TODO: 要考察(1): kotlin-android-extensions が利用されていれば、削除しても動作する。しかし、そうでなければビルド時にエラーになる。
    // TODO: jdk8 は要検討。
    // Cannot access built-in declaration 'kotlin.Unit'. Ensure that you have a dependency on the Kotlin standard library
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

    // TODO: 要考察(2): 削除しても動作する。
    // https://developer.android.com/kotlin/ktx
//    implementation 'androidx.core:core-ktx:1.3.1'

    // appcompat は事実上不可欠な存在。Android Studio から生成されたプロジェクト中のコードでも利用されている。
    implementation 'androidx.appcompat:appcompat:1.1.0'

    // constraint layout は事実上不可欠と言っていいと思う。Android Studio から生成されたプロジェクト中のコードでも利用されている。
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    // 通常の unit test から利用される JUnit 4 のクラス群への依存。※ org.junit.Test 等
    testImplementation 'junit:junit:4.12'

    // instrumented unit test から利用される JUnit 4 のクラス群への依存。※ AndroidJUnit4, ActivityScenarioRule 等
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'

    // Espresso testing framework への依存。
    // Espresso testing framework は UI テストのためのフレームワーク。
    // @see https://developer.android.com/training/testing/ui-testing/espresso-testing
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

}
```

# 考察

## 1. kotlinの依存関係

### ☆ 関連コード
**要考察(1)**のコードを以下に抜粋します：

```groovy
// TODO: 要考察(1): org.jetbrains.kotlin:kotlin-stdlib への依存があれば、削除しても動作する。しかし、そうでなければビルド時にエラーになる。
apply plugin: 'kotlin-android-extensions'
dependencies {
    // TODO: 要考察(1): kotlin-android-extensions が利用されていれば、削除しても動作する。しかし、そうでなければビルド時にエラーになる。
    // Cannot access built-in declaration 'kotlin.Unit'. Ensure that you have a dependency on the Kotlin standard library
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
```

### ☆ 依存関係の確認方法
以下のように依存関係を確認してみます。

```
$ ./gradlew app:dependencies --configuration debugCompileClasspath
```

### ☆ 両方削除
kotlin-android-extensions と org.jetbrains.kotlin:kotlin-stdlib 両方の記述を削除した場合は、kotlin 関連の依存は検出されませんでした。

ビルド失敗するのは当然ですね。

### ☆ ライブラリだけ記述
以下のような依存関係が検出されました。(kotlinで行フィルタ)

```
debugCompileClasspath - Compile classpath for compilation 'debug' (target  (androidJvm)).
+--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72
|    +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72
+--- org.jetbrains.kotlin:kotlin-stdlib:{strictly 1.3.72} -> 1.3.72 (c)
+--- org.jetbrains.kotlin:kotlin-stdlib-common:{strictly 1.3.72} -> 1.3.72 (c)
```

### ☆ プラグインだけ記述
以下のような依存関係が検出されました。(kotlinで行フィルタ)

```
debugCompileClasspath - Compile classpath for compilation 'debug' (target  (androidJvm)).
+--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.3.72
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72
|         +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72
|         \--- org.jetbrains:annotations:13.0
+--- org.jetbrains.kotlin:kotlin-stdlib:1.3.72 (*)
+--- androidx.core:core-ktx:1.3.1
|    +--- org.jetbrains.kotlin:kotlin-stdlib:1.3.71 -> 1.3.72 (*)
+--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:{strictly 1.3.72} -> 1.3.72 (c)
+--- org.jetbrains.kotlin:kotlin-stdlib:{strictly 1.3.72} -> 1.3.72 (c)
+--- org.jetbrains.kotlin:kotlin-stdlib-common:{strictly 1.3.72} -> 1.3.72 (c)
```

### ☆ プラグインだけでいいのか？
事足りていて、困らないのであれば、ライブラリ側の記述はなくても実害は無いと思いますし、コードの保守コストが減るというメリットもあるのでプラグインだけ記述するという選択肢もあるかもしれません。しかし、plugin の副作用とも言えるものなので、明示的に指定してあげるのが正しい気がします。

また、jdk8 を指定するような場合は記述が必要ですが、この点に関しては、次回 jdk8 対応することとして、今は放置することにします。

## 2. ktxの依存関係

### ☆ 関連コード
**要考察(2)**のコードを以下に抜粋します：

```groovy
    // TODO: 要考察(2): 削除しても動作する。
    // https://developer.android.com/kotlin/ktx
//    implementation 'androidx.core:core-ktx:1.3.1'
```

### ☆ 考察
普通に ktx のコードを使ってないというだけのことですよね。たぶん。
使うときに追加すればよいということで、削除しちゃうことにします。

# 現時点のコード
[build.gradle](https://github.com/beyondseeker/chrono0015/blob/e2cb85631b5c0aedc05048543669b5f23ba62430/build.gradle)
[app/build.gradle](https://github.com/beyondseeker/chrono0015/blob/e2cb85631b5c0aedc05048543669b5f23ba62430/app/build.gradle)

# まとめ
今回は、build.gradle の内容確認とある程度の整理をしてみました。

次回は、TODO として残された jdk8 対応について考えてみようと思います。