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 プラグインを追加しておきます。
[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
を以下の通り実装します。
plugins {
`kotlin-dsl`
}
dependencies {
compileOnly(libs.android.gradlePlugin)
compileOnly(libs.kotlin.gradlePlugin)
}
build-logic
モジュールにて プロジェクト名/gradle/libs.versions.toml
を参照するため、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
に以下を記載します。
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
から参照していました。
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
の例です。
...
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
に移行します。
[versions]
...
composeCompiler = "1.4.7"
# ライブラリ以外のバージョン情報
compileSdkVersion = "33"
minSdkVersion = "26"
versionCode = "1"
versionName = "1.0.0"
...
...
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 を追加します。
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 でも使用するような共通の設定を以下のようにまとめておくと便利です。
例えば compileSdk
と minSdk
、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
の実装が以下の通りだったとします。
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
に以下を記載します。
...
gradlePlugin {
plugins {
register("androidLibrary") {
id = "sample.android.library"
implementationClass = "sample.buildlogic.AndroidLibraryPlugin"
}
}
}
register
に指定する名前は外部から参照することはないため、識別できれば何でも OK です。
id
に参照する際のプラグイン ID、implementationClass
に Plugin クラスのパッケージ名およびクラス名を指定します。
そして、任意のライブラリモジュールにて、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 を作成、適用しました
- モジュール構成図の詳細はこちら
まとめ
本記事では、N予備校
Android チームでビルドロジックを buildSrc から Composite Build に移行した件についてまとめました。
Composite Build に移行することで、バージョン管理を Version Catalog にまとめることができたのと、ビルド設定が共通化できたため、共通設定を変更する際に少ない変更で済むなどメリットがありました。