LoginSignup
3
2

N予備校 Android アプリでビルドロジックを buildSrc から Composite Build に移行した話

Last updated at Posted at 2023-08-24

N予備校 Androidチームでテックリードをしている鎌田です。

N予備校 Android チームでは、Version Catalog の導入をきっかけに、ビルドロジックを buildSrc から Composite Build に移行しました。

Version Catalog を導入したことで、buildSrc でバージョン管理する必要がなくなり、buildSrc が不要になったのと、マルチモジュール化しているのでビルド設定を共通化したかったためです。
本記事では、どのように buildSrc から Composite Build に移行したのかについてまとめます。

前提条件

前提条件は下記の通りです。

  • Kotlin DSL であること
  • Version Catalog 導入済みであること
  • buildSrc を使用していること

導入手順

1. toml ファイルに Gradle プラグインを追加しておく

build-logic モジュールを追加する際に使用するため、gradle/libs.versions.toml に Gradle プラグインを追加しておきます。

gradle/libs.versions.toml
[versions]
androidGradlePlugin = "8.1.0"
kotlin = "1.9.0"
...
[libraries]
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" }
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
...

2. build-logic モジュールを追加する

build-logic モジュールを追加します。
build-logic/build.gragle.kts を以下の通り実装します。

build-logic/build.gradle.kts
plugins {
    `kotlin-dsl`
}

dependencies {
    compileOnly(libs.android.gradlePlugin)
    compileOnly(libs.kotlin.gradlePlugin)
}

build-logic モジュールにて プロジェクト名/gradle/libs.versions.toml を参照するため、build-logic/settings.gragle.kts を以下の通り新規で作成します。

build-logic/settings.gragle.kts
dependencyResolutionManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}

rootProject.name = "build-logic"

build-logic モジュールを参照できるよう、settings.gragle.kts に以下を記載します。

settings.gragle.kts
pluginManagement {
    includeBuild("build-logic")
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven(url = "https://jitpack.io")
    }
}
rootProject.name = "プロジェクト名"

上記の各種実装は基本的に Now in Android の実装を参考にしました。

3. buildSrc からの依存を外す

もともと N予備校 Android アプリでは、buildSrc にて各種バージョン情報を以下のように定義し、各モジュールの build.gradle.kts から参照していました。

buildSrc/src/main/java/dependency/Versions.kt
package dependency

object Versions {
    const val compileSdkVersion = 33
    const val minSdkVersion = 26
    const val versionCode = 1
    const val versionName = "1.0.0"
    const val composeCompiler = "1.4.7"
}

以下は app/build.gradle.kts の例です。

app/build.gradle.kts
...
android {
    ...
    compileSdk = dependency.Versions.compileSdkVersion
    ...
    defaultConfig {
        ...
        minSdk = dependency.Versions.minSdkVersion
        targetSdk = dependency.Versions.compileSdkVersion
        versionCode = dependency.Versions.versionCode
        versionName = dependency.Versions.versionName
        ...
    }
    ...
    composeOptions {
        kotlinCompilerExtensionVersion = dependency.Versions.composeCompiler
    }
    ...
}
...
dependencies {
    ...
}

最終的には buildSrc を削除したいため、各種バージョン情報を libs.versions.toml に移行します。

gradle/libs.versions.toml
[versions]
...
composeCompiler = "1.4.7"

# ライブラリ以外のバージョン情報
compileSdkVersion = "33"
minSdkVersion = "26"
versionCode = "1"
versionName = "1.0.0"
...
app/build.gradle.kts
...
android {
    ...
    compileSdk = libs.versions.compileSdkVersion.get().toInt()
    ...
    defaultConfig {
        ...
        minSdk = libs.versions.minSdkVersion.get().toInt()
        targetSdk = libs.versions.compileSdkVersion.get().toInt()
        versionCode = libs.versions.versionCode.get().toInt()
        versionName = libs.versions.versionName.get()
        ...
    }
    ...
    composeOptions {
        kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get()
    }
    ...
}
...
dependencies {
    ...
}

4. Plugin を追加する

一例として、ライブラリモジュール用の Plugin を追加します。

AndroidLibraryPlugin.kt
class AndroidLibraryPlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            with(pluginManager) {
                apply("com.android.library")
                apply("org.jetbrains.kotlin.android")
            }

            extensions.configure<LibraryExtension> {
                configureKotlinAndroid(this)
            }
        }
    }
}

