如何开发一个自定义 Complication Provider 来提供健康数据?

解读

Wear OS 的 Complication 相当于表盘上的“小组件”,系统每 1–15 min 主动拉取一次数据,省电且对后台限制极严。国内面试问这道题,核心想验证三点:

  1. 是否理解 Wear OS 的“Provider 不主动推、由系统拉”的模型;
  2. 能否把健康数据(如本地传感器、Health Connect、运动 SDK)安全地桥接到 Complication 框架;
  3. 是否熟悉国内特殊合规要求:后台定位、健康数据属于“个人敏感信息”,必须弹窗授权、加密存储、可撤销,否则应用市场审核直接打回。

因此,回答要围绕“框架接入 + 数据合规 + 性能省电”展开,而不是单纯贴代码。

知识点

  1. Complication Provider 四大组件:Service 继承 ComplicationDataSourceService,声明 android.support.wearable.complications.PROVIDER 过滤器;在 AndroidManifest.xml 中注册并配置 update_period_seconds(国内建议 ≥300 s,避免后台频繁唤醒)。
  2. 数据类型映射:健康场景常用 ComplicationData.TYPE_SHORT_TEXTTYPE_LONG_TEXTTYPE_RANGED_VALUE(步数、心率区间)、TYPE_SMALL_IMAGE(心率图标)。
  3. 权限与合规:
    • 传感器:必须动态申请 ACTIVITY_RECOGNITION(Android 10+)与 BODY_SENSORS(Android 12+)。
    • 后台定位:若需 GPS 轨迹,需额外 ACCESS_BACKGROUND_LOCATION 并在应用市场后台“场景说明”里勾选“运动健身”。
    • 健康数据:接入 Health Connect 需声明 android.permission.health.READ_STEPSREAD_HEART_RATE,并在首次启动时弹《个人信息收集使用规则》与《健康数据授权说明》,否则华为、小米、OPPO 市场会驳回。
  4. 省电策略:
    • 使用 ProviderUpdateRequester.requestUpdate() 只在用户刚完成一次运动(前台 Service 结束瞬间)时主动触发一次,其余时间完全依赖系统拉取。
    • 传感器采样用 SensorManager.SENSOR_DELAY_NORMAL 并在 onPause() 立即 unregisterListener(),防止后台 0-uid 挂起。
  5. 数据安全:
    • 心率、血氧等原始值只在内存中保留,不落地;需要缓存时写入 EncryptedFile(Tink+Keystore)。
    • 提供“一键清除”入口,响应《个人信息保护法》第 49 条“可撤销权”。
  6. 兼容性:
    • Wear 3.x 开始强制 TargetSdk 33,必须适配前台服务 FOREGROUND_SERVICE_TYPE_HEALTH
    • 国内部分手表(如华为 GT 系列)无 GMS,需额外实现华为 Health Kit 桥接,用同一 ComplicationDataSourceService 做多 flavor 打包。

答案

步骤概览(可直接口述给面试官,展示思路清晰):

  1. 新建 Wear 模块,依赖:

    implementation "androidx.wear.watchface:watchface-complications-data-source:1.2.0"
    implementation "androidx.health:health-services-client:1.0.0-beta3"
    
  2. 继承 ComplicationDataSourceService,重写:

    override fun onComplicationRequest(request: ComplicationRequest, listener: ComplicationRequestListener) {
        val steps = HealthConnectClient.getSteps(request.lastUpdate) // 伪代码
        val data = when (request.complicationType) {
            ComplicationType.SHORT_TEXT ->
                ShortTextComplicationData.Builder(
                    PlainComplicationText.Builder("${steps}步").build(),
                    ComplicationText.EMPTY
                ).build()
            ComplicationType.RANGED_VALUE ->
                RangedValueComplicationData.Builder(
                    steps.toFloat(), 0f, 10000f,
                    PlainComplicationText.Builder("${steps}").build()
                ).build()
            else -> null
        }
        listener.onComplicationData(data)
    }
    
  3. AndroidManifest.xml 注册:

    <service
        android:name=".HealthComplicationService"
        android:exported="true"
        android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
        <intent-filter>
            <action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
        </intent-filter>
        <meta-data android:name="android.support.wearable.complications.SUPPORTED_TYPES"
                   android:value="SHORT_TEXT,RANGED_VALUE"/>
        <meta-data android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
                   android:value="300"/>
    </service>
    
  4. 权限与合规:

    • 启动页统一动态申请 ACTIVITY_RECOGNITIONBODY_SENSORS,拒绝则跳系统设置。
    • 接入 Health Connect 时,先检查 HealthConnectClient.isProviderAvailable(),再调用 requestPermissions() 弹出 Google 或 OEM 的联合授权页。
    • 将健康数据归类为“敏感个人信息”,在应用市场后台上传《隐私政策》与《健康数据使用场景说明》,否则审核必挂。
  5. 省电与安全:

    • 只在用户点击“结束运动”时调用 ProviderUpdateRequester.requestUpdate(context, ComponentName(...)) 刷新一次;其余时间完全依赖系统 5 min 周期。
    • 原始传感器数据不落盘;必须缓存时用 MasterKey+EncryptedFile 写入 /data/data/<pkg>/files/encrypted/ 目录,随账号退出即 delete()
  6. 国内多厂商适配:

    • build.gradle 定义 flavorDimensions "store",含 gmshms 两个 flavor;hms flavor 内用 HuaweiHealthKit 查询步数,同一套 ComplicationDataSourceService 做接口隔离,保证 70% 代码复用。

这样即可在 Wear OS 表盘上稳定、合规地展示步数、心率等健康数据,并通过国内应用市场审核。

拓展思考

  1. 实时心率曲线:Complication 只允许 1–2 个数据点,若产品坚持“秒级心率曲线”,需引导面试官理解:必须跳转专属 Tile 或 Activity,Complication 本身不适合高频更新;否则会被系统限频甚至拉黑 Provider。
  2. 无传感器权限的备用方案:可演示如何降级到 Health Connect 的“已同步历史数据”,保证用户拒绝传感器权限时仍显示昨日步数,体现“优雅降级”思维。
  3. 功耗量化:可补充使用 Battery Historian 对比“Provider 周期 300 s”与“30 s”两种场景,证明 300 s 场景下 24 h 传感器耗电 < 1%,给面试官展示数据驱动的优化意识。