mcpField
A
android-native-dev

android-native-dev

github.com/minimax-ai開発13.7k2.7k 回インストール28 週間前に更新
リポジトリ

android-native-dev について

android-native-devは、KotlinとJetpack Composeを使ったAndroidアプリ開発向けのスキルです。プロジェクト設定、コーディング規約、UIの実践方法、Gradleのビルドエラー診断を開発者に案内します。

主な機能

  1. 01Androidプロジェクトの初期化とGradle設定
  2. 02Kotlinのコーディングとコルーチンの指針
  3. 03Jetpack Composeの状態管理とUI設計
  4. 04ビルドバリアントとフレーバーの設定
  5. 05ビルドエラーの診断とデバッグ

活用シーン

  1. 01空のディレクトリからAndroidプロジェクトを開始
  2. 02開発・ステージング・本番用のフレーバー追加
  3. 03KotlinとComposeコードのよくある問題の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/minimax-ai/skills --skill android-native-dev

インストール後、Claude Code で/android-native-devを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
accessibility.md
adaptive-screens.md
design-style-guide.md
functional-requirements.md
motion-system.md
performance-stability.md
privacy-security.md
testing.md
visual-design.md

詳細

1. プロジェクトのシナリオ評価

開発を始める前に、現在のプロジェクトの状態を評価します。

シナリオ特徴対応方法
空のディレクトリファイルが存在しないGradle Wrapper を含め、全体を初期化する必要があります
Gradle Wrapper があるgradlew と gradle/wrapper/ が存在するビルドには ./gradlew を直接使用します
Android Studio プロジェクトプロジェクト構成は完全ですが、Wrapper がない場合がありますWrapper を確認し、必要に応じて gradle wrapper を実行します
不完全なプロジェクト一部のファイルが存在する不足しているファイルを確認し、設定を補完します

基本原則:

  • ビジネスロジックを記述する前に、./gradlew assembleDebug が成功することを確認します
  • gradle.properties がない場合は、まず作成して AndroidX を設定します
1.1 必須ファイルのチェックリスト
MyApp/
├── gradle.properties          # Configure AndroidX and other settings
├── settings.gradle.kts
├── build.gradle.kts           # Root level
├── gradle/wrapper/
│   └── gradle-wrapper.properties
├── app/
│   ├── build.gradle.kts       # Module level
│   └── src/main/
│       ├── AndroidManifest.xml
│       ├── java/com/example/myapp/
│       │   └── MainActivity.kt
│       └── res/
│           ├── values/
│           │   ├── strings.xml
│           │   ├── colors.xml
│           │   └── themes.xml
│           └── mipmap-*/       # App icons

2. プロジェクトの設定

2.1 gradle.properties
# Required configuration
android.useAndroidX=true
android.enableJetifier=true

# Build optimization
org.gradle.parallel=true
kotlin.code.style=official

# JVM memory settings (adjust based on project size)
# Small projects: 2048m, Medium: 4096m, Large: 8192m+
# org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8

注:ビルド中に OutOfMemoryError が発生した場合は、-Xmx の値を増やしてください。依存関係が多い大規模なプロジェクトでは、8GB 以上が必要になる場合があります。

