Android / Kotlin / Programming

dependenciesを一元管理する方法 – Android Kotlin

はじめに

前回の記事でbuildSrcの作成方法を解説しました。
buildSrcを用いてdependenciesを一元的に管理する方法を、これらを例にご紹介します。

・androidx.activity:activity-compose:1.6.1
----
・androidx.compose:compose-bom:2023.03.00
・androidx.compose.ui:ui
・androidx.compose.ui:ui-graphics
・androidx.compose.ui:ui-tooling-preview
・androidx.compose.material3:material3
----
group(前回作ったモジュール)

主要なファイルの構成内容はこのようになります。

// ここより上は変更なし

dependencies {

    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
    
//    implementation("androidx.activity:activity-compose:1.8.1")
    activityCompose()
    
//    implementation(platform("androidx.compose:compose-bom:2023.03.00"))
//    implementation("androidx.compose.ui:ui")
//    implementation("androidx.compose.ui:ui-graphics")
//    implementation("androidx.compose.ui:ui-tooling-preview")
//    implementation("androidx.compose.material3:material3")
//    androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
//    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
//    debugImplementation("androidx.compose.ui:ui-tooling")
//    debugImplementation("androidx.compose.ui:ui-test-manifest")
    compose()

    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    
    // groupモジュール参照
    group()
}
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.kotlin.dsl.project

object Dependencies {
    const val activityCompose = "androidx.activity:activity-compose:${Versions.activityCompose}"
    const val compose = "androidx.compose:compose-bom:${Versions.composeBom}"
    const val composeUi = "androidx.compose.ui:ui"
    const val composeUiGraphics = "androidx.compose.ui:ui-graphics"
    const val composeUiToolingPreview = "androidx.compose.ui:ui-tooling-preview"
    const val composeMaterial3 = "androidx.compose.material3:material3"
    const val composeUiTest = "androidx.compose.ui:ui-test-junit4"
    const val composeUiTooling = "androidx.compose.ui:ui-tooling"
    const val composeUiManifest = "androidx.compose.ui:ui-test-manifest"
    const val groupModulePath = ":group"
}

fun DependencyHandler.activityCompose() {
    implementation(dependency = Dependencies.activityCompose)
}

fun DependencyHandler.compose() {
    implementation(
        dependency = Dependencies.compose,
        isBom = true
    )
    implementation(dependency = Dependencies.composeUi)
    implementation(dependency = Dependencies.composeUiGraphics)
    implementation(dependency = Dependencies.composeUiToolingPreview)
    implementation(dependency = Dependencies.composeMaterial3)

    androidTestImplementation(
        dependency = Dependencies.compose,
        isBom = true
    )
    androidTestImplementation(dependency = Dependencies.composeUi)
    androidTestImplementation(dependency = Dependencies.composeUiTest)
    debugImplementation(dependency = Dependencies.composeUiTooling)
    debugImplementation(dependency = Dependencies.composeUiManifest)
}

fun DependencyHandler.group() {
    implementation(project(path = Dependencies.groupModulePath))
}
object Versions {
    const val activityCompose = "1.6.1"
    const val composeBom = "2023.03.00"
}
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.dsl.DependencyHandler

fun DependencyHandler.implementation(dependency: String, isBom: Boolean = false) {
    add(
        "implementation",
        if (isBom) platform(dependency) else dependency
    )
}

fun DependencyHandler.implementation(dependency: Dependency) {
    add("implementation", dependency)
}

fun DependencyHandler.testImplementation(dependency: String) {
    add("testImplementation", dependency)
}

fun DependencyHandler.androidTestImplementation(dependency: String, isBom: Boolean = false) {
    add(
        "androidTestImplementation",
        if (isBom) platform(dependency) else dependency
    )
}

fun DependencyHandler.debugImplementation(dependency: String) {
    add("debugImplementation", dependency)
}

fun DependencyHandler.kapt(dependency: String) {
    add("kapt", dependency)
}

一元管理ができるようになると、build.gradle.kts(:app)ではDependencies.ktの下部にある拡張関数を用いて依存関係を指定できます。
そのためにDependencies.ktではオブジェクトに依存先情報を保存し、下部の拡張関数で依存先をグループ化しています。
Versions.ktからバージョン情報を取得し、拡張関数内で使用している関数はDependencyHandlerExt.ktファイルに記載しているものを使用しています。

一元管理の方法

buildSrcフォルダで右クリックをし、「Directory」を選択します。


表示される選択肢から「src\main\kotlin」をクリックし、エンターキーを押下します。


作成したkotlinフォルダを右クリックし、「Kotlin Class/File」を選択します。


ファイル名に「Versions」と入力し、Objectを選択します。


object Versions {
    const val activityCompose = "1.6.1"
    const val composeBom = "2023.03.00"
}

作成されたVersions.ktを上記の通りに編集します。
このオブジェクトで各dependencyのバージョンを管理します。