with(pluginManager) ブロックが plugins ブロックにあたり、ここでプラグイン ID を指定します。

with(pluginManager) {
    apply("com.android.library")
    apply("org.jetbrains.kotlin.android")
}

また、他の Plugin でも使用するような共通の設定を以下のようにまとめておくと便利です。
例えば compileSdkminSdk、Java バージョンを共通化するための関数を作成します。

/**
 * Android の build 共通設定を適用する
 */
fun Project.configureKotlinAndroid(
    commonExtension: CommonExtension<*, *, *, *, *>,
) {
    commonExtension.apply {
        compileSdk = libs.version("compileSdkVersion").toInt()
        defaultConfig {
            minSdk = libs.version("minSdkVersion").toInt()
        }

        compileOptions {
            sourceCompatibility = JavaVersion.VERSION_11
            targetCompatibility = JavaVersion.VERSION_11
        }

        tasks.withType<KotlinCompile>().configureEach {
            kotlinOptions {
                jvmTarget = JavaVersion.VERSION_11.toString()
            }
        }
    }
}

/**
 * VersionCatalog の取得
 */
val Project.libs
    get(): VersionCatalog = extensions.getByType<VersionCatalogsExtension>().named("libs")

libs.versions.toml から [versions] の値を参照したい場合、libs.version("compileSdkVersion").toInt() という形で指定します。

5. 追加した Plugin を該当のモジュールに適用する

任意のライブラリモジュールにて、build.gradle.kts の実装が以下の通りだったとします。

build.gradle.kts
plugins {
    id(libs.plugins.android.library.get().pluginId)
    id(libs.plugins.kotlin.android.get().pluginId)
}

android {
    namespace = "sample.library"
    compileSdk = libs.versions.compileSdkVersion.get().toInt()

    defaultConfig {
        minSdk = libs.versions.minSdkVersion.get().toInt()
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles("consumer-rules.pro")
    }
    buildFeatures {
        buildConfig = true
    }
    buildTypes {
        debug {
            isMinifyEnabled = false
        }
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility(JavaVersion.VERSION_11)
        targetCompatibility(JavaVersion.VERSION_11)
    }
    kotlinOptions {
        jvmTarget = "11"
    }
    ...
}

dependencies {
    ...
}

AndroidLibraryPlugin を適用するため、build-logic/build.gradle.kts に以下を記載します。

build-logic/build.gradle.kts
...
gradlePlugin {
    plugins {
        register("androidLibrary") {
            id = "sample.android.library"
            implementationClass = "sample.buildlogic.AndroidLibraryPlugin"
        }
    }
}

register に指定する名前は外部から参照することはないため、識別できれば何でも OK です。
id に参照する際のプラグイン ID、implementationClass に Plugin クラスのパッケージ名およびクラス名を指定します。

そして、任意のライブラリモジュールにて、build.gradle.kts を以下のように書き換えます。

build.gradle.kts
plugins {
    id("sample.android.library")
}

android {
    namespace = "sample.library"

    defaultConfig {
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles("consumer-rules.pro")
    }
    buildFeatures {
        buildConfig = true
    }
    buildTypes {
        debug {
            isMinifyEnabled = false
        }
        release {
            isMinifyEnabled = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    ...
}

dependencies {
    ...
}

AndroidLibraryPlugin を適用したことで、AndroidLibraryPlugin に記載されている内容を削除し、build.gradle.kts を簡略化できました。

導入時のポイント

導入にあたって以下の点を心がけました。

  • 共通化しすぎない
    • 共通化しすぎてしまうと、Plugin の修正時に影響範囲が大きくなるなどのリスクがあるので、明らかに全モジュールで共通化するべきもののみ共通化しました
  • モジュール構成によって最適な共通化を行うようにした
    • 当アプリでは ui モジュール、domain モジュールにおいて、さらに機能ごとにモジュールが分かれていて、各機能のモジュールを共通化するための Plugin を作成、適用しました
    • モジュール構成図の詳細はこちら

module_configuration_diagram.png

まとめ

本記事では、N予備校 Android チームでビルドロジックを buildSrc から Composite Build に移行した件についてまとめました。
Composite Build に移行することで、バージョン管理を Version Catalog にまとめることができたのと、ビルド設定が共通化できたため、共通設定を変更する際に少ない変更で済むなどメリットがありました。

参考URL

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2