Capacitor plugin to query data from Apple Health and Google Health Connect
Some parts, concepts and ideas are borrowed from cordova-plugin-health. Big thanks to @dariosalvi78 for the support.
npm install capacitor-health
npx cap sync
- Make sure your app id has the 'HealthKit' entitlement when this plugin is installed (see iOS dev center).
- Also, make sure your app and App Store description comply with the Apple review guidelines.
- There are two keys to be added to the info.plist file: NSHealthShareUsageDescription and NSHealthUpdateUsageDescription.
- Android Manifest in application tag
<!-- 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="com.fit_up.health.capacitor.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="com.fit_up.health.capacitor.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>
- Android Manifest in root tag
<queries>
<package android:name="com.google.android.apps.healthdata" />
</queries>
<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_DISTANCE" />
<uses-permission android:name="android.permission.health.READ_EXERCISE" />
<uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTE" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE" />
isHealthAvailable()
checkHealthPermissions(...)
requestHealthPermissions(...)
openAppleHealthSettings()
openHealthConnectSettings()
showHealthConnectInPlayStore()
queryAggregated(...)
queryWorkouts(...)
- Interfaces
- Type Aliases
isHealthAvailable() => Promise<{ available: boolean; }>
Checks if health API is available. Android: If false is returned, the Google Health Connect app is probably not installed. See showHealthConnectInPlayStore()
Returns: Promise<{ available: boolean; }>
checkHealthPermissions(permissions: PermissionsRequest) => Promise<PermissionResponse>
Android only: Returns for each given permission, if it was granted by the underlying health API
Param | Type | Description |
---|---|---|
permissions |
PermissionsRequest |
permissions to query |
Returns: Promise<PermissionResponse>
requestHealthPermissions(permissions: PermissionsRequest) => Promise<PermissionResponse>
Requests the permissions from the user.
Android: Apps can ask only a few times for permissions, after that the user has to grant them manually in the Health Connect app. See openHealthConnectSettings()
iOS: If the permissions are already granted or denied, this method will just return without asking the user. In iOS we can't really detect if a user granted or denied a permission. The return value reflects the assumption that all permissions were granted.
Param | Type | Description |
---|---|---|
permissions |
PermissionsRequest |
permissions to request |
Returns: Promise<PermissionResponse>
openAppleHealthSettings() => Promise<void>
Opens the apps settings, which is kind of wrong, because health permissions are configured under: Settings > Apps > (Apple) Health > Access and Devices > [app-name] But we can't go there directly.
openHealthConnectSettings() => Promise<void>
Opens the Google Health Connect app
showHealthConnectInPlayStore() => Promise<void>
Opens the Google Health Connect app in PlayStore
queryAggregated(request: QueryAggregatedRequest) => Promise<QueryAggregatedResponse>
Query aggregated data
Param | Type |
---|---|
request |
QueryAggregatedRequest |
Returns: Promise<QueryAggregatedResponse>
queryWorkouts(request: QueryWorkoutRequest) => Promise<QueryWorkoutResponse>
Query workouts
Param | Type |
---|---|
request |
QueryWorkoutRequest |
Returns: Promise<QueryWorkoutResponse>
Prop | Type |
---|---|
permissions |
{ [key: string]: boolean; }[] |
Prop | Type |
---|---|
permissions |
HealthPermission[] |
Prop | Type |
---|---|
aggregatedData |
AggregatedSample[] |
Prop | Type |
---|---|
startDate |
string |
endDate |
string |
value |
number |
Prop | Type |
---|---|
startDate |
string |
endDate |
string |
dataType |
'steps' | 'calories' |
bucket |
string |
Prop | Type |
---|---|
workouts |
Workout[] |
Prop | Type |
---|---|
startDate |
string |
endDate |
string |
workoutType |
string |
sourceName |
string |
id |
string |
duration |
number |
distance |
number |
calories |
number |
sourceBundleId |
string |
route |
RouteSample[] |
heartRate |
HeartRateSample[] |
Prop | Type |
---|---|
timestamp |
string |
lat |
number |
lng |
number |
alt |
number |
Prop | Type |
---|---|
timestamp |
string |
bpm |
number |
Prop | Type |
---|---|
startDate |
string |
endDate |
string |
includeHeartRate |
boolean |
includeRoute |
boolean |
'READ_STEPS' | 'READ_WORKOUTS' | 'READ_CALORIES' | 'READ_DISTANCE' | 'READ_HEART_RATE' | 'READ_ROUTE'