目录
今日工作:Android Health Connect 接入记录

Android Health Connect 接入实战:从 0 到可上线的完整流程

适用人群:Android 健康/运动类应用开发者
目标:把 Health Connect 的接入流程、配置项、关键代码和避坑点一次讲清楚

一、先说结论:为什么要接 Health Connect

Health Connect 是 Android 侧统一的健康数据平台。对开发者来说,核心价值是:

  • 统一 API:不用分别适配多个健康应用的数据接口。
  • 用户可控:权限粒度清晰,用户可随时撤回。
  • 本地存储:数据加密保存在设备端,隐私合规压力更可控。
  • 生态协同:你的应用可以和其他健康应用在同一数据层互通(在用户授权前提下)。

二、版本差异与前置条件

1) 系统版本差异

  • Android 14+:Health Connect 已并入系统框架,通常无需单独安装 App。
  • Android 13 及以下:需要用户先安装 Health Connect 应用(Google Play)。

2) 开发和测试前置条件

  • Android Studio 最新稳定版。
  • 真机 Android 9(API 28)及以上。
  • 设备必须开启锁屏(PIN/图案/密码),否则 Health Connect 可能不可用。

三、项目接入总流程(建议按这个顺序)

  1. 添加 SDK 依赖。
  2. 在 Manifest 声明包可见性与健康权限。
  3. 增加权限用途说明页(隐私政策入口 intent)。
  4. 初始化 HealthConnectClient
  5. 实现权限检查 + 动态申请。
  6. 接入数据写入(如体重、运动会话)。
  7. 接入数据读取(原始记录 + 聚合统计)。
  8. 增加后台读取、历史读取能力(按需)。
  9. 接入 Differential Changes(差分同步)。
  10. 用官方 Toolbox + 真机进行验收测试。

四、核心配置清单(可直接对照)

1) Gradle 依赖

gradle
复制代码
dependencies {
    implementation "androidx.health.connect:connect-client:1.1.0-alpha11"
}

建议:实际项目里用最新稳定/推荐版本,避免长期停留在旧 alpha。

2) Manifest:声明 Health Connect 包可见性

xml
复制代码
<queries>
    <package android:name="com.google.android.apps.healthdata" />
</queries>

3) Manifest:声明你需要的权限(最小化原则)

xml
复制代码
<uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
<uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>
<uses-permission android:name="android.permission.health.READ_STEPS"/>
<uses-permission android:name="android.permission.health.WRITE_STEPS"/>
<uses-permission android:name="android.permission.health.READ_EXERCISE"/>
<uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
<uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED"/>
<uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED"/>
<uses-permission android:name="android.permission.health.READ_WEIGHT"/>
<uses-permission android:name="android.permission.health.WRITE_WEIGHT"/>

可选能力(按需声明):

xml
复制代码
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY" />

4) Manifest:权限用途说明入口(非常关键)

xml
复制代码
<!-- Android 13 及以下 -->
<intent-filter>
    <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
</intent-filter>

<!-- Android 14+ -->
<intent-filter>
    <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
    <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
</intent-filter>

这里要落地一个真实可访问的隐私说明页面,讲清楚“用什么数据、为什么用、如何处理、如何删除”。


五、代码接入骨架(建议抽一层 Manager)

1) 初始化客户端

kotlin
复制代码
private val healthConnectClient by lazy { HealthConnectClient.getOrCreate(context) }

2) 权限检查 + 请求 Contract

kotlin
复制代码
suspend fun hasAllPermissions(permissions: Set<String>): Boolean {
    return healthConnectClient.permissionController
        .getGrantedPermissions()
        .containsAll(permissions)
}

fun requestPermissionsActivityContract(): ActivityResultContract<Set<String>, Set<String>> {
    return PermissionController.createRequestPermissionResultContract()
}

3) 体重写入示例(注意时区)

kotlin
复制代码
suspend fun writeWeightInput(weightInput: Double) {
    val time = ZonedDateTime.now().withNano(0)
    val weightRecord = WeightRecord(
        metadata = Metadata.manualEntry(),
        weight = Mass.kilograms(weightInput),
        time = time.toInstant(),
        zoneOffset = time.offset
    )
    healthConnectClient.insertRecords(listOf(weightRecord))
}

4) 读取记录示例

kotlin
复制代码
suspend fun readWeightInputs(start: Instant, end: Instant): List<WeightRecord> {
    val request = ReadRecordsRequest(
        recordType = WeightRecord::class,
        timeRangeFilter = TimeRangeFilter.between(start, end)
    )
    return healthConnectClient.readRecords(request).records
}

5) 聚合读取示例(周平均体重)

