「Gemini in Android Studio」を利用したAndroid プロジェクトのビルドシステム改善:実装詳細編 前編

はじめに

エクストーンのAndroidエンジニアの石原です。

前回の記事では、Androidプロジェクトのビルドシステムを改善するための取り組みとして、 Groovy DSLからKotlin DSLへの移行と、Convention Pluginの導入について概要を説明しました。 design-tech.xtone.co.jp

前回のおさらいをすると、私が参画したプロジェクトは多くのモジュールで構成され、Groovy DSLで記述されたbuild.gradleファイルに依存関係の重複や外部スクリプトへの依存が多く存在し、保守性や拡張性に課題を抱えていました。そこで、AIツール「Gemini in Android Studio」を活用しながら、ビルドシステムをKotlin DSLに移行し、build-logicモジュールを導入することで、これらの課題解決に取り組みました。

本記事では「実装詳細編」と題して、前回紹介した内容をさらに深掘りし、実際のコード例や具体的な移行手順、Convention Pluginの実装方法などについて詳しく解説します。特に、Gemini in Android Studioをどのように活用して効率的な移行を実現したか、また、マルチモジュール環境でのConvention Plugin導入によってどのようにビルドロジックの重複を削減し、保守性を向上させたかについて、実際のプロジェクトでの経験に基づいて説明します。

この記事が、同様の課題に直面しているAndroidエンジニアの方々の参考になれば幸いです。

Groovy DSLからKotlin DSLへの具体的な移行例

Kotlin DSLへの移行は、単なる構文変更以上のものです。適切に実施することで、コードの可読性、型安全性、IDEサポートが向上し、開発効率が大幅に改善されます。本章では、基本的な移行ステップとGemini in Android Studioを活用した効率的な移行方法を解説します。

ステップ1 ファイル名の変更

Kotlin DSLを使用するには、まずファイル名の拡張子を変更する必要があります

  • build.gradlebuild.gradle.kts
  • settings.gradlesettings.gradle.kts
  • その他の.gradleスクリプト → .gradle.ktsに変更

注意点として、同じプロジェクト内でGroovy DSLとKotlin DSLを混在させることも可能です。これにより、モジュール単位での段階的な移行が可能になります。ファイル名を変更するだけでは動作しないため、内容を適切に変換する必要があります。

ステップ2 基本的な構文変換ポイント

Groovy DSLからKotlin DSLへの移行では、いくつかの基本的な構文ルールが変更になります。以下に主な変換ポイントを詳しく説明します。

1. クォーテーションの使用

