返回全部 Skills

android-native-dev

开发工具 官方认证

Android原生应用开发和UI设计指南。涵盖Material Design 3、Kotlin/Compose开发、项目配置、无障碍性和构建问题排查。请在开始Android原生应用开发前阅读本文。

44

下载量

AI SkillHub 能力展示图

安装方式

命令行安装

在项目根目录执行以下命令,完成 Skill 安装。

npx bzskills add MiniMax-AI/skills --skill android-native-dev

skill.md

name: android-native-dev
description: Android原生应用开发和UI设计指南。涵盖Material Design 3、Kotlin/Compose开发、项目配置、无障碍性和构建问题排查。请在开始Android原生应用开发前阅读本文。
license: MIT
metadata:
    version: "1.0.0"
    category: mobile
    sources:
        - Material Design 3 Guidelines (material.io)
        - Android Developer Documentation (developer.android.com)
        - Google Play Quality Guidelines
        - WCAG Accessibility Guidelines

1. 项目场景评估

在开始开发之前,评估当前项目状态:

场景特征处理方法
空目录无任何文件需要完整初始化,包括 Gradle Wrapper
已有 Gradle Wrapper存在 gradlewgradle/wrapper/ 目录直接使用 ./gradlew 构建
Android Studio 项目完整的项目结构,可能缺少 Wrapper检查 Wrapper,如需则运行 gradle wrapper
不完整的项目部分文件存在检查缺失文件,补全配置

关键原则

  • 在编写业务逻辑前,确保 ./gradlew assembleDebug 成功执行
  • 如果缺少 gradle.properties,先创建并配置 AndroidX

1.1 必需文件清单

MyApp/
├── gradle.properties          # 配置 AndroidX 和其他设置
├── settings.gradle.kts
├── build.gradle.kts           # 根级别
├── gradle/wrapper/
│   └── gradle-wrapper.properties
├── app/
│   ├── build.gradle.kts       # 模块级别
│   └── src/main/
│       ├── AndroidManifest.xml
│       ├── java/com/example/myapp/
│       │   └── MainActivity.kt
│       └── res/
│           ├── values/
│           │   ├── strings.xml
│           │   ├── colors.xml
│           │   └── themes.xml
│           └── mipmap-*/       # 应用图标

---

2. 项目配置

2.1 gradle.properties

# 必需配置
android.useAndroidX=true
android.enableJetifier=true

# 构建优化
org.gradle.parallel=true
kotlin.code.style=official

# JVM 内存设置(根据项目规模调整)
# 小项目:2048m,中等项目:4096m,大项目:8192m+
# org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
注意:如果构建过程中遇到 OutOfMemoryError,增加 -Xmx 值。依赖较多的大型项目可能需要 8GB 或更多。

2.2 依赖声明标准

