开始使用 Health Connect

本指南与健康数据共享版本 1.1.0-alpha12 兼容。

本指南介绍如何开始在应用中使用“健康数据共享”。

第 1 步:准备健康数据共享应用

健康数据共享应用负责处理您的应用通过健康数据共享 SDK 发送的所有请求。这些请求包括存储数据和管理数据读写访问权限。

对健康数据共享的访问权限取决于手机上安装的 Android 版本。 以下部分概述了如何处理多个近期的 Android 版本。

Android 14

从 Android 14(API 级别 34)开始,健康数据共享是 Android 框架的一部分。此版本的健康数据共享是一个框架模块。这样一来,您无需进行任何设置。

Android 13 及更低版本

在 Android 13(API 级别 33)及更低版本中,健康数据共享不是 Android 框架的一部分。因此,您需要从 Google Play 商店安装健康数据共享应用

如果您已在 Android 13 及更低版本上将应用与健康数据共享集成,并且希望在 Android 14 上进行迁移,请参阅从 Android 13 迁移到 Android 14

打开“健康数据共享”应用

Health Connect 默认不再显示在主屏幕上。如需打开 Health Connect,请依次前往设置 > 应用 > Health Connect,或将 Health Connect 添加到您的快捷设置菜单中。

此外,健康数据共享要求用户使用 PIN 码、解锁图案或密码启用屏锁,以便在设备锁定时保护存储在健康数据共享中的健康数据免受恶意方的入侵。如需设置屏锁,请依次前往设置 > 安全 > 屏幕锁定

第 2 步:将 Health Connect SDK 添加到您的应用

健康数据共享 SDK 负责使用健康数据共享 API 发送请求,以对健康数据共享应用中的数据存储区执行操作。

在模块级 build.gradle 文件中添加 Health Connect SDK 依赖项:

dependencies {
  ...
  implementation "androidx.health.connect:connect-client:1.2.0-alpha01"
  ...
}

如需查看最新版本,请参阅 Health Connect 版本

第 3 步:配置应用

以下部分介绍了如何配置应用以与健康数据共享集成。

声明权限

健康与健身数据的访问权限属于敏感权限。健康数据共享针对读取和写入操作实现了一层安全保护,从而维护用户信任。

在应用中,根据所需的数据类型在 AndroidManifest.xml 文件中声明读取和写入权限,这些权限应与您在 Play 管理中心内声明的访问权限相符。

健康数据共享会使用标准 Android 权限声明格式。 使用 <uses-permission> 标记分配权限。将它们嵌套在 <manifest> 标记中。

<manifest>
  <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"/>

  <application>
  ...
  </application>
</manifest>

如需查看权限及其对应数据类型的完整列表,请参阅数据类型列表

显示应用的隐私权政策对话框

您的 Android 清单需要包含一个 activity,用于显示应用的隐私权政策(即应用对所请求权限的理由),说明如何使用和处理用户数据。

声明此 activity 以处理 ACTION_SHOW_PERMISSIONS_RATIONALE intent,当用户点击“健康数据共享”权限界面中的隐私权政策链接时,系统会向应用发送此 intent。

...
<application>
  ...
  <!-- For supported versions through Android 13, create an activity to show the rationale
       of Health Connect permissions once users click the privacy policy link. -->
  <activity
      android:name=".PermissionsRationaleActivity"
      android:exported="true">
    <intent-filter>
      <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
    </intent-filter>
  </activity>

  <!-- For versions starting Android 14, create an activity alias to show the rationale
       of Health Connect permissions once users click the privacy policy link. -->
  <activity-alias
      android:name="ViewPermissionUsageActivity"
      android:exported="true"
      android:targetActivity=".PermissionsRationaleActivity"
      android:permission="android.permission.START_VIEW_PERMISSION_USAGE">
    <intent-filter>
      <action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
      <category android:name="android.intent.category.HEALTH_PERMISSIONS" />
    </intent-filter>
  </activity-alias>
  ...
</application>
...

获取健康数据共享客户端

HealthConnectClient 是 Health Connect API 的入口点。 它允许应用使用 Health Connect 应用中的数据存储区。它会自动管理与底层存储层的连接,并处理传出请求和传入响应的所有 IPC 和序列化。