Groovy DSLでは、シングルクォート(')とダブルクォート(")の両方を使用できますが、Kotlin DSLでは原則としてダブルクォート(")を使用します。

// Groovy DSL
implementation 'androidx.core:core-ktx:1.7.0'  // シングルクォート
implementation "androidx.appcompat:appcompat:1.4.1"  // ダブルクォート(両方可能)
// Kotlin DSL
implementation("androidx.core:core-ktx:1.7.0")  // ダブルクォートが必須

2. 関数呼び出しの括弧

Groovy DSLでは関数呼び出しの括弧を省略できますが、Kotlin DSLでは括弧が必須です。

// Groovy DSL
apply plugin: 'com.android.library'  // 括弧なし
testImplementation junit  // 括弧なし
// Kotlin DSL
apply(plugin = "com.android.library")  // 括弧が必須
testImplementation(junit)  // 括弧が必須

3. 代入演算子

Groovy DSLでは代入に=がなくても良い場合がありますが、Kotlin DSLでは常に=が必要です。

// Groovy DSL
compileSdkVersion 33  // = がない
versionCode 1
// Kotlin DSL
compileSdk = 33  // = が必須
versionCode = 1

4. プラグインの適用方法

Groovy DSLではapply plugin:を使いますが、Kotlin DSLではpluginsブロックかapply()関数を使います。

// Groovy DSL
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
// Kotlin DSL - 推奨方法
plugins {
    id("com.android.library")
    kotlin("android")  // kotlin-androidの短縮形
}

// 代替方法
apply(plugin = "com.android.library")

5. 変数と拡張プロパティ

Groovy DSLではextブロックを使いますが、Kotlin DSLでは通常の変数宣言を使います。

// Groovy DSL
ext {
    kotlin_version = '1.8.0'
}
// または
ext.kotlin_version = '1.8.0'
// Kotlin DSL
val kotlin_version = "1.8.0"

Gemini in Android Studioを活用した移行作業

これまで、Groovy DSLからKotlin DSLへの基本的な移行ステップとして、ファイル名の変更や構文変換のポイントについて解説しました。しかし、実際の大規模プロジェクトでは、これらの変換作業を手動で行うのは時間がかかり、ミスも発生しやすくなります。そこで次に、AIツールを活用して効率的に移行作業を進める方法について紹介します。特に、Google が提供する「Gemini in Android Studio」は、この移行プロセスを大幅に効率化してくれる強力なツールです。

具体的な活用方法は以下の通りです

1. 移行対象のGroovyファイルを記憶させる

まず、移行対象のbuild.gradle(Groovy)ファイルの内容をGeminiに提示し、その構造と内容を記憶させました。

// Geminiに提示したbuild.gradle例
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
    compileSdkVersion 33

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 33
    }

    // その他の設定...
}

dependencies {
    implementation 'androidx.core:core-ktx:1.7.0'
    // その他の依存関係...
}

2. Kotlin DSL形式でのファイル生成を依頼

次に、Geminiに対して同じ内容をbuild.gradle.kts形式に変換するよう依頼しました。

// Geminiが生成したbuild.gradle.kts例
plugins {
    id("com.android.library")
    kotlin("android")
}

android {
    compileSdk = 33

    defaultConfig {
        minSdk = 21
        targetSdk = 33
    }

    // その他の設定...
}

dependencies {
    implementation("androidx.core:core-ktx:1.7.0")
    // その他の依存関係...
}

3. 修正と微調整

Geminiが生成したコードは基本的には正しいものの、一部でGroovy DSLの記法が残ってしまうこともありました。例えば

// 間違い(Groovy記法の混入)
compileSdkVersion 33  // = がない

// 修正後
compileSdk = 33  // = が必須

こういった箇所を手動で修正することで、正常に動作するKotlin DSLファイルを効率的に作成することができました。

4. 効果と利点

Gemini in Android Studioを活用することで、以下の利点がありました - 時間の節約

基本的な変換作業を自動化することで、手作業での書き換え時間を大幅に削減することができました。
以前手動で同様な作業を行った時と比べ体感としては三分の一くらいの時間で作業ができたと思います。
  • 一貫性の確保

    複数のモジュールでも同じパターンで変換が可能になりました。

  • 学習機会

    AIが生成したコードと実際に動作するコードの差分を確認することで、Kotlin DSLの理解が深まりました。

マルチモジュール環境における Convention Plugin の導入

ここまで、Gemini in Android Studioを活用してGroovy DSLからKotlin DSLへの移行を効率的に進める方法について説明しました。しかし、移行だけでは本質的な問題解決には至りません。マルチモジュール環境では、モジュール間で共通するビルド設定の重複が依然として課題となります。

次に紹介するConvention Pluginの導入は、Kotlin DSLの恩恵を最大限に活かしながら、ビルドロジックの共有と再利用を促進する重要なステップです。build-logicモジュールを作成し、プロジェクト全体で一貫したビルド設定を適用することで、保守性と拡張性を大幅に向上させることができます。

1. Convention Plugin とは

Convention Plugin は、Gradle プロジェクトのビルドロジックを再利用可能な形でカプセル化するための仕組みです。 特定のプロジェクトやモジュールに特有のビルド設定やタスクを、 プラグインとして定義し、 それを複数のモジュールで共有・ 適用することができます。 これにより、 ビルドスクリプトの重複を減らし、 保守性を向上させることができます。