2.2 依存関係の宣言に関する規則
dependencies {
    // Use BOM to manage Compose versions
    implementation(platform("androidx.compose:compose-bom:2024.02.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    
    // Activity & ViewModel
    implementation("androidx.activity:activity-compose:1.8.2")
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
}
2.3 ビルドバリアントとプロダクトフレーバー

プロダクトフレーバーを使うと、アプリの異なるバージョン(無料版/有料版、開発版/ステージング版/本番版など)を作成できます。

app/build.gradle.kts での設定:

android {
    // Define flavor dimensions
    flavorDimensions += "environment"
    
    productFlavors {
        create("dev") {
            dimension = "environment"
            applicationIdSuffix = ".dev"
            versionNameSuffix = "-dev"
            
            // Different config values per flavor
            buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")
            buildConfigField("Boolean", "ENABLE_LOGGING", "true")
            
            // Different resources
            resValue("string", "app_name", "MyApp Dev")
        }
        
        create("staging") {
            dimension = "environment"
            applicationIdSuffix = ".staging"
            versionNameSuffix = "-staging"
            
            buildConfigField("String", "API_BASE_URL", "\"https://staging-api.example.com\"")
            buildConfigField("Boolean", "ENABLE_LOGGING", "true")
            resValue("string", "app_name", "MyApp Staging")
        }
        
        create("prod") {
            dimension = "environment"
            // No suffix for production
            
            buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
            buildConfigField("Boolean", "ENABLE_LOGGING", "false")
            resValue("string", "app_name", "MyApp")
        }
    }
    
    buildTypes {
        debug {
            isDebuggable = true
            isMinifyEnabled = false
        }
        release {
            isDebuggable = false
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
        }
    }
}

ビルドバリアントの命名:{flavor}{BuildType} → 例:devDebug、prodRelease

Gradle のビルドコマンド:

# List all available build variants
./gradlew tasks --group="build"

# Build specific variant (flavor + buildType)
./gradlew assembleDevDebug        # Dev flavor, Debug build
./gradlew assembleStagingDebug    # Staging flavor, Debug build
./gradlew assembleProdRelease     # Prod flavor, Release build

# Build all variants of a specific flavor
./gradlew assembleDev             # All Dev variants (debug + release)
./gradlew assembleProd            # All Prod variants

# Build all variants of a specific build type
./gradlew assembleDebug           # All flavors, Debug build
./gradlew assembleRelease         # All flavors, Release build

# Install specific variant to device
./gradlew installDevDebug
./gradlew installProdRelease

# Build and install in one command
./gradlew installDevDebug && adb shell am start -n com.example.myapp.dev/.MainActivity

コードからの BuildConfig へのアクセス:

注:AGP 8.0 以降では、BuildConfig はデフォルトで生成されなくなりました。build.gradle.kts で明示的に有効にする必要があります。

android {
    buildFeatures {
        buildConfig = true
    }
}
// Use build config values in your code
val apiUrl = BuildConfig.API_BASE_URL
val isLoggingEnabled = BuildConfig.ENABLE_LOGGING

if (BuildConfig.DEBUG) {
    // Debug-only code
}

フレーバー固有のソースセット:

app/src/
├── main/           # Shared code for all flavors
├── dev/            # Dev-only code and resources
│   ├── java/
│   └── res/
├── staging/        # Staging-only code and resources
├── prod/           # Prod-only code and resources
├── debug/          # Debug build type code
└── release/        # Release build type code

複数のフレーバーディメンション(例:環境 + プラン):

android {
    flavorDimensions += listOf("environment", "tier")
    
    productFlavors {
        create("dev") { dimension = "environment" }
        create("prod") { dimension = "environment" }
        
        create("free") { dimension = "tier" }
        create("paid") { dimension = "tier" }
    }
}
// Results in: devFreeDebug, devPaidDebug, prodFreeRelease, etc.

3. Kotlin 開発規則

3.1 命名規則
種類規則例
クラス/インターフェースPascalCaseUserRepository、MainActivity
関数/変数camelCasegetUserName()、isLoading
定数SCREAMING_SNAKEMAX_RETRY_COUNT
パッケージ小文字com.example.myapp
ComposablePascalCase@Composable fun UserCard()
3.2 コード規則(重要)

Null 安全性:

// ❌ Avoid: Non-null assertion !! (may crash)
val name = user!!.name

// ✅ Recommended: Safe call + default value
val name = user?.name ?: "Unknown"

// ✅ Recommended: let handling
user?.let { processUser(it) }

例外処理:

// ❌ Avoid: Random try-catch in business layer swallowing exceptions
fun loadData() {
    try {
        val data = api.fetch()
    } catch (e: Exception) {
        // Swallowing exception, hard to debug
    }
}

// ✅ Recommended: Let exceptions propagate, handle at appropriate layer
suspend fun loadData(): Result<Data> {
    return try {
        Result.success(api.fetch())
    } catch (e: Exception) {
        Result.failure(e)  // Wrap and return, let caller decide handling
    }
}

// ✅ Recommended: Unified handling in ViewModel
viewModelScope.launch {
    runCatching { repository.loadData() }
        .onSuccess { _uiState.value = UiState.Success(it) }
        .onFailure { _uiState.value = UiState.Error(it.message) }
}
3.3 スレッドとコルーチン(重要)

スレッド選択の原則:

処理の種類スレッド説明
UI の更新Dispatchers.MainView、State、LiveData を更新します
ネットワークリクエストDispatchers.IOHTTP 呼び出し、API リクエスト
ファイル I/ODispatchers.IOローカルストレージ、データベース操作
計算負荷の高い処理Dispatchers.DefaultJSON の解析、ソート、暗号化

正しい使用方法:

// In ViewModel
viewModelScope.launch {
    // Default Main thread, can update UI State
    _uiState.value = UiState.Loading
    
    // Switch to IO thread for network request
    val result = withContext(Dispatchers.IO) {
        repository.fetchData()
    }
    
    // Automatically returns to Main thread, update UI
    _uiState.value = UiState.Success(result)
}

// In Repository (suspend functions should be main-safe)
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
    api.getData()
}

よくある間違い:

// ❌ Wrong: Updating UI on IO thread
viewModelScope.launch(Dispatchers.IO) {
    val data = api.fetch()
    _uiState.value = data  // Crash or warning!
}

// ❌ Wrong: Executing time-consuming operation on Main thread
viewModelScope.launch {
    val data = api.fetch()  // Blocking main thread! ANR
}

// ✅ Correct: Fetch on IO, update on Main
viewModelScope.launch {
    val data = withContext(Dispatchers.IO) { api.fetch() }
    _uiState.value = data
}
3.4 可視性の規則
// Default is public, declare explicitly when needed
class UserRepository {           // public
    private val cache = mutableMapOf<String, User>()  // Visible only within class
    internal fun clearCache() {} // Visible only within module
}

// data class properties are public by default, be careful when used across modules
data class User(
    val id: String,       // public
    val name: String
)
3.5 よくある構文上の落とし穴
// ❌ Wrong: Accessing uninitialized lateinit
class MyViewModel : ViewModel() {
    lateinit var data: String
    fun process() = data.length  // May crash
}

// ✅ Correct: Use nullable or default value
class MyViewModel : ViewModel() {
    var data: String? = null
    fun process() = data?.length ?: 0
}

// ❌ Wrong: Using return in lambda
list.forEach { item ->
    if (item.isEmpty()) return  // Returns from outer function!
}

// ✅ Correct: Use return@forEach
list.forEach { item ->
    if (item.isEmpty()) return@forEach
}
3.6 サーバー応答のデータクラスのフィールドは Nullable にする必要があります
// ❌ Wrong: Fields declared as non-null (server may not return them)
data class UserResponse(
    val id: String = "",
    val name: String = "",
    val avatar: String = ""
)

// ✅ Correct: All fields declared as nullable
data class UserResponse(
    @SerializedName("id")
    val id: String? = null,
    @SerializedName("name")
    val name: String? = null,
    @SerializedName("avatar")
    val avatar: String? = null
)
3.7 ライフサイクルに応じたリソース管理
// ❌ Wrong: Only adding Observer, not removing
class MyView : View {
    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        activity?.lifecycle?.addObserver(this)
    }
    // Memory leak!
}

