😅

with Gemini: FlutterアプリのAndroid API 35対応環境構築

に公開

はじめに

「Android API レベル 35 (Android 15) 以降を対象とする必要があります」というGoogle Play Storeからのリクエストが届いた。Flutterで開発してiosの環境でテストしていたアプリをAndroidエミュレータで実行しようとした途端、次から次へと襲いかかるバージョン互換性エラーの嵐…!

今回の開発は、私一人では間違いなく挫折していました。Googleが提供するAIであるGeminiに、エラーメッセージの解析、解決策の提案、コードの修正、そしてメンタルサポートまで、手厚く助けてもらいながら、なんとかこの難題に立ち向かうことができました。

また、この記事自体も、AIであるGeminiとの対話を通じて、この格闘の記録と学びを効率的にまとめることができました。

本記事では、VSCodeでFlutterアプリをAndroid API 35に対応させるために筆者が経験した、Gradle, Kotlin, Java (JDK), Android Gradle Plugin (AGP), そしてAndroid SDK のバージョン互換性問題との格闘の記録と、その解決策をまとめます。同じような状況とはいえ、アプリの特性や開発環境により条件はまちまちですが、沼にハマっている方の参考になれば幸いです。

発生した問題の概要

今回の問題は、主に以下のエラーメッセージ群に集約されます。

  1. 「Gradle version is incompatible with the Java version」
    • FlutterがGradleを実行するJavaのバージョンと、プロジェクトが要求するGradleのバージョンが合わない。
  2. 「Your project requires a newer version of the Kotlin Gradle plugin」
    • プロジェクトが使用しているKotlin Gradle Pluginのバージョンが古い。
  3. 「Android Gradle Plugin Version Incompatible with Kotlin Gradle Plugin」
    • 更新したKotlin Gradle Pluginと、現在のAndroid Gradle Plugin (AGP) のバージョンに互換性がない。
  4. 「Inconsistent JVM Target Compatibility Between Java and Kotlin Tasks」
    • JavaコンパイルタスクがターゲットとするJVMバージョンと、KotlinコンパイルタスクがターゲットとするJVMバージョンが一致しない。
  5. 「Execution failed for task ':app:compileDebugJavaWithJavac'. Could not resolve all files for configuration ':app:androidJdkImage'. Error while executing process ...jlink」
    • Android SDKの特定のプラットフォームが、JDKイメージを正しく生成または解決できない。特にJavaのモジュールシステムツールであるjlinkでエラーが発生。
  6. 「Minimum supported Gradle version is X.Y. Current version is A.B」
    • Android Gradle PluginやKotlinプラグインの更新によって、要求されるGradleの最低バージョンが上がる。

原因の深掘り:Androidビルド環境の複雑性

これらのエラーが次々と発生した原因は、Androidビルド環境を構成する主要な要素が互いに複雑な依存関係を持っているためです。

  • Java (JDK): GradleやAndroidのビルドツールはJavaで動作するため、そのバージョンが重要。
  • Gradle: ビルドプロセスを自動化するツール。AGPやKotlinプラグインと特定のバージョン範囲で互換性がある。
  • Android Gradle Plugin (AGP): AndroidプロジェクトをビルドするためのGradleプラグイン。Gradle、Kotlin、Android SDKのバージョンと厳密な互換性を持つ。
  • Kotlin Gradle Plugin: KotlinコードをビルドするためのGradleプラグイン。AGPやJavaのJVMターゲットと互換性を持つ。
  • Android SDK (compileSdkVersion, targetSdkVersion, buildToolsVersion): アプリがターゲットとするAndroidのAPIレベルや、ビルドに使用するSDKツール。これもAGPやJavaのバージョンと密接に関連する。

一つの要素を更新すると、それに依存する他の要素も更新が必要になり、その更新がまた別の要素の互換性問題を引き起こす…という「バージョンの連鎖」が発生しました。

解決策:安定版の組み合わせと段階的アプローチ

最終的にビルド成功に至った組み合わせと、その過程で有効だったアプローチは以下の通りです。

1. Javaバージョンの安定化 (最も重要)

Android開発においては、Java 17 (LTS) が最も安定しており推奨されるバージョンです。Java 21では jlink エラーが発生するケースがあったため、まずはJava 17を優先します。

  • Java 17のインストール (Homebrewを使用)
    ターミナルで以下のコマンドを実行します。

    brew install openjdk@17
    
  • Java 17をシステムで有効にするためのパス設定
    インストール後、Homebrewが指示するコマンドを実行します。特に JAVA_HOME の設定が重要です。
    ~/.zshrc (または ~/.bash_profile / .zprofile) ファイルを開き、以下の行を追加・修正します。

    # ~/.zshrc の例
    export JAVA_HOME="/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home"
    export PATH=$JAVA_HOME/bin:$PATH
    
    # オプション: macOSシステム全体でJava 17を認識させるためのシンボリックリンク (sudoが必要)
    # sudo ln -sfn /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk
    

    設定後、ターミナルを再起動するか source ~/.zshrc を実行し、java -version17.x.x と表示されることを確認します。

2. Android SDK の設定