2. build-logic モジュールの作成

build-logic モジュールは、Convention Plugin を集約して管理するための専用モジュールです。 このモジュール内に、 プロジェクト全体で共通して使用されるビルドロジックを実装します。

2.1 build-logic/settings.gradle.kts の設定

まず、build-logic モジュール自体を定義します。このモジュールには、 依存関係の解決先を定義するlibsのバージョンカタログへの参照と名前を定義します。

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

rootProject.name = "build-logic"

2.2 build-logic/build.gradle.kts の設定

次に、build-logic モジュールのビルド設定を行います。ここで、 Convention Plugin を定義し、その ID と実装クラスを登録します。

// build-logic/build.gradle.kts
plugins {
     // Kotlin DSL を使用するためのプラグイン。
    `kotlin-dsl`
    // Gradle プラグインを開発するためのプラグイン。
    `java-gradle-plugin`
    // kaptプラグインを適用。
    alias(libs.plugins.kotlin.kapt)
}

dependencies {
    // compileOnly: コンパイル時にのみ必要な依存関係を指定します。
    compileOnly(libs.android.gradlePlugin)
    compileOnly(libs.kotlin.gradlePlugin)
    compileOnly(libs.compose.gradlePlugin)
    // implementation: 実装に必要な依存関係を指定します。
    implementation(gradleApi())
    implementation(localGroovy())
}

java {
    // ソースコードの互換性を設定します。
    sourceCompatibility = JavaVersion.VERSION_17
    // バイトコードの互換性を設定します。
    targetCompatibility = JavaVersion.VERSION_17
}

gradlePlugin {
    // Convention Plugin を定義します。
    plugins {
        register("androidApplication") {
       // プラグインを適用する際に使用する ID。
            id = libs.plugins.sample.android.application.asProvider().get().pluginId
            // プラグインの実装クラスへのフルパス。
            implementationClass = "com.sample.AndroidApplicationConventionPlugin"
        }
        // ... 他の Convention plugin の登録 ...
        register("ui") {
            id = libs.plugins.sample.ui.get().pluginId
            implementationClass = "com.sample.UiModuleConventionPlugin"
        }
    }
}

3. プロジェクトレベルでの build-logic モジュールの利用設定

プロジェクト全体で build-logic モジュールを利用するためには、ルートプロジェクトの settings.gradle.kts ファイルで includeBuild を使用して build-logic モジュールをインクルードする必要があります。

3.1 settings.gradle.kts の設定

// settings.gradle.kts
pluginManagement {
    // build-logic モジュールをビルドに含めます。
    // これにより、 build-logic モジュールで定義された 
    // Convention Plugin が利用可能になります。
    includeBuild("build-logic")
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("${rootDir.absolutePath}/app/sdk") }
    }
}

// ... 他のモジュールの include ...
include(":app")
include(":ui")

4. Convention Plugin の適用

build-logic モジュールで定義された Convention Plugin は、他のモジュールで簡単に適用できます。 例えば、 androidApplication という ID の Convention Plugin を適用するには、モジュールの build.gradle.kts ファイルで以下のように記述します。

// app/build.gradle.kts
plugins {
    id("sample.android.application")
}

// ... その他の設定 ...

このように、plugins { id("...") } ブロックに Convention Plugin の ID を指定するだけで、そのプラグインが適用されます。

5. まとめ

Convention Plugin と build-logic モジュールを組み合わせることで、マルチモジュール環境でのビルドロジックの一元管理と再利用が容易になります。 これにより、 ビルドスクリプトの保守性と可読性が向上し、 開発効率の向上に繋がります。 本章で説明した手順に従い、 Convention Plugin の導入を検討してみてください。 長くなってきましたので後編に続きます。