// ✅ Correct: Paired add and remove
class MyView : View {
    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        activity?.lifecycle?.addObserver(this)
    }

    override fun onDetachedFromWindow() {
        activity?.lifecycle?.removeObserver(this)
        super.onDetachedFromWindow()
    }
}
3.8 ログレベルの使い分け
import android.util.Log

// Info: Key checkpoints in normal flow
Log.i(TAG, "loadData: started, userId = $userId")

// Warning: Abnormal but recoverable situations
Log.w(TAG, "loadData: cache miss, fallback to network")

// Error: Failure/error situations
Log.e(TAG, "loadData failed: ${error.message}")
レベル用途
i(情報)通常の処理の流れ、メソッドの開始、重要なパラメーター
w(警告)回復可能な例外、フォールバック処理、null の返却
e(エラー)リクエストの失敗、捕捉した例外、回復不能なエラー

4. Jetpack Compose の規則

4.1 @Composable コンテキストの規則
// ❌ Wrong: Calling Composable from non-Composable function
fun showError(message: String) {
    Text(message)  // Compile error!
}

// ✅ Correct: Mark as @Composable
@Composable
fun ErrorMessage(message: String) {
    Text(message)
}

// ❌ Wrong: Using suspend outside LaunchedEffect
@Composable
fun MyScreen() {
    val data = fetchData()  // Error!
}