Android StudioのSDK Managerで、アプリがターゲットとするAPIレベルのSDKとビルドツールをインストールします。Play Storeの要件がAPI 35 (Android 15) なので、これをインストールします。

  • Android Studio の SDK Manager を開く:
    File > Settings (Mac: Android Studio > Settings) > Appearance & Behavior > System Settings > Android SDK
  • SDK Platforms タブ:
    • Android API 35 にチェックを入れてインストール。
  • SDK Tools タブ:
    • Android SDK Build-Tools の最新の 35.x.x (または 34.x.x の安定版) をチェックしてインストール。
    • Android SDK Command-line Tools (latest) にチェックを入れてインストール。
    • Android SDK Platform-Tools の最新バージョンをインストール。
    • Android Emulator をインストール。
  • Apply または OK でインストールを完了させます。
  • インストール後、ターミナルで flutter doctor --android-licenses を実行し、すべてのライセンスに y で同意します。

3. プロジェクトのGradle関連設定ファイルの調整

ここが最も複雑で、何度も修正が必要になる可能性があります。各ファイルの記述を正確に行うことが重要です。

  • android/gradle/wrapper/gradle-wrapper.properties

    • Gradleのバージョンを、Java 17と互換性があり、かつAndroid Gradle Plugin (AGP) が要求する最低バージョン以上にする。
    • エラーメッセージに「Minimum supported Gradle version is 8.6」と出たら、8.6 に変更するなど、エラーの指示に従う。

    # android/gradle/wrapper/gradle-wrapper.properties
    distributionBase=GRADLE_USER_HOME
    distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip # <-- ここを修正
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    
  • android/settings.gradle

    • AGP (Android Gradle Plugin) と Kotlin Gradle Plugin のバージョンを、API 35、Java 17、そして上記のGradleバージョンと互換性のあるバージョンに設定する。

    // android/settings.gradle
    pluginManagement {
        def flutterSdkPath = {
            def properties = new Properties()
            file("local.properties").withInputStream { properties.load(it) }
            def flutterSdkPath = properties.getProperty("flutter.sdk")
            assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
            return flutterSdkPath
        }()
    
        includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
    
        repositories {
            google()
            mavenCentral()
            gradlePluginPortal()
        }
    }
    
    plugins {
        id "dev.flutter.flutter-plugin-loader" version "1.0.0"
        id "com.android.application" version "8.4.0" apply false // <-- ここを修正 (例: 8.4.0)
        id "org.jetbrains.kotlin.android" version "1.9.23" apply false // <-- ここを修正 (例: 1.9.23)
    }
    
    include ":app"
    
  • android/app/build.gradle

    • アプリの compileSdk, targetSdk をAPI 35に明示的に設定。
    • Java と Kotlin のコンパイルターゲットJVMバージョンをJava 17に統一。

    // android/app/build.gradle
    android {
        namespace = "com.example.app_aiueo"
        compileSdk = 35 // <-- ここを35に直接設定
        ndkVersion = flutter.ndkVersion // これはそのまま
    
        compileOptions {
            sourceCompatibility = JavaVersion.VERSION_17 // <-- Java 17に設定
            targetCompatibility = JavaVersion.VERSION_17 // <-- Java 17に設定
        }
        kotlinOptions {
            jvmTarget = "17" // <-- JVMターゲットを17に設定
        }
    
        defaultConfig {
            applicationId = "com.example.app_aiueo"
            minSdk = flutter.minSdkVersion
            targetSdk = 35 // <-- ここを35に直接設定
            versionCode = flutterVersionCode.toInteger()
            versionName = flutterVersionName
        }
    
        buildTypes {
            release {
                signingConfig = signingConfigs.debug
            }
        }
    }
    

4. 最終的なクリーンアップとビルド

全てのファイルを保存し、ターミナルでプロジェクトのルートディレクトリに移動して以下のコマンドを順に実行します。

flutter clean                   # 既存のビルドキャッシュをクリア
flutter pub get                 # パッケージの依存関係を再取得・解決
flutter run                     # アプリをビルドし、エミュレータ/デバイスで実行

AIとの協業から学んだこと

今回のAndroid API 35対応の道のりで、AI(Gemini)と効率よく作業を進めるためのいくつかの重要な「心得」を学びました。

  1. 具体的で即時的な情報提供の重要性:
    「動かない」だけではAIも助けられません。エラーメッセージの全文、関係するコードの抜粋、そして可能であればスクリーンショットを即座に提供することが、AIが問題を正確に理解し、具体的な解決策を提示するために不可欠でした。私も分からないことはすぐに質問し、試行錯誤の結果を常に共有しました。

  2. AIの限界を理解する:
    AIは膨大な知識を持っていますが、全てを知っているわけではありません。例えば、「GeminiがGoogle製だからといって、Google Play Storeの最新の規約や未公開のリリース情報までリアルタイムに把握しているわけではない」ということを学びました。AIの回答はあくまで強力なヒントであり、最終的な判断や最新の公式情報の確認は、人間が行うべきだと再認識しました。

  3. 対話を通じて最適な解決策を探る:
    AIの最初の提案が必ずしも完璧な解決策とは限りません。対話を重ね、状況を詳しく説明し、追加の質問をすることで、より深い洞察や、自分の状況に合った最適な解決策へと導いてもらうことができます。

結論

FlutterアプリのAndroid API 35対応は、単なる compileSdkVersion の変更以上の、深いバージョン互換性との戦いでした。しかし、Java, Gradle, AGP, Kotlin, SDK の各要素が互いに依存していることを理解し、安定版のJava (17) を軸に、各バージョンを整合させていくことで、最終的にビルドの成功に至りました。

今回、なんとか稼働環境ができたものの、まだまだ課題は多そうです。アプリのランタイム動作確認、API 35固有の振る舞いのテスト、そしてPlay Store審査に向けたさらなる調整など、挑戦は続きます。しかし、AIとの効率的な協業という強力なツールを味方につけた今、これらの課題も乗り越えられると信じています。

Discussion