使用 Kotlin 和 Jetpack Compose 开发 Wear OS 应用的完整指南

发布于:2025-05-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

环境配置与项目搭建

1. Gradle 依赖配置

// build.gradle (Module)
android {
    buildFeatures {
        compose true
    }
    composeOptions {
        kotlinCompilerExtensionVersion "1.5.3"
    }
}

dependencies {
    def wear_compose_version = "1.2.0"
    implementation "androidx.wear.compose:compose-material:$wear_compose_version"
    implementation "androidx.wear.compose:compose-foundation:$wear_compose_version"
    implementation "androidx.wear.compose:compose-navigation:$wear_compose_version"
    implementation "androidx.activity:activity-compose:1.8.0"
    
    // 添加健康服务支持
    implementation "androidx.health:health-services-client:1.0.0-beta02"
}

核心组件深度解析

1. 自适应布局容器

@Composable
fun HealthDataScreen() {
    val scrollState = rememberScalingLazyListState()
    
    ScalingLazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .background(MaterialTheme.colors.background),
        state = scrollState,
        anchorType = ScalingLazyListAnchorType.ItemStart
    ) {
        item { 
            Header(
                modifier = Modifier.padding(8.dp),
                text = "健康数据监测"
            ) 
        }
        
        items(healthItems) { item ->
            HealthChip(
                item = item,
                onItemClick = { navigateToDetail(item.id) }
            )
        }
        
        item {
            Spacer(modifier = Modifier.height(16.dp))
            CircularProgressIndicator(
                modifier = Modifier
                    .size(24.dp)
                    .align(Alignment.CenterHorizontally)
            )
        }
    }
    
    TimeText(
        modifier = Modifier.scrollAway(scrollState),
        timeSource = TimeTextDefaults.timeSource(
            timeFormat = "HH:mm",
            timeZone = TimeZone.currentSystemDefault()
        )
    )
}

@Composable
fun HealthChip(item: HealthItem, onItemClick: () -> Unit) {
    Chip(
        modifier = Modifier.padding(4.dp),
        onClick = onItemClick,
        colors = ChipDefaults.chipColors(
            backgroundColor = MaterialTheme.colors.surface,
            contentColor = MaterialTheme.colors.onSurface
        ),
        border = ChipDefaults.chipBorder(
            borderWidth = 1.dp,
            borderColor = MaterialTheme.colors.outline
        ),
        label = {
            Text(
                text = item.title,
                style = MaterialTheme.typography.body2
            )
        },
        icon = {
            Icon(
                imageVector = item.icon,
                contentDescription = null,
                modifier = Modifier.size(24.dp)
        }
    )
}

2. 健康数据集成实现

class HealthDataManager(context: Context) {
    private val healthClient = HealthServices.getClient(context)
    private var heartRateListener: HeartRateListener? = null

    suspend fun startHeartRateMonitoring() {
        val request = SensorRegistrationRequest(
            sensorType = SensorType.HEART_RATE,
            reportingMode = ReportingMode.RECEIVE_IF_INACTIVE,
            sampleInterval = 5.seconds
        )

        try {
            healthClient.registerSensorListener(
                object : HeartRateListener {
                    override fun onHeartRateUpdate(data: HeartRateData) {
                        // 更新UI或存储数据
                        Log.d("Health", "当前心率: ${data.value} BPM")
                    }
                },
                request
            )
        } catch (e: Exception) {
            Log.e("Health", "传感器注册失败", e)
        }
    }

    fun stopMonitoring() {
        heartRateListener?.let {
            healthClient.unregisterSensorListener(it)
        }
    }
}

// 在ViewModel中使用
class HealthViewModel(application: Application) : AndroidViewModel(application) {
    private val healthManager = HealthDataManager(application)
    
    init {
        viewModelScope.launch {
            healthManager.startHeartRateMonitoring()
        }
    }
    
    override fun onCleared() {
        healthManager.stopMonitoring()
        super.onCleared()
    }
}

高级导航架构

1. 分层导航实现

@Composable
fun WearApp() {
    val navController = rememberSwipeDismissableNavController()
    
    SwipeDismissExample(navController) {
        NavHost(
            navController = navController,
            startDestination = Screen.Main.route
        ) {
            composable(Screen.Main.route) {
                MainScreen(
                    onNavigateToDetail = { id ->
                        navController.navigate("${Screen.Detail.route}/$id")
                    }
                )
            }
            composable(
                route = "${Screen.Detail.route}/{id}",
                arguments = listOf(navArgument("id") { type = NavType.IntType })
            ) { backStackEntry ->
                DetailScreen(
                    itemId = backStackEntry.arguments?.getInt("id") ?: 0,
                    onBack = { navController.popBackStack() }
                )
            }
        }
    }
}

sealed class Screen(val route: String) {
    object Main : Screen("main")
    object Detail : Screen("detail")
}

设备适配策略

1. 多形态屏幕适配

@Composable
fun AdaptiveLayout() {
    val windowInfo = rememberWindowInfo()
    
    when (windowInfo.devicePosture) {
        is DevicePosture.Flat -> {
            // 普通模式布局
            StandardLayout()
        }
        is DevicePosture.HalfOpened -> {
            // 折叠半开模式
            HalfOpenLayout()
        }
        else -> {
            // 默认布局
            DefaultLayout()
        }
    }
}

@Composable
fun rememberWindowInfo(): WindowInfo {
    val context = LocalContext.current
    val windowInfo = remember {
        WindowInfoRepository.getOrCreate(context)
    }
    return windowInfo
}

性能优化实践

1. 智能缓存策略

@Composable
fun ComplexDataView() {
    val viewModel: HealthViewModel = viewModel()
    val dataState by viewModel.complexDataState.collectAsState()
    
    when (dataState) {
        is DataState.Loading -> ShowLoading()
        is DataState.Success -> ShowData((dataState as DataState.Success).data)
        is DataState.Error -> ShowError()
    }
}

class HealthViewModel : ViewModel() {
    private val _complexDataState = mutableStateOf<DataState>(DataState.Loading)
    val complexDataState: State<DataState> = _complexDataState
    
    init {
        loadData()
    }
    
    private fun loadData() {
        viewModelScope.launch {
            _complexDataState.value = DataState.Loading
            try {
                val result = computeExpensiveData()
                _complexDataState.value = DataState.Success(result)
            } catch (e: Exception) {
                _complexDataState.value = DataState.Error(e.message)
            }
        }
    }
    
    private suspend fun computeExpensiveData(): HealthData {
        return withContext(Dispatchers.Default) {
            // 模拟复杂计算
            delay(1000)
            HealthData(...)
        }
    }
}

发布配置与优化

1. 构建配置最佳实践

android {
    defaultConfig {
        minSdk 26
        targetSdk 34
        versionCode generateVersionCode()
        versionName "2.1.0-wear"
        
        // Wear OS 专属配置
        resConfigs "en", "zh-rCN"
        wearAppUnbundled true
    }
    
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
        }
    }
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
}