// ✅ Correct: Use LaunchedEffect
@Composable
fun MyScreen() {
    var data by remember { mutableStateOf<Data?>(null) }
    LaunchedEffect(Unit) {
        data = fetchData()
    }
}
4.2 状態管理
// Basic State
var count by remember { mutableStateOf(0) }

// Derived State (avoid redundant computation)
val isEven by remember { derivedStateOf { count % 2 == 0 } }

// Persist across recomposition (e.g., scroll position)
val scrollState = rememberScrollState()

// State in ViewModel
class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(UiState())
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}
4.3 Compose でよくある間違い
// ❌ Wrong: Creating objects in Composable (created on every recomposition)
@Composable
fun MyScreen() {
    val viewModel = MyViewModel()  // Wrong!
}

// ✅ Correct: Use viewModel() or remember
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
    // ...
}

5. リソースとアイコン

5.1 アプリアイコンの要件

複数の解像度のアイコンを用意する必要があります。

ディレクトリサイズ用途
mipmap-mdpi48x48基準
mipmap-hdpi72x721.5 倍
mipmap-xhdpi96x962 倍
mipmap-xxhdpi144x1443 倍
mipmap-xxxhdpi192x1924 倍

推奨:アダプティブアイコンを使用します(Android 8 以降)。


<adaptive-icon>
    <background android:drawable="@color/ic_launcher_background"/>
    <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
5.2 リソースの命名規則
種類接頭辞例
レイアウトlayout_layout_main.xml
画像ic_、img_、bg_ic_user.png
色color_color_primary
文字列-app_name、btn_submit
5.3 Android の予約済み名称を避ける(重要)

変数名、リソース ID、色、アイコン、XML 要素には、Android の予約語やシステムリソース名を使用しないでください。予約済みの名前を使用すると、ビルドエラーやリソースの競合が発生します。

避けるべき一般的な予約済み名称:

カテゴリ予約済み名称(使用禁止)
色background、foreground、transparent、white、black
アイコン/ドローアブルicon、logo、image、drawable
ビューview、text、button、layout、container
属性id、name、type、style、theme、color
システムapp、android、content、data、action

例:


<color name="background">#FFFFFF</color>
<color name="icon">#000000</color>


<color name="app_background">#FFFFFF</color>
<color name="icon_primary">#000000</color>
// ❌ Wrong: Variable names conflict with system
val icon = R.drawable.my_icon
val background = Color.White

// ✅ Correct: Use descriptive names
val appIcon = R.drawable.my_icon
val screenBackground = Color.White

<ImageView android:src="@drawable/icon" />


<ImageView android:src="@drawable/ic_home" />

6. ビルドエラーの診断と修正