kotlin
复制代码
suspend fun computeWeeklyAverage(start: Instant, end: Instant): Mass? {
    val request = AggregateRequest(
        metrics = setOf(WeightRecord.WEIGHT_AVG),
        timeRangeFilter = TimeRangeFilter.between(start, end)
    )
    return healthConnectClient.aggregate(request)[WeightRecord.WEIGHT_AVG]
}

六、进阶能力:后台读取 / 历史读取 / 差分同步

1) 功能可用性检查(不要直接硬调)

kotlin
复制代码
fun isFeatureAvailable(feature: Int): Boolean {
    return healthConnectClient.features.getFeatureStatus(feature) ==
        HealthConnectFeatures.FEATURE_STATUS_AVAILABLE
}
  • 后台读取:FEATURE_READ_HEALTH_DATA_IN_BACKGROUND
  • 历史读取:FEATURE_READ_HEALTH_DATA_HISTORY

2) 差分同步(Differential Changes)

核心思路:

  1. 先拿 token(记录某个同步起点)。
  2. 下次用 token 拉增量变更(新增/更新/删除)。
  3. 持久化新 token。
  4. 处理 token 过期(30 天有效期)回退全量或区间同步。

示例骨架:

kotlin
复制代码
suspend fun getChangesToken(): String {
    return healthConnectClient.getChangesToken(
        ChangesTokenRequest(setOf(ExerciseSessionRecord::class))
    )
}
kotlin
复制代码
suspend fun getChanges(token: String): Flow<ChangesMessage> = flow {
    var nextToken = token
    do {
        val response = healthConnectClient.getChanges(nextToken)
        if (response.changesTokenExpired) throw IOException("Changes token expired")
        emit(ChangesMessage.ChangeList(response.changes))
        nextToken = response.nextChangesToken
    } while (response.hasMore)
    emit(ChangesMessage.NoMoreChanges(nextToken))
}

七、必须关注的注意点(项目里最容易踩坑)

  • 权限最小化:只申请你当前页面真正要用的数据类型,否则用户信任下降。
  • 拒绝保护:权限连续拒绝可能导致系统不再弹窗,需要引导用户去设置页手动开启。
  • 时区必填:写记录请带 zoneOffset,否则跨时区展示会错位。
  • 数据来源策略:读取聚合时是否加 dataOriginFilter,决定“只看本应用”还是“融合全来源”。
  • 差分 token 生命周期:30 天会过期,必须有兜底同步策略。
  • 后台能力非全量可用:先 getFeatureStatus 再开放 UI。
  • 真机验证优先:模拟器与不同 ROM 行为可能不一致,尤其权限弹窗与后台任务。
  • 合规文案要可审计:隐私政策和权限用途说明必须与实际采集字段一致。

八、建议的日志与错误处理规范(生产可观测)

你在接入时建议统一按以下规范做:

  • 关键流程打点:权限申请结果、读写请求、聚合请求、差分同步开始/结束。
  • 关键数据日志:请求时间范围、记录数量、来源应用数(避免直接打印敏感值)。
  • 全链路错误日志:SDK 调用异常、权限缺失、token 过期、后台任务失败都要记录错误码和上下文。
  • 统一错误映射:把原始异常映射成业务可理解错误(如“无权限”“数据暂不可用”“请重试”)。

示例(仅示意):

kotlin
复制代码
try {
    val records = healthConnectClient.readRecords(request).records
    Log.i("HealthConnect", "readWeight success, size=${records.size}, range=$start~$end")
} catch (e: Exception) {
    Log.e("HealthConnect", "readWeight failed, range=$start~$end", e)
    throw e
}

九、测试与验收清单(上线前)

  • 首次安装后可正确识别 Health Connect 可用状态。
  • 权限申请流程完整可达,拒绝后有可恢复路径。
  • 体重/运动会话写入后,在 Health Connect 数据页可见。
  • 读取原始记录与聚合统计数值正确。
  • 后台读取任务在授权后可执行并产生日志。
  • 历史读取在授权后可读取 30 天前数据。
  • 差分同步可正确处理新增、更新、删除。
  • token 过期时可自动触发兜底同步。
  • 不同 Android 版本(至少 13、14)完成回归。

参考资料