dependencies {
    // 使用 BOM 管理 Compose 版本
    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 {
    // 定义风味维度
    flavorDimensions += "environment"
    
    productFlavors {
        create("dev") {
            dimension = "environment"
            applicationIdSuffix = ".dev"
            versionNameSuffix = "-dev"
            
            // 每个风味不同的配置值
            buildConfigField("String", "API_BASE_URL", "\"https://dev-api.example.com\"")
            buildConfigField("Boolean", "ENABLE_LOGGING", "true")
            
            // 不同资源
            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"
            // 生产环境不加后缀
            
            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")
        }
    }
}

构建变体命名{风味}{构建类型} → 例如 devDebugprodRelease

Gradle 构建命令

# 列出所有可用的构建变体
./gradlew tasks --group="build"

# 构建特定变体(风味 + 构建类型)
./gradlew assembleDevDebug        # Dev 风味,Debug 构建
./gradlew assembleStagingDebug    # Staging 风味,Debug 构建
./gradlew assembleProdRelease     # Prod 风味,Release 构建

# 构建特定风味的所有变体
./gradlew assembleDev             # 所有 Dev 变体(debug + release)
./gradlew assembleProd            # 所有 Prod 变体

# 构建特定构建类型的所有变体
./gradlew assembleDebug           # 所有风味的 Debug 构建
./gradlew assembleRelease         # 所有风味的 Release 构建

# 安装特定变体到设备
./gradlew installDevDebug
./gradlew installProdRelease

# 一键构建并安装
./gradlew installDevDebug && adb shell am start -n com.example.myapp.dev/.MainActivity

在代码中访问 BuildConfig

注意:从 AGP 8.0 开始,BuildConfig 默认不再生成。必须在 build.gradle.kts 中显式启用:
```kotlin
android {
buildFeatures {
buildConfig = true
}
}
```
// 在代码中使用构建配置值
val apiUrl = BuildConfig.API_BASE_URL
val isLoggingEnabled = BuildConfig.ENABLE_LOGGING

if (BuildConfig.DEBUG) {
    // 仅调试模式下的代码
}

风味特定的源集

app/src/
├── main/           # 所有风味共享的代码
├── dev/            # Dev 独有的代码和资源
│   ├── java/
│   └── res/
├── staging/        # Staging 独有的代码和资源
├── prod/           # Prod 独有的代码和资源
├── debug/          # Debug 构建类型代码
└── release/        # Release 构建类型代码

多个风味维度(例如 environment + tier):

android {
    flavorDimensions += listOf("environment", "tier")
    
    productFlavors {
        create("dev") { dimension = "environment" }
        create("prod") { dimension = "environment" }
        
        create("free") { dimension = "tier" }
        create("paid") { dimension = "tier" }
    }
}
// 结果:devFreeDebug, devPaidDebug, prodFreeRelease 等

---

3. Kotlin 开发标准

3.1 命名约定

类型约定示例
类/接口PascalCaseUserRepository, MainActivity
函数/变量camelCasegetUserName(), isLoading
常量SCREAMING_SNAKEMAX_RETRY_COUNT
包名小写com.example.myapp
Composable 函数PascalCase@Composable fun UserCard()

3.2 代码标准(重要)

空安全

// ❌ 避免:非空断言 !! (可能崩溃)
val name = user!!.name

// ✅ 推荐:安全调用 + 默认值
val name = user?.name ?: "Unknown"

// ✅ 推荐:let 处理
user?.let { processUser(it) }

异常处理

// ❌ 避免:在业务层随意使用 try-catch 吞掉异常
fun loadData() {
    try {
        val data = api.fetch()
    } catch (e: Exception) {
        // 吞掉异常,难以调试
    }
}

// ✅ 推荐:让异常传播,在合适层次处理
suspend fun loadData(): Result<Data> {
    return try {
        Result.success(api.fetch())
    } catch (e: Exception) {
        Result.failure(e)  // 包裹并返回,让调用方决定处理
    }
}

// ✅ 推荐:在 ViewModel 中统一处理
viewModelScope.launch {
    runCatching { repository.loadData() }
        .onSuccess { _uiState.value = UiState.Success(it) }
        .onFailure { _uiState.value = UiState.Error(it.message) }
}

3.3 线程与协程(关键)

线程选择原则

操作类型线程描述
UI 更新Dispatchers.Main更新 View、State、LiveData
网络请求Dispatchers.IOHTTP 调用、API 请求
文件 I/ODispatchers.IO本地存储、数据库操作
计算密集型Dispatchers.DefaultJSON 解析、排序、加密

正确用法

// 在 ViewModel 中
viewModelScope.launch {
    // 默认在主线程,可以更新 UI State
    _uiState.value = UiState.Loading
    
    // 切换到 IO 线程进行网络请求
    val result = withContext(Dispatchers.IO) {
        repository.fetchData()
    }
    
    // 自动返回主线程,更新 UI
    _uiState.value = UiState.Success(result)
}

// 在 Repository 中(挂起函数应为主线程安全)
suspend fun fetchData(): Data = withContext(Dispatchers.IO) {
    api.getData()
}

常见错误

// ❌ 错误:在 IO 线程更新 UI
viewModelScope.launch(Dispatchers.IO) {
    val data = api.fetch()
    _uiState.value = data  // 崩溃或警告!
}

// ❌ 错误:在主线程执行耗时操作
viewModelScope.launch {
    val data = api.fetch()  // 阻塞主线程!ANR
}

// ✅ 正确:在 IO 线程获取数据,在主线程更新
viewModelScope.launch {
    val data = withContext(Dispatchers.IO) { api.fetch() }
    _uiState.value = data
}

3.4 可见性规则

// 默认为 public,需要时显式声明
class UserRepository {           // public
    private val cache = mutableMapOf<String, User>()  // 仅在类内可见
    internal fun clearCache() {} // 仅在模块内可见
}

// data class 属性默认为 public,跨模块使用时需小心
data class User(
    val id: String,       // public
    val name: String
)

3.5 常见语法陷阱

// ❌ 错误:访问未初始化的 lateinit
class MyViewModel : ViewModel() {
    lateinit var data: String
    fun process() = data.length  // 可能崩溃
}

// ✅ 正确:使用可空类型或默认值
class MyViewModel : ViewModel() {
    var data: String? = null
    fun process() = data?.length ?: 0
}

// ❌ 错误:在 lambda 中使用 return
list.forEach { item ->
    if (item.isEmpty()) return  // 从外部函数返回!
}

// ✅ 正确:使用 return@forEach
list.forEach { item ->
    if (item.isEmpty()) return@forEach
}

3.6 服务端响应数据类字段必须可为空

// ❌ 错误:字段声明为非空(服务端可能不返回)
data class UserResponse(
    val id: String = "",
    val name: String = "",
    val avatar: String = ""
)

// ✅ 正确:所有字段声明为可空
data class UserResponse(
    @SerializedName("id")
    val id: String? = null,
    @SerializedName("name")
    val name: String? = null,
    @SerializedName("avatar")
    val avatar: String? = null
)

3.7 生命周期资源管理

// ❌ 错误:只添加 Observer,不删除
class MyView : View {
    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        activity?.lifecycle?.addObserver(this)
    }
    // 内存泄漏!
}

