@flomentum溶液/电容-健康延伸
用于从 Apple HealthKit 读取数据的 Cross- platform Capacitor 插件
谷歌健康联通. 插件需要 节点.js 24+ 并兼容
与 电容 8。对于iOS,插件传送 a Swift 软件包管理器
分布( 电容 8 默认), 而 CocoaPods 光谱
FlomentumsolutionsCapacitorHealthExtended 留作遗留项目之用.
感谢和归属
从 电容器保健 就是这样...
- 一些部分、概念和想法借用自 克多瓦-插素-健康。 。 。 .
- 谢谢 @dariosalvi78 (英语) 供养.
谢谢 @mley (英语) 在地面上工作。 这个分叉的目标是扩展功能和数据点,并跟上不断变化的全新的Android健康连接平台. 希望为基于电容API的健康数据访问创建平台等同.
要求(冲洗和消耗用具)
- 节点.js 24+(推荐最后的LTS版本)
- 电容 8
- iOS 15+(Xcode 26 + HealthKit + SwiftPM 工具链)
- Android 16+ (Android Studio Otter 2025.2.1 + Health Connect 1.2.0-alpha02 + Gradle 8.13.0 + Kotlin 2.2.2.20) (中文(简体) )
特征
- 检查设备是否有健康功能
- 申请和核实健康许可
- 查询步骤或卡路里等汇总数据
- 获取带有可选路由和心率数据的解决会话
- 创建解决会话(如攀岩),包含总计,可选路线,以及心率样本(写 API)
- 将手动测量值(体重、身高、身体脂肪%、休息心率)保存到健康与健康连接(写出API)
- 获取最新样本,包括步骤、距离(包括循环)、卡路里(活性/总/流域)、心率、休息HR、HRV、呼吸速率、血压、氧饱和、血糖、体温(下水道+核心)、体肥、高、体重、飞行爬升、睡眠(包括REM持续时间)和锻炼时间.
- 阅读iOS上的剖面特征:生物性别,血型,出生日期,菲茨帕特里克皮肤类型,轮椅使用.
支持的数据类型(均等iOS + Android)
- 活动:步道、相距、相距骑行、锻炼时间(阿普勒锻炼时间)、健身(带路线/步道/卡路里)、飞行爬升
- 能源:活性热量、总热量、玄武质热量
- 活性:心率,休息心率,HRV,呼吸率,血压,氧饱和,血糖,体温,玄武体温
- 身体:体重、身高、脂肪
- 特征(iOS):生物性别,血型,出生日期,菲茨帕特里克皮肤类型,轮椅使用
- 会话: 注意,入睡,入睡 REM(仅限最晚样本)
安装
npm install @flomentumsolutions/capacitor-health-extended
npx cap sync
设置消费应用程序
iOS系统
电容 8 通过 SwiftPM 解决 iOS 插件。 运行 npx cap sync ios 将
添加 FlomentumSolutionsCapacitorHealthExtended 软件包(由
capacitor-swift-pm您的 Xcode 项目 。 如果你被钉在7号电容器上的话,
你可以继续使用可可花谱 FlomentumSolutionsCapacitorHealthExtended。 。 。 .
- 安装此插件时确保您的app id具有“ 健康 Kit” 权限( 见 iOS dev Centre) .
- 另外,确保您的应用和App Store描述符合苹果审查准则.
- 信息.plist文件要添加两个密钥:NSHealthShareUsageDescription和NSHealthUpdateUsageDecription.
- 请求 WRITEQQ 权限
requestHealthPermissions以便节省锻炼/能量/距离/路由/心电图样本和手动测量(重量/高/身体脂肪/呼吸力)至健康设备.
机器人
插件命名空间/ 套件是 com.flomentumsolutions.capacitorhealthextended.capacitor (去除旧的连字符) com.flomentumsolutions.capacitor-health-extended 引用);在线条活动、显示条目或ProGuard规则时使用.
- 打开显示标记后立即在根标签中显示Android
<!-- Make Health Connect visible to detect installation -->
<queries>
<package android:name="com.google.android.apps.healthdata" />
</queries>
<!-- Declare permissions you’ll request -->
<!-- READ permissions -->
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />
<uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" />
<uses-permission android:name="android.permission.health.READ_DISTANCE" />
<uses-permission android:name="android.permission.health.READ_EXERCISE" />
<uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTES" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE" />
<uses-permission android:name="android.permission.health.READ_WEIGHT" />
<uses-permission android:name="android.permission.health.READ_HEIGHT" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" />
<uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE" />
<uses-permission android:name="android.permission.health.READ_MINDFULNESS" />
<uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE" />
<uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE" />
<uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" />
<uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" />
<uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" />
<uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" />
<uses-permission android:name="android.permission.health.READ_BODY_FAT" />
<uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
<uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" />
<uses-permission android:name="android.permission.health.READ_SLEEP" />
<!-- WRITE permissions -->
<uses-permission android:name="android.permission.health.WRITE_EXERCISE" />
<uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED" />
<uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED" />
<uses-permission android:name="android.permission.health.WRITE_DISTANCE" />
<uses-permission android:name="android.permission.health.WRITE_HEART_RATE" />
<uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
<uses-permission android:name="android.permission.health.WRITE_WEIGHT" />
<uses-permission android:name="android.permission.health.WRITE_HEIGHT" />
<uses-permission android:name="android.permission.health.WRITE_BODY_FAT" />
<uses-permission android:name="android.permission.health.WRITE_RESTING_HEART_RATE" />
调用时包含 WRITEQQ 条目 saveWorkout 插入练习会话、能量、距离、路由或心率样本,并在使用时添加参数写入权限 saveMetrics。 。 。 .
- 应用程序标签中的 Android 特性
<!-- Handle Health Connect rationale (Android 13-) -->
<!-- REPLACE com.my.app with your details -->
<activity
android:name="com.my.app.PermissionsRationaleActivity"
android:exported="true">
<intent-filter>
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
<category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
</intent-filter>
</activity>
<!-- Handle Android 14+ alias -->
<!-- REPLACE com.my.app with your details -->
<activity-alias
android:name="ViewPermissionUsageActivity"
android:exported="true"
android:targetActivity="com.my.app.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>
- 安全 WebView 内容的应用程序标签中的 Android Munification
<!-- Configure secure WebView and allow HTTPS loading -->
<application
android:usesCleartextTraffic="false"
android:networkSecurityConfig="@xml/network_security_config">
...
</application>
- 创建
com.my.app.PermissionsRationaleActivity.kt与(REPLACE com.my.app与您的细节):
<!-- REPLACE com.my.app with your details -->
package com.my.app
import android.os.Bundle
import android.util.Log
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
class PermissionsRationaleActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportActionBar?.apply {
title = "Privacy Policy"
setDisplayHomeAsUpEnabled(true)
}
webView = WebView(this).apply {
settings.apply {
javaScriptEnabled = true
domStorageEnabled = true
useWideViewPort = true
loadWithOverviewMode = true
}
webChromeClient = WebChromeClient()
webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: android.webkit.WebResourceRequest) = false
override fun onReceivedError(
view: WebView,
request: android.webkit.WebResourceRequest,
error: android.webkit.WebResourceError
) {
Log.e("WebView", "Failed to load: ${error.description}")
}
override fun onPageFinished(view: WebView, url: String) {
Log.d("WebView", "Loaded: $url")
}
}
loadUrl("https://mywebsite.com/privacy-policy")
}
setContentView(webView)
// Device back button behavior
onBackPressedDispatcher.addCallback(this) {
finish()
}
}
// Toolbar Up button behavior
override fun onSupportNavigateUp(): Boolean {
finish()
return true
}
}
- 创建
res/xml/network_security_config.xml改为:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
此设置可确保您的 WebView 将安全地加载 HTTPS 内容并遵守 Android 默认的网络安全政策 .
iOS 读取允许 UX 提示
在iOS上, checkHealthPermissions 对读取样本权限表示乐观,因为HealthKit没有区分
拒绝从空数据获取 。 如果查询返回无结果,请提示用户验证Apple Health设置.
import { Health, type HealthPermission } from '@flomentumsolutions/capacitor-health-extended';
const NO_DATA_HINT =
'No data found. If you believe this is an error, please verify your settings in Apple Health.';
export async function queryWithHealthEmptyHint<T>(
permission: HealthPermission,
query: () => Promise<T>,
isEmpty: (result: T) => boolean,
showHint: (message: string) => void
): Promise<T | null> {
const { permissions } = await Health.checkHealthPermissions({ permissions: [permission] });
if (!permissions[permission]) {
return null;
}
const result = await query();
if (isEmpty(result)) {
showHint(NO_DATA_HINT);
}
return result;
}
API 密码
<docgen-index>
* [`isHealthAvailable()`](#ishealthavailable)
* [`checkHealthPermissions(...)`](#checkhealthpermissions)
* [`requestHealthPermissions(...)`](#requesthealthpermissions)
* [`openAppleHealthSettings()`](#openapplehealthsettings)
* [`openHealthConnectSettings()`](#openhealthconnectsettings)
* [`showHealthConnectInPlayStore()`](#showhealthconnectinplaystore)
* [`getCharacteristics(...)`](#getcharacteristics)
* [`queryAggregated(...)`](#queryaggregated)
* [`queryWorkouts(...)`](#queryworkouts)
* [`queryLatestSample(...)`](#querylatestsample)
* [`queryWeight()`](#queryweight)
* [`queryHeight()`](#queryheight)
* [`queryHeartRate()`](#queryheartrate)
* [`querySteps()`](#querysteps)
* [`saveWorkout(...)`](#saveworkout)
* [`saveMetrics(...)`](#savemetrics)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)
</docgen-index>
可健康( A)
isHealthAvailable() => Promise<{ available: boolean; }>
检查是否有健康API. Android:如果还回了虚假信息,Google健康连接应用程序很可能没有安装. Ưμ㼯A
回返情况: Promise<{ available: boolean; }>
检查健康许可(...)
checkHealthPermissions(permissions: PermissionsRequest) => Promise<PermissionResponse>
返回是否每个许可 . Android:使用健康连接赠款状态. iOS:写权限严格. 阅读样本类型的权限是乐观的, 因为 HealthKit 不 区分已拒绝的对无数据; 仅在未确定读取权限时此返回为虚假 。 对于 特性,此探测器在拒绝时会错误返回. UX 提示: 如果此返回为真, 但查询不产生结果, 请提示检查 Apple Health 设置 .
| 参数 | 类型 | 说明 |
|---|---|---|
permissions | PermissionsRequest | 查询权限 |
回返情况: Promise<PermissionResponse>
健康许可(...)
requestHealthPermissions(permissions: PermissionsRequest) => Promise<PermissionResponse>
向用户请求权限 .
Android:Apps只能请求几回权限,之后用户必须手动授权进入 健康连接应用程序。 参见 openHealthConnectSettings ()
iOS:如果已经授予或拒绝权限,这种方法只会返回而不询问用户. 在iOS系统 我们无法真正发现用户是否批准或拒绝许可。 回报值反映了以下假设: 获得许可.
| 参数 | 类型 | 说明 |
|---|---|---|
permissions | PermissionsRequest | 请求权限 |
回返情况: Promise<PermissionResponse>
开放式健康安排( )
openAppleHealthSettings() => Promise<void>
打开应用程序设置, 这有点错误, 因为健康权限被配置在 : 设置 > Apps > (苹果) 健康 > 访问和装置 > [app-name] 但我们不能直接去那里.
开放式健康连接设置( )
openHealthConnectSettings() => Promise<void>
打开 Google 健康连接应用程序 iOS:异名打开了AppleHealthSettings ().
显示健康连接InPlayStore ()
showHealthConnectInPlayStore() => Promise<void>
在 PlayStore 中打开 Google 健康连接应用程序 iOS:不采取行动就解决.
获取特征(...)
getCharacteristics(request?: CharacteristicsRequest | undefined) => Promise<CharacteristicsResponse>
iOS只:读取生物性别,血型,出生日期,菲茨帕特里克皮肤类型等用户特征,并使用轮椅.
值在无值或未获许可时无效。 Android 不暴露这些特性; 它返回 platformSupported: false (单位:千美元) platformMessage 为 UI 提示,而不释放无效值.
通过 fields 允许您只请求特定特性(例如出生日期)来保持范围狭小的许可。 省略时默认所有特性.
| 参数 | 类型 |
|---|---|
request | CharacteristicsRequest |
回返情况: Promise<CharacteristicsResponse>
查询分类(...)
queryAggregated(request: QueryAggregatedRequest) => Promise<QueryAggregatedResponse>
查询汇总数据
- 血压总量回落到平分数
value加号systolic, (中文(简体) ),diastolic,以及unit。 。 。 . total-calories在iOS和Android上作为活性+玄武能量得到,用于最新的样品,汇总的查询和锻炼. 我们回到月台的总卡路里度(或活性卡路里), 请求两者READ_ACTIVE_CALORIES财务报告和审定财务报表READ_BASAL_CALORIES总计.- 体重/身高汇总每天返回最新样本(无平均值).
- Android聚合目前支持每日桶;不支持的桶会被拒绝.
- 机器人
distance-cycling在自行车练习会中记录的总距离(需要距离+解决权限). - 每日
bucket: "day"查询使用设备时区的日历日边界(从一天开始到下一个开始日),而不是跟踪24小时窗口。 关于“今天”,请发送startDate在今天的开始和endDate现在或明天的开始.
| 参数 | 类型 |
|---|---|
request | QueryAggregatedRequest |
回返情况: Promise<QueryAggregatedResponse>
查询工作(...)
queryWorkouts(request: QueryWorkoutRequest) => Promise<QueryWorkoutResponse>
查询工作
| 参数 | 类型 |
|---|---|
request | QueryWorkoutRequest |
回返情况: Promise<QueryWorkoutResponse>
查询LatestSample(...)
queryLatestSample(request: { dataType: LatestDataType; }) => Promise<QueryLatestSampleResponse>
查询特定数据类型的最新样本
- 最新睡眠样本返回从上~36小时开始的最新完整睡眠会话(仅睡眠状态);如果存在更长的过夜会话,会忽略较短的午睡.
sleep-rem返回最近睡眠会话的REM持续时间(分);需要iOS 16+睡眠阶段和Health Connect REM在Android上的数据.
| 参数 | 类型 |
|---|---|
request | { dataType: LatestDataType; } |
回返情况: Promise<QueryLatestSampleResponse>
查询网( )
queryWeight() => Promise<QueryLatestSampleResponse>
查询最新重量样本 查询LatestSample({数据类型:"重量"})周围的方便包装器.
回返情况: Promise<QueryLatestSampleResponse>
查询高 ()
queryHeight() => Promise<QueryLatestSampleResponse>
查询最新高度样本 查询LatestSample({ data Type: 'hight'})周围的方便包装器.
回返情况: Promise<QueryLatestSampleResponse>
查询HeartRate ()
queryHeartRate() => Promise<QueryLatestSampleResponse>
查询最新心率样本 查询LatestSample({数据类型:'心率'})周围的方便包装器.
回返情况: Promise<QueryLatestSampleResponse>
查询Steps( )
querySteps() => Promise<QueryLatestSampleResponse>
查询最新步骤样本 围绕查询LatestSample({ dataType: 'steps' })的方便包装器.
回返情况: Promise<QueryLatestSampleResponse>
保存 Workout (...)
saveWorkout(request: SaveWorkoutRequest) => Promise<SaveWorkoutResponse>
创建包含可选总计和路由/心率样本的解决会话.
- iOS 存储 a
HKWorkout(活动) 绘图类型从activityType),拥有总能/距离和可选元数据/路由/心率样本. - Android 存储 a
ExerciseSessionRecord加号ActiveCaloriesBurnedRecord, (中文(简体) ),DistanceRecord,以及HeartRateRecord提供时。 路线通过ExerciseRoute。 。 。 . - 需要匹配 WRITEQ 权限来匹配您包括的值(例如 WRITE WORKOOTS + WRITE ACALORIES + WRITE DISTANCE + WRITE HEART RATE + WRITE RUTE).
| 参数 | 类型 |
|---|---|
request | SaveWorkoutRequest |
回返情况: Promise<SaveWorkoutResponse>
保存度量衡(...)
saveMetrics(request: SaveMetricsRequest) => Promise<SaveMetricsResponse>
将用户提供的体能测量值保存到健康平台. iOS:为保留读权限而写时请求相同的公尺类型读取权限.
| 参数 | 类型 |
|---|---|
request | SaveMetricsRequest |
回返情况: Promise<SaveMetricsResponse>
接口
权限响应
| Prop | 类型 |
|---|---|
permissions | Record<HealthPermission, boolean> |
权限请求
| Prop | 类型 |
|---|---|
permissions | HealthPermission[] |
特征响应
| Prop | 类型 | 说明 |
|---|---|---|
biologicalSex | HealthBiologicalSex | null | |
bloodType | HealthBloodType | null | |
dateOfBirth | string | null | |
fitzpatrickSkinType | HealthFitzpatrickSkinType | null | |
wheelchairUse | HealthWheelchairUse | null | |
platformSupported | boolean | 表示平台是否通过插件(真在iOS上,假在Android上)来暴露这些特性. |
platformMessage | string | 可选的平台特有消息;在Android上,我们返回一个面向用户的注释,解释除非从iOS同步,否则数值仍然为空. |
特征请求
| Prop | 类型 | 说明 |
|---|---|---|
fields | CharacteristicField[] | 要查询的特征 。 省略时默认所有特性. |
查询分类回复
| Prop | 类型 |
|---|---|
aggregatedData | AggregatedSample[] |
总计样本
| Prop | 类型 |
|---|---|
startDate | string |
endDate | string |
value | number |
systolic | number |
diastolic | number |
unit | string |
查询分离请求
| Prop | 类型 |
|---|---|
startDate | string |
endDate | string |
dataType | 'steps' | 'active-calories' | 'total-calories' | 'basal-calories' | 'distance' | 'weight' | 'height' | 'heart-rate' | 'resting-heart-rate' | 'respiratory-rate' | 'oxygen-saturation' | 'blood-glucose' | 'body-temperature' | 'basal-body-temperature' | 'body-fat' | 'flights-climbed' | 'exercise-time' | 'distance-cycling' | 'mindfulness' | 'sleep' | 'hrv' | 'blood-pressure' |
bucket | string |
查询工作响应
| Prop | 类型 |
|---|---|
workouts | Workout[] |
errors | Record<string, string> |
工作
| Prop | 类型 |
|---|---|
startDate | string |
endDate | string |
workoutType | string |
sourceName | string |
id | string |
duration | number |
distance | number |
steps | number |
calories | number |
sourceBundleId | string |
route | RouteSample[] |
heartRate | HeartRateSample[] |
路由样板
| Prop | 类型 |
|---|---|
timestamp | string |
lat | number |
lng | number |
alt | number |
心纹样
| Prop | 类型 |
|---|---|
timestamp | string |
bpm | number |
查询工作请求
| Prop | 类型 |
|---|---|
startDate | string |
endDate | string |
includeHeartRate | boolean |
includeRoute | boolean |
includeSteps | boolean |
查询Latest 样本响应
| Prop | 类型 |
|---|---|
value | number |
systolic | number |
diastolic | number |
timestamp | number |
endTimestamp | number |
unit | string |
metadata | Record<string, unknown> |
保存工作响应
| Prop | 类型 |
|---|---|
success | boolean |
id | string |
保存工作请求
| Prop | 类型 |
|---|---|
activityType | WorkoutActivityType |
startDate | string |
endDate | string |
calories | number |
distance | number |
metadata | Record<string, any> |
route | RouteSample[] |
heartRateSamples | HeartRateSample[] |
保存计量响应
| Prop | 类型 |
|---|---|
success | boolean |
inserted | number |
保存计量请求
| Prop | 类型 |
|---|---|
weightKg | number |
heightCm | number |
bodyFatPercent | number |
restingHeartRate | number |
类型异名
记录
构造 T 类型 K 的一组属性类型
{
[P in K]: T;
}
保健
'READ_STEPS' | 'READ_WORKOUTS' | 'WRITE_WORKOUTS' | 'READ_ACTIVE_CALORIES' | 'WRITE_ACTIVE_CALORIES' | 'READ_TOTAL_CALORIES' | 'WRITE_TOTAL_CALORIES' | 'READ_DISTANCE' | 'WRITE_DISTANCE' | 'READ_WEIGHT' | 'WRITE_WEIGHT' | 'READ_HEIGHT' | 'WRITE_HEIGHT' | 'READ_HEART_RATE' | 'WRITE_HEART_RATE' | 'READ_RESTING_HEART_RATE' | 'WRITE_RESTING_HEART_RATE' | 'READ_ROUTE' | 'WRITE_ROUTE' | 'READ_MINDFULNESS' | 'READ_HRV' | 'READ_BLOOD_PRESSURE' | 'READ_BASAL_CALORIES' | 'READ_RESPIRATORY_RATE' | 'READ_OXYGEN_SATURATION' | 'READ_BLOOD_GLUCOSE' | 'READ_BODY_TEMPERATURE' | 'READ_BASAL_BODY_TEMPERATURE' | 'READ_BODY_FAT' | 'WRITE_BODY_FAT' | 'READ_FLOORS_CLIMBED' | 'READ_SLEEP' | 'READ_EXERCISE_TIME' | 'READ_BIOLOGICAL_SEX' | 'READ_BLOOD_TYPE' | 'READ_DATE_OF_BIRTH' | 'READ_FITZPATRICK_SKIN_TYPE' | 'READ_WHEELCHAIR_USE'
健康生物性行为
'female' | 'male' | 'other' | 'not_set' | 'unknown'
健康血迹图
'a-positive' | 'a-negative' | 'b-positive' | 'b-negative' | 'ab-positive' | 'ab-negative' | 'o-positive' | 'o-negative' | 'not_set' | 'unknown'
卫生基金会
'type1' | 'type2' | 'type3' | 'type4' | 'type5' | 'type6' | 'not_set' | 'unknown'
卫生椅
'wheelchair_user' | 'not_wheelchair_user' | 'not_set' | 'unknown'
特性字段
'biologicalSex' | 'bloodType' | 'dateOfBirth' | 'fitzpatrickSkinType' | 'wheelchairUse'
最新数据类型
'steps' | 'active-calories' | 'total-calories' | 'basal-calories' | 'distance' | 'weight' | 'height' | 'heart-rate' | 'resting-heart-rate' | 'respiratory-rate' | 'oxygen-saturation' | 'blood-glucose' | 'body-temperature' | 'basal-body-temperature' | 'body-fat' | 'flights-climbed' | 'exercise-time' | 'distance-cycling' | 'mindfulness' | 'sleep' | 'sleep-rem' | 'hrv' | 'blood-pressure'
工作活动类型
'rock-climbing' | 'climbing' | 'hiking' | 'running' | 'walking' | 'cycling' | 'biking' | 'strength-training' | 'yoga' | 'other'