Source profileQuality 89/100

MiniMax-AI/skills/skills/android-native-dev/SKILL.md

android-native-dev

Android native application development and UI design guide. Covers Material Design 3, Kotlin/Compose development, project configuration, accessibility, and build troubleshooting. Read this before Android native application development.

Source repository stars
13,218
Declared platforms
0
Static risk flags
1
Last source update
2026-04-18
Source checked
2026-08-04

Decision brief

What it does—and where it fits

Before starting development, assess the current project state:

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/MiniMax-AI/skills --skill "skills/android-native-dev"
    Safe inspection promptEditorial

    Inspect the Agent Skill "android-native-dev" from https://github.com/MiniMax-AI/skills/blob/60aaae52bb2af8162732751a4332f62a5fef518b/skills/android-native-dev/SKILL.md at commit 60aaae52bb2af8162732751a4332f62a5fef518b. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      1. Project Scenario Assessment

      Before starting development, assess the current project state:

      Before writing business logic, ensure ./gradlew assembleDebug succeedsIf gradle.properties is missing, create it first and configure AndroidXBefore starting development, assess the current project state:
    2. 02

      3.8 Logging Level Usage

      Review the “3.8 Logging Level Usage” section in the pinned source before continuing.

      Review and apply the “3.8 Logging Level Usage” source section.
    3. 03

      Review Checklist

      [ ] 8dp spacing grid compliance

      [ ] 8dp spacing grid compliance[ ] 48dp minimum touch targets[ ] Proper typography scale usage
    4. 04

      1.1 Required Files Checklist

      Review the “1.1 Required Files Checklist” section in the pinned source before continuing.

      Review and apply the “1.1 Required Files Checklist” source section.
    5. 05

      2. Project Configuration

      Review the “2. Project Configuration” section in the pinned source before continuing.

      Review and apply the “2. Project Configuration” source section.

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 95

    The documentation includes network, browsing, or remote request actions.

    buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")

    Network access

    medium · line 107

    The documentation includes network, browsing, or remote request actions.

    buildConfigField("String", "API_BASE_URL", "\"https://staging-api.example.com\"")

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score89/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars13,218SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    MiniMax-AI/skills
    Skill path
    skills/android-native-dev/SKILL.md
    Commit
    60aaae52bb2af8162732751a4332f62a5fef518b
    License
    MIT
    Collected
    2026-08-04
    Default branch
    main
    View the original SKILL.md

    1. Project Scenario Assessment

    Before starting development, assess the current project state:

    ScenarioCharacteristicsApproach
    Empty DirectoryNo files presentFull initialization required, including Gradle Wrapper
    Has Gradle Wrappergradlew and gradle/wrapper/ existUse ./gradlew directly for builds
    Android Studio ProjectComplete project structure, may lack wrapperCheck wrapper, run gradle wrapper if needed
    Incomplete ProjectPartial files presentCheck missing files, complete configuration

    Key Principles:

    • Before writing business logic, ensure ./gradlew assembleDebug succeeds
    • If gradle.properties is missing, create it first and configure AndroidX

    1.1 Required Files Checklist

    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. Project Configuration

    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
    

    Note: If you encounter OutOfMemoryError during build, increase -Xmx value. Large projects with many dependencies may require 8GB or more.

    2.2 Dependency Declaration Standards

    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 Build Variants & Product Flavors

    Product Flavors allow you to create different versions of your app (e.g., free/paid, dev/staging/prod).

    Configuration in 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")
            }
        }
    }
    

    Build Variant Naming: {flavor}{BuildType} → e.g., devDebug, prodRelease

    Gradle Build Commands:

    # 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
    

    Access BuildConfig in Code:

    Note: Starting from AGP 8.0, BuildConfig is no longer generated by default. You must explicitly enable it in your 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
    }
    

    Flavor-Specific Source Sets:

    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
    

    Multiple Flavor Dimensions (e.g., environment + tier):

    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 Development Standards

    3.1 Naming Conventions

    TypeConventionExample
    Class/InterfacePascalCaseUserRepository, MainActivity
    Function/VariablecamelCasegetUserName(), isLoading
    ConstantSCREAMING_SNAKEMAX_RETRY_COUNT
    Packagelowercasecom.example.myapp
    ComposablePascalCase@Composable fun UserCard()

    3.2 Code Standards (Important)

    Null Safety:

    // ❌ 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) }
    

    Exception Handling:

    // ❌ 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 Threading & Coroutines (Critical)

    Thread Selection Principles:

    Operation TypeThreadDescription
    UI UpdatesDispatchers.MainUpdate View, State, LiveData
    Network RequestsDispatchers.IOHTTP calls, API requests
    File I/ODispatchers.IOLocal storage, database operations
    Compute IntensiveDispatchers.DefaultJSON parsing, sorting, encryption

    Correct Usage:

    // 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()
    }
    

    Common Mistakes:

    // ❌ 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 Visibility Rules

    // 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 Common Syntax Pitfalls

    // ❌ 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 Server Response Data Class Fields Must Be 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 Lifecycle Resource Management

    // ❌ 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 Logging Level Usage

    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}")
    
    LevelUse Case
    i (Info)Normal flow, method entry, key parameters
    w (Warning)Recoverable exceptions, fallback handling, null returns
    e (Error)Request failures, caught exceptions, unrecoverable errors

    4. Jetpack Compose Standards

    4.1 @Composable Context Rules

    // ❌ 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 State Management

    // 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 Common Compose Mistakes

    // ❌ 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. Resources & Icons

    5.1 App Icon Requirements

    Must provide multi-resolution icons:

    DirectorySizePurpose
    mipmap-mdpi48x48Baseline
    mipmap-hdpi72x721.5x
    mipmap-xhdpi96x962x
    mipmap-xxhdpi144x1443x
    mipmap-xxxhdpi192x1924x

    Recommended: Use Adaptive Icon (Android 8+):

    <!-- res/mipmap-anydpi-v26/ic_launcher.xml -->
    <adaptive-icon>
        <background android:drawable="@color/ic_launcher_background"/>
        <foreground android:drawable="@mipmap/ic_launcher_foreground"/>
    </adaptive-icon>
    

    5.2 Resource Naming Conventions

    TypePrefixExample
    Layoutlayout_layout_main.xml
    Imageic_, img_, bg_ic_user.png
    Colorcolor_color_primary
    String-app_name, btn_submit

    5.3 Avoid Android Reserved Names (Important)

    Variable names, resource IDs, colors, icons, and XML elements must not use Android reserved words or system resource names. Using reserved names causes build errors or resource conflicts.

    Common Reserved Names to Avoid:

    CategoryReserved Names (Do NOT Use)
    Colorsbackground, foreground, transparent, white, black
    Icons/Drawablesicon, logo, image, drawable
    Viewsview, text, button, layout, container
    Attributesid, name, type, style, theme, color
    Systemapp, android, content, data, action

    Examples:

    <!-- ❌ Wrong: Using reserved names -->
    <color name="background">#FFFFFF</color>
    <color name="icon">#000000</color>
    
    <!-- ✅ Correct: Add prefix or specific naming -->
    <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
    
    <!-- ❌ Wrong: Drawable name conflicts -->
    <ImageView android:src="@drawable/icon" />
    
    <!-- ✅ Correct: Add prefix -->
    <ImageView android:src="@drawable/ic_home" />
    

    6. Build Error Diagnosis & Fixes

    6.1 Common Error Quick Reference

    Error KeywordCauseFix
    Unresolved referenceMissing import or undefinedCheck imports, verify dependencies
    Type mismatchType incompatibilityCheck parameter types, add conversion
    Cannot accessVisibility issueCheck public/private/internal
    @Composable invocationsComposable context errorEnsure caller is also @Composable
    Duplicate classDependency conflictUse ./gradlew dependencies to investigate
    AAPT: errorResource file errorCheck XML syntax and resource references

    6.2 Fix Best Practices

    1. Read the complete error message first: Locate file and line number
    2. Check recent changes: Problems usually in latest modifications
    3. Clean Build: ./gradlew clean assembleDebug
    4. Check dependency versions: Version conflicts are common causes
    5. Refresh dependencies if needed: Clear cache and rebuild

    6.3 Debugging Commands

    # 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 Guidelines

    Review Android UI files for compliance with Material Design 3 Guidelines and Android best practices.

    Design Philosophy

    M3 Core Principles

    PrincipleDescription
    PersonalDynamic color based on user preferences and wallpaper
    AdaptiveResponsive across all screen sizes and form factors
    ExpressiveBold colors and typography with personality
    AccessibleInclusive design for all users

    M3 Expressive (Latest)

    The latest evolution adds emotion-driven UX through:

    • Vibrant, dynamic colors
    • Intuitive motion physics
    • Adaptive components
    • Flexible typography
    • Contrasting shapes (35 new shape options)

    App Style Selection

    Critical Decision: Match visual style to app category and target audience.

    App CategoryVisual StyleKey Characteristics
    Utility/ToolMinimalistClean, efficient, neutral colors
    Finance/BankingProfessional TrustConservative colors, security-focused
    Health/WellnessCalm & NaturalSoft colors, organic shapes
    Kids (3-5)Playful SimpleBright colors, large targets (56dp+)
    Kids (6-12)Fun & EngagingVibrant, gamified feedback
    Social/EntertainmentExpressiveBrand-driven, gesture-rich
    ProductivityClean & FocusedMinimal, high contrast
    E-commerceConversion-focusedClear CTAs, scannable

    See Design Style Guide for detailed style profiles.

    Quick Reference: Key Specifications

    Color Contrast Requirements

    ElementMinimum Ratio
    Body text4.5:1
    Large text (18sp+)3:1
    UI components3:1

    Touch Targets

    TypeSize
    Minimum48 × 48dp
    Recommended (primary actions)56 × 56dp
    Kids apps56dp+
    Spacing between targets8dp minimum

    8dp Grid System

    TokenValueUsage
    xs4dpIcon padding
    sm8dpTight spacing
    md16dpDefault padding
    lg24dpSection spacing
    xl32dpLarge gaps
    xxl48dpScreen margins

    Typography Scale (Summary)

    CategorySizes
    Display57sp, 45sp, 36sp
    Headline32sp, 28sp, 24sp
    Title22sp, 16sp, 14sp
    Body16sp, 14sp, 12sp
    Label14sp, 12sp, 11sp

    Animation Duration

    TypeDuration
    Micro (ripples)50-100ms
    Short (simple)100-200ms
    Medium (expand/collapse)200-300ms
    Long (complex)300-500ms

    Component Dimensions

    ComponentHeightMin Width
    Button40dp64dp
    FAB56dp56dp
    Text Field56dp280dp
    App Bar64dp-
    Bottom Nav80dp-

    Anti-Patterns (Must Avoid)

    UI Anti-Patterns

    • More than 5 bottom navigation items
    • Multiple FABs on same screen
    • Touch targets smaller than 48dp
    • Inconsistent spacing (non-8dp multiples)
    • Missing dark theme support
    • Text on colored backgrounds without contrast check

    Performance Anti-Patterns

    • Startup time > 2 seconds without progress indicator
    • Frame rate < 60 FPS (> 16ms per frame)
    • Crash rate > 1.09% (Google Play threshold)
    • ANR rate > 0.47% (Google Play threshold)

    Accessibility Anti-Patterns

    • Missing contentDescription on interactive elements
    • Element type in labels (e.g., "Save button" instead of "Save")
    • Complex gestures in kids apps
    • Text-only buttons for non-readers

    Review Checklist

    • 8dp spacing grid compliance
    • 48dp minimum touch targets
    • Proper typography scale usage
    • Color contrast compliance (4.5:1+ for text)
    • Dark theme support
    • contentDescription on all interactive elements
    • Startup < 2 seconds or shows progress
    • Visual style matches app category

    Design References

    TopicReference
    Colors, Typography, Spacing, ShapesVisual Design
    Animation & TransitionsMotion System
    Accessibility GuidelinesAccessibility
    Large Screens & FoldablesAdaptive Screens
    Android Vitals & PerformancePerformance & Stability
    Privacy & SecurityPrivacy & Security
    Audio, Video, NotificationsFunctional Requirements
    App Style by CategoryDesign Style Guide

    8. Testing

    Note: Only add test dependencies when the user explicitly asks for testing.

    A well-tested Android app uses layered testing: fast local unit tests for logic, instrumentation tests for UI and integration, and Gradle Managed Devices to run emulators reproducibly on any machine — including CI.

    8.1 Test Dependencies

    Before adding test dependencies, inspect the project's existing versions to avoid conflicts:

    1. Check gradle/libs.versions.toml — if present, add test deps using the project's version catalog style
    2. Check existing build.gradle.kts for already-pinned dependency versions
    3. Match version families using the table below

    Version Alignment Rules:

    Test DependencyMust Align WithHow to Check
    kotlinx-coroutines-testProject's kotlinx-coroutines-core versionSearch for kotlinx-coroutines in build files or version catalog
    compose-ui-test-junit4Project's Compose BOM or compose-compilerSearch for compose-bom or compose.compiler in build files
    espresso-*All Espresso artifacts must use the same versionSearch for espresso in build files
    androidx.test:runner, rules, ext:junitShould use compatible AndroidX Test versionsSearch for androidx.test in build files
    mockkMust support the project's Kotlin versionCheck kotlin version in root build.gradle.kts or version catalog

    Dependencies Reference — add only the groups you need:

    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
    }
    

    Note: If the project uses a Compose BOM, ui-test-junit4 and ui-test-manifest don't need explicit versions — the BOM manages them.

    Enable Robolectric resource support in the android block:

    android {
        testOptions {
            unitTests.isIncludeAndroidResources = true  // required for Robolectric
        }
    }
    

    8.2 Testing by Layer

    LayerLocationRuns OnSpeedUse For
    Unit (JUnit)src/test/JVM~msViewModels, repos, mappers, validators
    Unit + Robolectricsrc/test/JVM + simulated Android~100msCode needing Context, resources, SharedPrefs
    Compose UI (local)src/test/JVM + Robolectric~100msComposable rendering & interaction
    Espressosrc/androidTest/Device/Emulator~secondsView-based UI flows, Intents, DB integration
    Compose UI (device)src/androidTest/Device/Emulator~secondsFull Compose UI flows with real rendering
    UI Automatorsrc/androidTest/Device/Emulator~secondsSystem dialogs, notifications, multi-app
    Managed Devicesrc/androidTest/Gradle-managed AVD~minutes (first run)CI, matrix testing across API levels

    See Testing for detailed examples, code patterns, and Gradle Managed Device configuration.

    8.3 Testing Commands

    # 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
    

    Alternatives

    Compare before choosing

    Computed 10042,968

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 100165

    JasonColapietro/suede-creator-skills

    suede-ab-testing

    Suede-owned experimentation discipline for hypotheses, sample sizing, test duration, significance, and repeatable experiment programs. Use when comparing variants, deciding whether a result is reliable, or building an experiment backlog and cadence. NOT FOR: analytics instrumentation (use suede-analytics), post-click conversion diagnosis (use suede-site-alchemy), or writing the variant copy itself (use suede-copy).

    Computed 1007

    narrative-io/narrative-skills-marketplace

    design-analysis

    Translate a fuzzy analytical question into a rigorous investigation plan. Interrogates the ask, grounds the plan in the available data dictionary, applies analytical best practices, and produces a structured brief of query specifications for a downstream query-writing skill. Plans, does not write SQL. Use when: "why did X drop", "is there a relationship between A and B", "who are our highest-value customers", "what's driving the change in Y", "investigate this trend", "design an analysis for", "

    Computed 1007

    event4u-app/agent-config

    existing-ui-audit

    Use BEFORE writing or editing any non-trivial UI — inventories components, design tokens, shadcn primitives, and reusable patterns into state.ui_audit. Hard gate for the ui directive set.