"我视别人的钱财如粪土,但你的就不一样啦!"
本文由 程序员拉大锯 原创发布于 阳光沙滩 , 未经作者授权,禁止转载
评论
0 / 1024
推荐文章
面向 Java 程序员的 MinIO 入门教程
本文为Java程序员提供了一份详细的MinIO入门教程,涵盖MinIO的部署方法和Java SDK的集成使用。通过本文,您将学习如何在Java项目中高效管理桶和对象,快速上手MinIO这一高性能对象存储服务。
你知道:气和汽的区别吗?
了解‘气’和‘汽’的区别,掌握它们在不同语境下的含义与用法,帮助你更准确地使用中文。无论是日常交流还是写作,这对提升语言能力都大有裨益。
wsl update 下载不下来怎么办呀?
遇到Docker Desktop提示需要更新但无法解决?本文教你如何通过GitHub下载并安装WSL,轻松解决更新问题,适合使用x64芯片的用户。
今日经验:重置虚拟机的密码
本文详细记录了在KVM虚拟化环境中,如何通过virt-rescue工具重置遗忘的root密码。对于需要维护和管理虚拟机的IT人员来说,这是一份实用的排障指南,涵盖了从环境准备到密码修改的完整流程,帮助快速恢复系统访问权限。
今日工作:Android Health Connect 接入记录
本文详细讲解了如何将 Android Health Connect 接入到健康或运动类应用中,涵盖从配置、代码实现到测试验收的完整流程。适合希望统一健康数据管理、提升用户隐私合规性的开发者阅读。
Skill从入门到出家
探索AI Agent的核心能力——Skill,了解其模块化设计、渐进式披露机制和实际应用场景。从基础概念到高级实战,掌握如何构建可复用、可移植的AI技能,提升Agent处理复杂任务的能力。
Docker,Docker Compose,kubectl最近遇到的版本问题
本文分享了在使用Docker、Docker Compose和kubectl时遇到的版本问题及解决方法,适合需要更新或管理Linux系统中相关工具的开发者参考。
Google上架App退回
Google Play Console 抛出 16KB 内存页面大小合规性错误,导致应用无法上架。本文详细分析了错误原因,并提供了解决方案,帮助开发者适配 Android 15 的新要求。
国内常用的 npm 镜像源整理
在使用 npm 安装依赖时,国内开发者常常遇到速度慢的问题。本文整理了多个稳定且常用的国内 npm 镜像源,帮助提升依赖安装效率。还介绍了如何通过 nrm 工具快速切换镜像,非常适合需要优化开发环境的开发者。
列表项排序设计:分数索引思想与实践
本文介绍了分数索引思想在列表排序中的应用,通过实数轴上的插空方式实现高效插入与拖拽排序。适用于课程章节、导航菜单、看板列等多种场景,提供创建和更新时的业务规则及边界处理策略,帮助开发者优化排序性能并提升用户体验。
2026苹果电脑芯片的性能排行榜
了解2026年前后苹果电脑芯片的性能排名和关键变化,帮助你更好地选择适合自己的设备。从M1到M5,每一款芯片都有其独特优势,无论是日常办公还是专业需求都能找到合适的推荐。
在 KVM 上部署 Ubuntu 24.04 Server:企业级虚拟化完整实践指南
本文详细介绍了如何在 KVM 上部署 Ubuntu 24.04 Server,涵盖系统架构、部署步骤、核心命令解析和性能优化等内容。适合希望构建高性能、低成本企业虚拟化平台的技术人员阅读。
旧版本的kubesphere还能用的
本文介绍了如何使用KubeSphere配置和部署一个Kubernetes集群,包括修改配置文件、设置环境变量以及执行安装命令。适合需要了解Kubernetes集群搭建的开发者和系统管理员阅读。
Flutter Fragment 嵌入模式下返回键/侧滑直接退出应用-日常记录
在 Flutter 混合开发中,如何解决 Android 返回键无法正确触发 Flutter 页面返回逻辑的问题?本文详细解析了事件传递机制,并提供完整解决方案,包括 Android 和 Flutter 层的配置方式。适合开发者快速排查和修复类似问题。
记录一个问题,Post请求变Get请求了?原因很简单
本文讲述了一个关于HTTP请求方法被错误转换的问题,通过分析Nginx配置和日志,最终发现是由于301重定向导致POST请求变成GET请求。作者详细描述了问题排查过程,并给出了解决方案,对于开发人员在处理类似网络问题时具有参考价值。
Android 进阶:在非 ComponentActivity 中实现协程自动取消
本文深入探讨了在 Android 开发中如何为非 ComponentActivity 的类实现 LifecycleOwner 功能,分享了两种优雅的解决方案。通过手动注册和 Kotlin 属性委托的方式,确保协程能随 Activity 销毁而自动取消,提升代码健壮性。适合对 Android 生命周期管理和协程使用感兴趣的开发者阅读。
Uni-app 发送通知全解析(从本地通知到推送服务实战)
深入了解Uni-app中通知的四种类型及应用场景,掌握跨平台支持情况和代码实战技巧。从基础提示到高级推送架构设计,全面解析如何提升用户活跃度和业务触达能力,适合开发者系统学习与实践。
MQTT 学习指南:从入门到工程实践
深入解析MQTT在物联网中的核心作用,了解其轻量、稳定和省流量的特性。从发布/订阅模型到QoS机制,全面掌握MQTT的通信原理与应用场景,助你高效构建物联网系统。
深入理解 Java NIO:非阻塞 I/O 的原理、应用与案例实战
本文深入解析 Java NIO 的核心概念,包括 Buffer、Channel 和 Selector,对比传统 I/O 的优势,并通过实战案例展示如何构建高并发的聊天服务器。适合希望提升 Java 网络编程能力的开发者阅读。
二次函数全攻略:公式、图像、性质与应用
二次函数是数学中的核心内容,广泛应用于物理、经济和工程领域。本文系统讲解其定义、图像、性质及实际应用,通过案例帮助理解,适合学生和数学爱好者深入学习。
Java排序算法全解析:从冒泡到快速排序,案例实操
掌握Java中常见排序算法的实现方法,理解其时间复杂度和适用场景,提升编程能力。从冒泡排序到快速排序,全面解析各种排序技术,帮助你高效解决问题。
Java 面试算法题全解析:案例、讲解与面试频率分析
Java面试中,算法题是必考内容。掌握常见算法不仅能提升编程能力,还能提高通过率。本文详细讲解了两数之和、链表反转、二分查找等经典算法题的解题思路与实现代码,帮助你更有针对性地准备面试。
Java基础语法入门:跟着案例一步步学会
掌握Java基础语法,从零开始学习编程。本文通过实战案例,详细讲解程序结构、变量、运算符、条件语句、循环、数组和方法等核心内容,适合初学者系统学习。通过练习提升编程能力,为进阶开发打下坚实基础。
Java 多线程入门:从概念到实战(初学者必看)
掌握多线程编程,提升程序效率和响应速度。本文从基础概念到实战案例,一步步讲解如何在 Java 中实现多线程,帮助你快速上手并理解核心知识点。通过实际代码示例,了解线程的生命周期、常用方法及线程安全问题,适合初学者和进阶者学习参考。
Java 多线程入门:从概念到实战(初学者必看)
掌握多线程编程,提升程序效率与响应速度。本文从基础概念到实战案例,详细讲解Java多线程的实现方式、注意事项和线程安全问题,适合初学者快速上手。通过实例代码,帮助你理解如何高效编写多线程程序。
Flutter开发网路库封装示例
本教程详细介绍了如何在 Flutter 项目中通过 Dio 库封装网络请求,提供了一套完整的封装类及使用示例,适用于构建中大型项目。内容覆盖依赖引入、封装方法实现、使用场景演示以及扩展功能建议,帮助开发者快速提升代码复用性和可维护性。无论是初学者还是有经验的开发者,都能从中受益。
写完这些案例,就掌握flutter开发了。
学习如何在Flutter中实现输入框的实时显示、页面跳转与数据传递,以及动态列表的展示和网络请求数据的解析与展示。通过这些基础案例,掌握Flutter的核心功能,为构建复杂应用打下坚实基础。
Flutter学习路线
想要掌握Flutter开发?这篇详细的学习路线图将帮助你从零开始,逐步成长为Flutter开发者。覆盖基础入门、核心概念、进阶开发以及发布优化四个阶段,结合理论与实践,让你轻松掌握Flutter技能。无论是想开发手机应用还是探索跨平台开发,这份指南都能满足你的需求。立即行动,开启你的Flutter之旅吧!
什么是MCP? Monte Carlo Planning(蒙特卡洛规划)
MCP(Monte Carlo Planning,蒙特卡洛规划)是强化学习和决策系统中的重要方法,广泛应用于复杂环境下的行动策略规划。无论是博弈中的AI,还是机器人路径规划,MCP都能通过随机模拟预测未来策略的效果。其中,蒙特卡洛树搜索(MCTS)是其典型实现,具有强大的全局最优性和适应高维复杂策略的能力。文章详细解析了MCP的基本概念、与强化学习的关系、典型算法以及实际应用场景,展示了其在AlphaGo、自动驾驶、游戏AI等领域的卓越表现。
智能体相关的概念介绍一下,并且给出学习路线!
智能体是人工智能领域的重要概念,广泛应用于强化学习、多智能体系统和机器人学等方向。本文从智能体的基本概念出发,介绍了其核心组成和分类,并提供了涵盖基础知识、模型理解、实践项目及前沿研究的系统学习路线。无论是初学者还是希望深入探索的研究者,都能从中找到有价值的信息和资源。