def generateVersionCode() {
    return (new Date().format('yyyyMMddHH').toInteger())
}

关键注意事项

  1. 交互设计规范

    • 保持单次交互在5秒内完成
    • 所有可点击区域 ≥ 48dp
    • 优先使用系统级手势(如右滑返回)
  2. 功耗优化

    fun updateDataStrategy() {
        if (isAmbientMode) {
            // 省电模式更新间隔
            setUpdateInterval(60_000L) 
        } else {
            setUpdateInterval(1_000L)
        }
    }
    
  3. Always-on Display 适配

    @Composable
    fun AmbientModeAwareText(text: String) {
        val ambientState = ambientAware()
        
        Text(
            text = if (ambientState.isAmbient) simplifyText(text) else text,
            color = if (ambientState.isAmbient) Color.White else MaterialTheme.colors.primary,
            style = MaterialTheme.typography.body1
        )
    }
    

测试与验证

  1. 性能基准测试

    @RunWith(AndroidJUnit4::class)
    class PerformanceTest {
        @get:Rule
        val rule = createComposeRule()
        
        @Test
        fun testMainScreenPerformance() {
            rule.setContent {
                MainScreen()
            }
            
            rule.onRoot().assertNoIdleResources()
            rule.waitForIdle()
            
            // 测量帧率
            val stats = rule.frameStats()
            assertThat(stats.avgFps).isGreaterThan(45)
        }
    }
    
  2. 功耗监测

    adb shell dumpsys batterystats --reset
    # 执行测试用例
    adb shell dumpsys batterystats --charged <package_name>
    

总结与最佳实践

通过上述完整实现方案,我们构建了一个符合 Wear OS 设计规范的健壮应用。关键实践包括:

  1. 分层架构设计:清晰的 ViewModel + Repository 结构
  2. 响应式 UI:充分利用 Compose 的状态管理
  3. 性能优先:智能数据加载策略和计算缓存
  4. 设备感知:自适应不同穿戴设备形态
  5. 健康数据集成:规范使用 Health Services API

建议结合最新 Wear OS 设计指南进行以下优化:

  • 实现 Material You 动态主题
  • 添加触觉反馈(Haptic Feedback)
  • 集成 Google 健身数据平台
  • 支持跨设备数据同步