6.1 よくあるエラーのクイックリファレンス
エラーキーワード原因修正方法
Unresolved referenceインポートの不足、または未定義インポートを確認し、依存関係を検証します
Type mismatch型の不一致パラメーターの型を確認し、変換を追加します
Cannot access可視性の問題public/private/internal を確認します
@Composable invocationsComposable コンテキストのエラー呼び出し元も @Composable であることを確認します
Duplicate class依存関係の競合./gradlew dependencies を使用して調査します
AAPT: errorリソースファイルのエラーXML 構文とリソース参照を確認します
6.2 修正のベストプラクティス
  1. まずエラーメッセージ全体を読む:ファイルと行番号を特定します
  2. 最近の変更を確認する:問題は通常、直近の変更にあります
  3. ビルドをクリーンにする:./gradlew clean assembleDebug
  4. 依存関係のバージョンを確認する:バージョンの競合はよくある原因です
  5. 必要に応じて依存関係を更新する:キャッシュをクリアして再ビルドします
6.3 デバッグコマンド
# Clean and build
./gradlew clean assembleDebug

# View dependency tree (investigate conflicts)
./gradlew :app:dependencies

# View detailed errors
./gradlew assembleDebug --stacktrace

# Refresh dependencies
./gradlew --refresh-dependencies

7. Material Design 3 のガイドライン

Android の UI ファイルを確認し、Material Design 3 のガイドラインと Android のベストプラクティスに準拠していることを確かめます。

デザインの理念
M3 の基本原則
原則説明
パーソナルユーザーの好みや壁紙に基づくダイナミックカラー
適応性すべての画面サイズとフォームファクターに対応
表現力個性のある大胆な色とタイポグラフィ
アクセシブルすべてのユーザーを対象としたインクルーシブなデザイン
M3 Expressive(最新)

最新の進化では、感情を重視した UX を次の要素によって実現します:

  • 鮮やかなダイナミックカラー
  • 直感的な動きの物理特性
  • 適応型コンポーネント
  • 柔軟なタイポグラフィ
  • コントラストのある形状(新たに 35 種類の形状オプション)
アプリのスタイル選択

重要な判断:視覚スタイルをアプリのカテゴリと対象ユーザーに合わせます。

アプリのカテゴリ視覚スタイル主な特徴
ユーティリティ/ツールミニマリストすっきりとして効率的、中立的な色
金融/銀行信頼感のあるプロフェッショナル控えめな色、安全性を重視
健康/ウェルネス穏やかで自然柔らかな色、有機的な形状
子ども向け(3~5 歳)シンプルで遊び心のあるデザイン明るい色、大きなタッチ領域(56dp 以上)
子ども向け(6~12 歳)楽しく夢中になれるデザイン鮮やかで、ゲーム感覚のフィードバック
ソーシャル/エンターテインメント表現力豊かブランド主導で、ジェスチャーを多用
生産性すっきりとして集中しやすいミニマルで、高いコントラスト
E コマースコンバージョン重視明確な CTA、スキャンしやすいレイアウト

詳しいスタイルプロファイルについては、デザインスタイルガイドを参照してください。