// ✅ 正确:配对添加和删除
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:正常流程的关键检查点
Log.i(TAG, "loadData: started, userId = $userId")

// Warning:可恢复的异常情况
Log.w(TAG, "loadData: cache miss, fallback to network")

// Error:失败/错误情况
Log.e(TAG, "loadData failed: ${error.message}")
级别使用场景
i (Info)正常流程、方法入口、关键参数
w (Warning)可恢复异常、回退处理、空返回
e (Error)请求失败、捕获到的异常、不可恢复错误

---

4. Jetpack Compose 标准

4.1 @Composable 上下文规则

// ❌ 错误:从非 Composable 函数中调用 Composable
fun showError(message: String) {
    Text(message)  // 编译错误!
}

// ✅ 正确:标记为 @Composable
@Composable
fun ErrorMessage(message: String) {
    Text(message)
}

// ❌ 错误:在 LaunchedEffect 之外使用 suspend
@Composable
fun MyScreen() {
    val data = fetchData()  // 错误!
}

// ✅ 正确:使用 LaunchedEffect
@Composable
fun MyScreen() {
    var data by remember { mutableStateOf<Data?>(null) }
    LaunchedEffect(Unit) {
        data = fetchData()
    }
}

4.2 状态管理

// 基本状态
var count by remember { mutableStateOf(0) }

// 派生状态(避免重复计算)
val isEven by remember { derivedStateOf { count % 2 == 0 } }

// 跨重组持久化(例如滚动位置)
val scrollState = rememberScrollState()

// ViewModel 中的状态
class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(UiState())
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()
}

4.3 常见 Compose 错误

// ❌ 错误:在 Composable 中创建对象(每次重组都会创建)
@Composable
fun MyScreen() {
    val viewModel = MyViewModel()  // 错误!
}

// ✅ 正确:使用 viewModel() 或 remember
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
    // ...
}

---

5. 资源与图标

5.1 应用图标要求

必须提供多分辨率图标:

目录尺寸用途
mipmap-mdpi48x48基准
mipmap-hdpi72x721.5x
mipmap-xhdpi96x962x
mipmap-xxhdpi144x1443x
mipmap-xxxhdpi192x1924x

