🦄

CodeX × Android開発:オフライン環境でもテスト可能なGradle依存の事前取得法

に公開

CodeX × Android開発:オフライン環境でもテスト可能なGradle依存の事前取得法

▶︎ English version here

背景・問題意識

私が開発しているプロジェクトは、以下のような構成になっています:

  • 複数のアプリを 1 つのリポジトリにまとめた「マルチアプリ構成」
  • アプリ間でコードを共有するための「マルチモジュール構成」

CodeX にテストも担保してもらいながら開発を進めるためには注意が必要です。CodeX はセットアップ処理の完了後にオフライン環境に切り替わるため、./gradlew test を正常に実行させるには、セットアップ時にすべての依存関係を解決・ダウンロードしておく必要があります。

CodeX対応のセットアップスクリプト全体像

本記事では、CodeX で Android プロジェクトのテストを正常に実行できるようにするためのセットアップ手順を紹介します。

やっていること(概要)

  • setup.sh で Android SDK, Build Tools, ライセンス承諾を自動化
  • resolveAllDependencies タスクを build.gradle.kts に追加して、全モジュールの依存解決を一括で実行

setup.sh(抜粋)

#!/bin/bash
set -ex

export ANDROID_SDK_ROOT="/root/android-sdk"

apt-get update && apt-get install -y expect

mkdir -p "$ANDROID_SDK_ROOT/licenses"
echo "8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_SDK_ROOT/licenses/android-sdk-license"

mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools"
cd "$ANDROID_SDK_ROOT/cmdline-tools"
curl -sSL -o tools.zip https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
unzip -q tools.zip
rm tools.zip

mkdir -p latest
mv cmdline-tools/* latest/

export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH"

yes | "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager" --licenses > /dev/null

expect <<EOF
spawn sdkmanager --sdk_root="$ANDROID_SDK_ROOT" --no_https \
  "platform-tools" \
  "platforms;android-35" \
  "build-tools;35.0.0"
expect {
    "Accept? (y/N):" { send "y\r"; exp_continue }
    eof
}
EOF

gradle help --no-daemon

PROJECT_DIR="/workspace/your_project_name"

echo "sdk.dir=$ANDROID_SDK_ROOT" > /workspace/your_project_name/local.properties

cd "$PROJECT_DIR"

./gradlew resolveAllDependencies

※スクリプト全体は推敲中のため、冗長な処理が残っている可能性があります。

build.gradle.kts(プロジェクトルート)

allprojects {
    tasks.register("resolveAllDependencies") {
        group = "dependency"
        description = "Resolves and downloads all dependencies for all configurations in all projects."

        doLast {
            configurations
                .filter { it.isCanBeResolved }
                .forEach { config ->
                    println("🔍 Resolving ${config.name} in ${project.name}")
                    try {
                        config.resolve()
                    } catch (e: Exception) {
                        println("❌ Failed to resolve ${config.name} in ${project.name}: ${e.message}")
                    }
                }
        }
    }
}

なぜこの構成にしたのか:試行錯誤の背景と設計意図

SDK ライセンス受諾の自動化

mkdir -p "$ANDROID_SDK_ROOT/licenses"
echo "8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_SDK_ROOT/licenses/android-sdk-license"

これは、sdkmanager コマンド実行時に毎回表示されるライセンス確認を事前に済ませるためです。

SDK コンポーネントの自動インストールと応答制御

当初は以下のように yes コマンドを使って一括応答させる方法を検討しました:

yes | sdkmanager --sdk_root=... "platforms;android-35" ...

しかし、CodeX の本番実行環境ではこの方法ではプロセスが途中で停止してしまうことがあり、安定したセットアップを構築できませんでした。

そのため、expect コマンドで Accept? (y/N): に明示的に "y" を送る方法に切り替えました。

Gradle の依存ライブラリ事前解決

./gradlew resolveAllDependencies

このタスクは canBeResolved な全設定に .resolve() を実行し、事前に依存ライブラリをすべてキャッシュに保存します。プロジェクトが大きく ./gradlew test./gradlew build では依存取得が間に合わない場合にも有効です。

local.properties による SDK パス指定

以下のようなエラーを避けるため:

SDK location not found. Define a valid SDK location with an ANDROID_HOME environment variable
or by setting the sdk.dir path in your project's local.properties file

次のように local.properties を生成しています:

echo "sdk.dir=$ANDROID_SDK_ROOT" > /workspace/soundverse-android/local.properties

Discussion