クイックリファレンス:主な仕様
色のコントラスト要件
要素最小比率
本文4.5:1
大きなテキスト(18sp 以上)3:1
UI コンポーネント3:1
タッチターゲット
種類サイズ
最小48 × 48dp
推奨(主要な操作)56 × 56dp
子ども向けアプリ56dp 以上
ターゲット間の間隔最小 8dp
8dp グリッドシステム
トークン値用途
xs4dpアイコンのパディング
sm8dp狭い間隔
md16dpデフォルトのパディング
lg24dpセクション間の間隔
xl32dp大きな間隔
xxl48dp画面の余白
タイポグラフィのスケール(概要)
カテゴリサイズ
ディスプレイ57sp、45sp、36sp
見出し32sp、28sp、24sp
タイトル22sp、16sp、14sp
本文16sp、14sp、12sp
ラベル14sp、12sp、11sp
アニメーションの時間
種類時間
マイクロ(波紋)50-100ms
短い(シンプル)100-200ms
中程度(展開/折りたたみ)200-300ms
長い(複雑)300-500ms
コンポーネントの寸法
コンポーネント高さ最小幅
ボタン40dp64dp
FAB56dp56dp
テキストフィールド56dp280dp
アプリバー64dp-
ボトムナビゲーション80dp-
アンチパターン(必ず避けること)
UI のアンチパターン
  • ボトムナビゲーションの項目が 5 つを超える
  • 同じ画面に複数の FAB を配置する
  • タッチターゲットが 48dp 未満
  • 間隔に一貫性がない(8dp の倍数ではない)
  • ダークテーマに対応していない
  • コントラストを確認せずに色付きの背景にテキストを配置する
パフォーマンスのアンチパターン
  • 進行状況インジケーターがない状態で起動時間が 2 秒を超える
  • フレームレートが 60 FPS 未満(1 フレームあたり 16ms 超)
  • クラッシュ率が 1.09% を超える(Google Play のしきい値)
  • ANR 率が 0.47% を超える(Google Play のしきい値)
アクセシビリティのアンチパターン
  • インタラクティブ要素に contentDescription が設定されていない
  • ラベルに要素の種類が含まれている(例:「保存ボタン」ではなく「保存」)
  • 子ども向けアプリで複雑なジェスチャーを使う
  • 読み書きができないユーザー向けにテキストのみのボタンを使う
レビューチェックリスト
  • 8dp 間隔グリッドに準拠している
  • タッチターゲットが最小 48dp である
  • タイポグラフィのスケールが適切に使われている
  • 色のコントラストに準拠している(テキストは 4.5:1 以上)
  • ダークテーマに対応している
  • すべてのインタラクティブ要素に contentDescription が設定されている
  • 起動時間が 2 秒未満、または進行状況を表示する
  • ビジュアルスタイルがアプリのカテゴリに合っている
デザインの参考資料
トピック参考資料
色、タイポグラフィ、間隔、形状ビジュアルデザイン
アニメーションとトランジションモーションシステム
アクセシビリティのガイドラインアクセシビリティ
大画面と折りたたみ式デバイスアダプティブ画面
Android Vitals とパフォーマンスパフォーマンスと安定性
プライバシーとセキュリティプライバシーとセキュリティ
オーディオ、動画、通知機能要件
カテゴリ別のアプリスタイルデザインスタイルガイド

8. テスト

注:ユーザーがテストを明示的に求めた場合にのみ、テストの依存関係を追加してください。

十分にテストされた Android アプリでは、階層化されたテストを使用します。ロジックには高速なローカル単体テスト、UI と統合にはインストルメンテーションテストを使い、Gradle Managed Devices でエミュレーターを再現性高く実行します。CI を含め、どのマシンでも実行できます。

8.1 テスト依存関係

テスト依存関係を追加する前に、競合を避けるため、プロジェクトで既に使用されているバージョンを確認します。

  1. gradle/libs.versions.toml を確認します。存在する場合は、プロジェクトのバージョンカタログのスタイルに合わせてテスト依存関係を追加します
  2. 既存の build.gradle.kts を確認し、バージョンが既に固定された依存関係がないか確認します
  3. 以下の表に従って、バージョン系列を合わせます

バージョンの整合性ルール:

テスト依存関係整合させる対象確認方法
kotlinx-coroutines-testプロジェクトの kotlinx-coroutines-core バージョンビルドファイルまたはバージョンカタログで kotlinx-coroutines を検索します
compose-ui-test-junit4プロジェクトの Compose BOM または compose-compilerビルドファイルで compose-bom または compose.compiler を検索します
espresso-*すべての Espresso アーティファクトで同じバージョンを使用しますビルドファイルで espresso を検索します
androidx.test:runner、rules、ext:junit互換性のある AndroidX Test バージョンを使用しますビルドファイルで androidx.test を検索します
mockkプロジェクトの Kotlin バージョンをサポートしている必要がありますルートの build.gradle.kts またはバージョンカタログで kotlin のバージョンを確認します