如需获取客户端实例,请先在 Android 清单中声明健康数据共享软件包名称。

<application> ... </application>
...
<!-- Check if Health Connect is installed -->
<queries>
    <package android:name="com.google.android.apps.healthdata" />
</queries>

然后在您的 activity 中,使用 getSdkStatus 检查是否已安装健康数据共享。如果是,请获取 HealthConnectClient 实例。

val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName)
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
  return // early return as there is no viable integration
}
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
  // Optionally redirect to package installer to find a provider, for example:
  val uriString = "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding"
  context.startActivity(
    Intent(Intent.ACTION_VIEW).apply {
      setPackage("com.android.vending")
      data = Uri.parse(uriString)
      putExtra("overlay", true)
      putExtra("callerId", context.packageName)
    }
  )
  return
}
val healthConnectClient = HealthConnectClient.getOrCreate(context)
// Issue operations with healthConnectClient

第 4 步:向用户请求权限

创建客户端实例后,应用需要向用户请求权限。用户必须能够随时授予或拒绝权限。

为此,请为所需的数据类型创建一组权限。 先确保此集中的权限已在 Android 清单中声明。

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(HeartRateRecord::class),
  HealthPermission.getWritePermission(HeartRateRecord::class),
  HealthPermission.getReadPermission(StepsRecord::class),
  HealthPermission.getWritePermission(StepsRecord::class)
)

使用 getGrantedPermissions 查看您的应用是否已获得所需的权限。如不具备,请使用 createRequestPermissionResultContract 请求这些权限。系统随即会显示“健康数据共享”权限界面。

// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()

val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions successfully granted
  } else {
    // Lack of required permissions
  }
}

suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
  val granted = healthConnectClient.permissionController.getGrantedPermissions()
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions already granted; proceed with inserting or reading data
  } else {
    requestPermissions.launch(PERMISSIONS)
  }
}

由于用户可以随时授予或撤消权限,因此您的应用需要定期检查已授予的权限,并应对权限丢失的情况。

第 5 步:执行操作

现在,一切都已设置完毕,在您的应用中执行读写操作。

写入数据

将您的数据构建成一个记录。查看 Health Connect 中支持的数据类型列表。

val stepsRecord = StepsRecord(
    count = 120,
    startTime = START_TIME,
    endTime = END_TIME,
    startZoneOffset = START_ZONE_OFFSET,
    endZoneOffset = END_ZONE_OFFSET,
)

然后,使用 insertRecords 写入记录。

suspend fun insertSteps(healthConnectClient: HealthConnectClient) {
    val endTime = Instant.now()
    val startTime = endTime.minus(Duration.ofMinutes(15))
    try {
        val stepsRecord = StepsRecord(
            count = 120,
            startTime = startTime,
            endTime = endTime,
            startZoneOffset = ZoneOffset.UTC,
            endZoneOffset = ZoneOffset.UTC,
            metadata = Metadata.autoRecorded(
                device = Device(type = Device.TYPE_WATCH)
            ),
        )
        healthConnectClient.insertRecords(listOf(stepsRecord))
    } catch (e: Exception) {
        // Run error handling here
    }
}

读取数据

您可以使用 readRecords 逐个读取数据。

suspend fun readHeartRateByTimeRange(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.readRecords(
            ReadRecordsRequest(
                HeartRateRecord::class,
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        for (record in response.records) {
            // Process each record
        }
    } catch (e: Exception) {
        // Run error handling here
    }
}

您还可以使用 aggregate 以汇总方式读取数据。

suspend fun aggregateSteps(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    try {
        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
            )
        )
        // The result may be null if no data is available in the time range
        val stepCount = response[StepsRecord.COUNT_TOTAL]
    } catch (e: Exception) {
        // Run error handling here
    }
}

视频教程

观看以下视频,详细了解 Health Connect 功能以及实现顺畅集成方面的最佳实践指南:

资源

请参阅以下资源,它们有助于之后的开发工作。

后续步骤

如需了解如何在“健康数据共享”中执行操作(例如):请参阅常见工作流