推荐:使用自适应图标(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 资源命名约定

类型前缀示例
布局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>
// ❌ 错误:变量名与系统冲突
val icon = R.drawable.my_icon
val background = Color.White

// ✅ 正确:使用描述性名称
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 调试命令

# 清理并构建
./gradlew clean assembleDebug

# 查看依赖树(调查冲突)
./gradlew :app:dependencies

# 查看详细错误
./gradlew assembleDebug --stacktrace

# 刷新依赖
./gradlew --refresh-dependencies

---

7. Material Design 3 指南

审查 Android UI 文件,确保符合 Material Design 3 指南和 Android 最佳实践。

设计理念

#### M3 核心原则

原则描述
个性化基于用户偏好和壁纸的动态颜色
自适应响应所有屏幕尺寸和形态因素
表现力大胆的色彩和字体,彰显个性
无障碍为所有用户设计的包容性设计

#### M3 表现力(最新)

最新演进通过以下方式增加情感驱动的 UX:

  • 鲜艳、动态的颜色
  • 直观的动效物理
  • 自适应组件
  • 灵活的排版
  • 对比形状(35 种新形状选项)

应用风格选择

关键决策:将视觉风格与应用类别和目标受众匹配。

应用类别视觉风格主要特征
工具/实用极简干净、高效、中性颜色
金融/银行专业信任保守颜色、安全第一
健康/养生平静自然柔和颜色、有机形状
儿童(3-5岁)趣味简单鲜艳颜色、大触摸目标(56dp+)
儿童(6-12岁)有趣互动活力四射、游戏化反馈
社交/娱乐表现力品牌驱动、手势丰富
生产力干净专注极简、高对比度
电子商务转化导向清晰的行动号召、便于扫描

详细风格配置文件请参阅 [设计风格指南](references/design-style-guide.md)。

快速参考:关键规格

#### 颜色对比度要求

元素最小比率
正文4.5:1
大字体(18sp+)3:1
UI 组件3:1

#### 触摸目标

类型尺寸
最小48 × 48dp
推荐(主要操作)56 × 56dp
儿童应用56dp+
目标之间间距最小 8dp

#### 8dp 网格系统

令牌用法
xs4dp图标内边距
sm8dp紧凑间距
md16dp默认内边距
lg24dp区块间距
xl32dp大间隔
xxl48dp屏幕边距

#### 字体比例(概要)

类别字号
Display57sp, 45sp, 36sp
Headline32sp, 28sp, 24sp
Title22sp, 16sp, 14sp
Body16sp, 14sp, 12sp
Label14sp, 12sp, 11sp

#### 动画时长

类型时长
微动效(波纹)50-100ms
短动效(简单)100-200ms
中动效(展开/折叠)200-300ms
长动效(复杂)300-500ms

#### 组件尺寸

组件高度最小宽度
按钮40dp64dp
浮动操作按钮56dp56dp
文本字段56dp280dp
应用栏64dp-
底部导航栏80dp-

反模式(必须避免)

#### UI 反模式

  • 底部导航超过 5 项
  • 同一屏幕多个浮动操作按钮
  • 触摸目标小于 48dp
  • 间距不一致(非 8dp 倍数)
  • 缺少深色主题支持
  • 未检查对比度就在彩色背景上放置文字

#### 性能反模式

  • 启动时间超过 2 秒,无进度指示器
  • 帧率低于 60 FPS(每帧超过 16ms)
  • 崩溃率超过 1.09%(Google Play 阈值)
  • ANR 率超过 0.47%(Google Play 阈值)

#### 无障碍反模式

  • 交互元素缺少 contentDescription
  • 标签中包含元素类型(例如“保存按钮”而非“保存”)
  • 儿童应用中包含复杂手势
  • 非阅读用户仅有文字按钮

审查清单

  • [ ] 符合 8dp 间距网格
  • [ ] 最小触摸目标 48dp
  • [ ] 正确使用字体比例
  • [ ] 颜色对比度合规(文本 4.5:1+)
  • [ ] 支持深色主题
  • [ ] 所有交互元素都有 contentDescription
  • [ ] 启动时间小于 2 秒或显示进度
  • [ ] 视觉风格与应用类别匹配

设计参考

主题参考
颜色、排版、间距、形状[视觉设计](references/visual-design.md)
动画与过渡[动效系统](references/motion-system.md)
无障碍指南[无障碍](references/accessibility.md)
大屏幕与折叠屏[自适应屏幕](references/adaptive-screens.md)
Android 核心指标与性能[性能与稳定性](references/performance-stability.md)
隐私与安全[隐私与安全](references/privacy-security.md)
音频、视频、通知[功能需求](references/functional-requirements.md)
按类别划分的应用风格[设计风格指南](references/design-style-guide.md)

---

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-bomcompose.compiler
espresso-*所有 Espresso 构件必须使用相同版本在构建文件中搜索 espresso
androidx.test:runner, rules, ext:junit应使用兼容的 AndroidX Test 版本在构建文件中搜索 androidx.test
mockk必须支持项目的 Kotlin 版本在根 build.gradle.kts 或版本目录中检查 kotlin 版本

依赖参考 —— 仅添加你需要的组:

dependencies {
    // --- 本地单元测试 (src/test/) ---
    testImplementation("junit:junit:<version>")                          // 4.13.2+
    testImplementation("org.robolectric:robolectric:<version>")          // 4.16.1+
    testImplementation("io.mockk:mockk:<version>")                      // 匹配 Kotlin 版本
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:<version>")  // 匹配 coroutines-core
    testImplementation("androidx.arch.core:core-testing:<version>")      // LiveData 的 InstantTaskExecutorRule
    testImplementation("app.cash.turbine:turbine:<version>")             // Flow/StateFlow 测试

    // --- 仪器化测试 (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 验证
    androidTestImplementation("androidx.test.espresso:espresso-idling-resource:<version>")
    androidTestImplementation("androidx.test.uiautomator:uiautomator:<version>")

    // --- Compose UI 测试 (仅当项目使用 Compose 时) ---
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")      // 版本来自 Compose BOM
    debugImplementation("androidx.compose.ui:ui-test-manifest")          // createComposeRule 必需
}
注意:如果项目使用 Compose BOM,ui-test-junit4ui-test-manifest 不需要显式版本 —— BOM 会管理它们。

android 块中启用 Robolectric 资源支持:

android {
    testOptions {
        unitTests.isIncludeAndroidResources = true  // Robolectric 必需
    }
}

8.2 按层次测试

层次位置运行环境速度用途
单元测试 (JUnit)src/test/JVM~msViewModels, repos, mappers, validators
单元测试 + Robolectricsrc/test/JVM + 模拟 Android~100ms需要 Context、资源、SharedPrefs 的代码
Compose UI (本地)src/test/JVM + Robolectric~100msComposable 渲染和交互
Espressosrc/androidTest/设备/模拟器~秒基于 View 的 UI 流程、Intent、数据库集成
Compose UI (设备)src/androidTest/设备/模拟器~秒完整 Compose UI 流程,真实渲染
UI Automatorsrc/androidTest/设备/模拟器~秒系统对话框、通知、多应用
Managed Devicesrc/androidTest/Gradle-managed AVD~分钟(首次运行)CI、跨 API 级别的矩阵测试

有关详细示例、代码模式以及 Gradle Managed Device 配置,请参阅 [测试](references/testing.md)。

8.3 测试命令

# 本地单元测试(快速,无需模拟器)
./gradlew test                          # 所有模块
./gradlew :app:testDebugUnitTest        # app 模块,debug 变体

# 单个测试类
./gradlew :app:testDebugUnitTest --tests "com.example.myapp.CounterViewModelTest"

# 仪器化测试(需要设备或 managed device)
./gradlew connectedDebugAndroidTest     # 在连接的设备上运行
./gradlew pixel6Api34DebugAndroidTest   # 在 managed device 上运行

# 同时运行两种测试
./gradlew test connectedDebugAndroidTest

# 带覆盖率报告测试(JaCoCo)
./gradlew testDebugUnitTest jacocoTestReport