依存関係のリファレンス — 必要なグループだけを追加します。

dependencies {
    // --- Local unit tests (src/test/) ---
    testImplementation("junit:junit:<version>")                          // 4.13.2+
    testImplementation("org.robolectric:robolectric:<version>")          // 4.16.1+
    testImplementation("io.mockk:mockk:<version>")                      // match Kotlin version
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:<version>")  // match coroutines-core
    testImplementation("androidx.arch.core:core-testing:<version>")      // InstantTaskExecutorRule for LiveData
    testImplementation("app.cash.turbine:turbine:<version>")             // Flow/StateFlow testing

    // --- Instrumentation tests (src/androidTest/) ---
    androidTestImplementation("androidx.test.ext:junit:<version>")
    androidTestImplementation("androidx.test:runner:<version>")
    androidTestImplementation("androidx.test:rules:<version>")
    androidTestImplementation("androidx.test.espresso:espresso-core:<version>")
    androidTestImplementation("androidx.test.espresso:espresso-contrib:<version>")   // RecyclerView, Drawer
    androidTestImplementation("androidx.test.espresso:espresso-intents:<version>")   // Intent verification
    androidTestImplementation("androidx.test.espresso:espresso-idling-resource:<version>")
    androidTestImplementation("androidx.test.uiautomator:uiautomator:<version>")

    // --- Compose UI tests (only if project uses Compose) ---
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")      // version from Compose BOM
    debugImplementation("androidx.compose.ui:ui-test-manifest")          // required for createComposeRule
}

注:プロジェクトで Compose BOM を使用している場合、ui-test-junit4 と ui-test-manifest に明示的なバージョンを指定する必要はありません。BOM が管理します。

android ブロックで Robolectric のリソースサポートを有効にします。

android {
    testOptions {
        unitTests.isIncludeAndroidResources = true  // required for Robolectric
    }
}
8.2 レイヤーごとのテスト
レイヤー場所実行環境速度用途
ユニット(JUnit)src/test/JVM約 msViewModel、リポジトリ、マッパー、バリデーター
ユニット+Robolectricsrc/test/JVM+シミュレートされた Android約100msContext、リソース、SharedPrefs が必要なコード
Compose UI(ローカル)src/test/JVM+Robolectric約100msComposable のレンダリングと操作
Espressosrc/androidTest/デバイス/エミュレーター約数秒View ベースの UI フロー、Intent、DB 統合
Compose UI(デバイス)src/androidTest/デバイス/エミュレーター約数秒実際のレンダリングを使った Compose UI の完全なフロー
UI Automatorsrc/androidTest/デバイス/エミュレーター約数秒システムダイアログ、通知、複数アプリ
マネージドデバイスsrc/androidTest/Gradle 管理の AVD約数分(初回実行時)CI、API レベルをまたいだマトリックステスト

詳しい例、コードパターン、Gradle Managed Device の設定については、テストを参照してください。

8.3 テストコマンド
# Local unit tests (fast, no emulator)
./gradlew test                          # all modules
./gradlew :app:testDebugUnitTest        # app module, debug variant

# Single test class
./gradlew :app:testDebugUnitTest --tests "com.example.myapp.CounterViewModelTest"

# Instrumentation tests (requires device or managed device)
./gradlew connectedDebugAndroidTest     # on connected device
./gradlew pixel6Api34DebugAndroidTest   # on managed device

# Both together
./gradlew test connectedDebugAndroidTest

# Test with coverage report (JaCoCo)
./gradlew testDebugUnitTest jacocoTestReport

コメント