先ほどと同様に、今度はDependenciesオブジェクトをkotlinフォルダ内に作成し、

import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.kotlin.dsl.project

object Dependencies {
    const val activityCompose = "androidx.activity:activity-compose:${Versions.activityCompose}"
    const val compose = "androidx.compose:compose-bom:${Versions.composeBom}"
    const val composeUi = "androidx.compose.ui:ui"
    const val composeUiGraphics = "androidx.compose.ui:ui-graphics"
    const val composeUiToolingPreview = "androidx.compose.ui:ui-tooling-preview"
    const val composeMaterial3 = "androidx.compose.material3:material3"
    const val composeUiTest = "androidx.compose.ui:ui-test-junit4"
    const val composeUiTooling = "androidx.compose.ui:ui-tooling"
    const val composeUiManifest = "androidx.compose.ui:ui-test-manifest"
}

fun DependencyHandler.activityCompose() {
    implementation(dependency = Dependencies.activityCompose)
}

fun DependencyHandler.compose() {
    implementation(
        dependency = Dependencies.compose,
        isBom = true
    )
    implementation(dependency = Dependencies.composeUi)
    implementation(dependency = Dependencies.composeUiGraphics)
    implementation(dependency = Dependencies.composeUiToolingPreview)
    implementation(dependency = Dependencies.composeMaterial3)

    androidTestImplementation(
        dependency = Dependencies.compose,
        isBom = true
    )
    androidTestImplementation(dependency = Dependencies.composeUi)
    androidTestImplementation(dependency = Dependencies.composeUiTest)
    debugImplementation(dependency = Dependencies.composeUiTooling)
    debugImplementation(dependency = Dependencies.composeUiManifest)
}

fun DependencyHandler.group() {
    implementation(project(path = Dependencies.groupModulePath))
}

上記の通りに編集します。
このオブジェクトで実際の文字列の管理とグループ化を行っています。


buildSrcフォルダ直下のbuild.gradle.ktsファイルを

plugins {
    `kotlin-dsl`
}

repositories {
    google()
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10")
    implementation("com.android.tools.build:gradle:8.0.0")
}

このように編集します。


// Top-level build file where you can add configuration options common to all sub-projects/modules.
//plugins {
//    id("com.android.application") version "8.1.3" apply false
//    id("org.jetbrains.kotlin.android") version "1.8.10" apply false
//    id("com.android.library") version "8.1.3" apply false
//}

プロジェクトフォルダ直下のbuild.gradle.ktsファイルの中身をすべて消去するか、コメントアウトし、「Sync Now」をクリックします。


同期が問題なく終了した後に、先ほどのkotlinフォルダ内に「DependencyHandlerExt」kotlinファイル(名前は任意)を作成し、

import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.dsl.DependencyHandler

fun DependencyHandler.implementation(dependency: String, isBom: Boolean = false) {
    add(
        "implementation",
        if (isBom) platform(dependency) else dependency
    )
}

fun DependencyHandler.implementation(dependency: Dependency) {
    add("implementation", dependency)
}

fun DependencyHandler.testImplementation(dependency: String) {
    add("testImplementation", dependency)
}

fun DependencyHandler.androidTestImplementation(dependency: String, isBom: Boolean = false) {
    add(
        "androidTestImplementation",
        if (isBom) platform(dependency) else dependency
    )
}

fun DependencyHandler.debugImplementation(dependency: String) {
    add("debugImplementation", dependency)
}

fun DependencyHandler.kapt(dependency: String) {
    add("kapt", dependency)
}

このように書き換えます。
先ほどのDependencies.ktファイルに作成したグループ化のための関数内で使用している関数は、このファイルの関数を使用しています。



dependencies {

    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
    
//    implementation("androidx.activity:activity-compose:1.8.1")
    activityCompose()
    
//    implementation(platform("androidx.compose:compose-bom:2023.03.00"))
//    implementation("androidx.compose.ui:ui")
//    implementation("androidx.compose.ui:ui-graphics")
//    implementation("androidx.compose.ui:ui-tooling-preview")
//    implementation("androidx.compose.material3:material3")
//    androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
//    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
//    debugImplementation("androidx.compose.ui:ui-tooling")
//    debugImplementation("androidx.compose.ui:ui-test-manifest")
    compose()

    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    
    // groupモジュール参照
    group()
}

appフォルダの直下にある「build.gradle.kts」のdependeciesの部分をこのように書き換え、同期します。

これで同期とビルドが問題なくできると思います。

おわりに

今回はdependenciesを一元管理することで、重複をなくし、各モジュールのgradleのdependenciesをすっきりさせました。
次回はdependencies{~~~}の上にある、plugins{~~~}とandroid{~~~}も一元管理し、すっきりさせようと思います。
こちらで解説しています。

参考

Dependency Management in a Multi-Module Project – THIS Is How You Need to Do It (YouTube)

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です