@flomentumsolutions/capacitor-health-extended 0.1.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{FlomentumsolutionsCapacitorHealthExtended.podspec → FlomentumSolutionsCapacitorHealthExtended.podspec} +6 -6
- package/LICENSE +1 -0
- package/Package.swift +27 -0
- package/README.md +123 -24
- package/android/build.gradle +15 -10
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/com/flomentum/health/capacitor/HealthPlugin.kt +732 -45
- package/android/src/main/java/com/flomentum/health/capacitor/PermissionsRationaleActivity.kt +1 -1
- package/dist/esm/definitions.d.ts +10 -6
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/HealthPluginPlugin/HealthPlugin.swift +544 -90
- package/package.json +40 -17
|
@@ -12,9 +12,9 @@ Pod::Spec.new do |s|
|
|
|
12
12
|
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
13
|
# Only include Swift/Obj-C source files that belong to the plugin
|
|
14
14
|
s.source_files = 'ios/Sources/HealthPluginPlugin/**/*.{swift,h,m}'
|
|
15
|
-
s.ios.deployment_target
|
|
16
|
-
s.dependency 'Capacitor', '~>
|
|
17
|
-
s.dependency 'CapacitorCordova', '~>
|
|
18
|
-
# Match the Swift shipped with Xcode 16
|
|
19
|
-
s.swift_version = '5.
|
|
20
|
-
end
|
|
15
|
+
s.ios.deployment_target = '15.0'
|
|
16
|
+
s.dependency 'Capacitor', '~> 8.0'
|
|
17
|
+
s.dependency 'CapacitorCordova', '~> 8.0'
|
|
18
|
+
# Match the Swift shipped with Xcode 15/16 (Capacitor 8)
|
|
19
|
+
s.swift_version = '5.9'
|
|
20
|
+
end
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2024 - Martin Ley1
|
|
4
|
+
Copyright (c) 2025 - Flomentum Solutions, LLC (Matthew May)
|
|
4
5
|
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
7
|
of this software and associated documentation files (the "Software"), to deal
|
package/Package.swift
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "FlomentumsolutionsCapacitorHealthExtended",
|
|
6
|
+
platforms: [
|
|
7
|
+
.iOS(.v15)
|
|
8
|
+
],
|
|
9
|
+
products: [
|
|
10
|
+
.library(
|
|
11
|
+
name: "FlomentumsolutionsCapacitorHealthExtended",
|
|
12
|
+
targets: ["HealthPluginPlugin"]
|
|
13
|
+
)
|
|
14
|
+
],
|
|
15
|
+
dependencies: [
|
|
16
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
|
|
17
|
+
],
|
|
18
|
+
targets: [
|
|
19
|
+
.target(
|
|
20
|
+
name: "HealthPluginPlugin",
|
|
21
|
+
dependencies: [
|
|
22
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm")
|
|
23
|
+
],
|
|
24
|
+
path: "ios/Sources/HealthPluginPlugin"
|
|
25
|
+
)
|
|
26
|
+
]
|
|
27
|
+
)
|
package/README.md
CHANGED
|
@@ -1,21 +1,25 @@
|
|
|
1
|
-
# capacitor-health-extended
|
|
1
|
+
# @flomentumsolutions/capacitor-health-extended
|
|
2
2
|
|
|
3
3
|
Cross‑platform Capacitor plugin for reading data from Apple HealthKit and
|
|
4
|
-
Google Health Connect. The plugin requires **Node.js
|
|
5
|
-
with **Capacitor
|
|
4
|
+
Google Health Connect. The plugin requires **Node.js 22+** and is compatible
|
|
5
|
+
with **Capacitor 8**. For iOS the plugin ships a **Swift Package Manager**
|
|
6
|
+
distribution (Capacitor 8 default), while the CocoaPods spec
|
|
7
|
+
`FlomentumSolutionsCapacitorHealthExtended` remains for legacy projects.
|
|
6
8
|
|
|
7
9
|
## Thanks and attribution
|
|
8
10
|
|
|
9
|
-
Forked from [capacitor-health](https://github
|
|
11
|
+
Forked from [capacitor-health](https://github.com/mley/capacitor-health) and as such...
|
|
10
12
|
- Some parts, concepts and ideas are borrowed from [cordova-plugin-health](https://github.com/dariosalvi78/cordova-plugin-health/).
|
|
11
13
|
- Big thanks to [@dariosalvi78](https://github.com/dariosalvi78) for the support.
|
|
12
14
|
|
|
13
15
|
Thanks [@mley](https://github.com/mley) for the ground work. The goal of this fork is to extend functionality and datapoints and keep up with the ever-changing brand-new Android Health Connect Platform. I'm hoping to create platform parity for capacitor API-based health data access.
|
|
14
16
|
|
|
15
|
-
## Requirements
|
|
17
|
+
## Requirements (Plugin & Consuming Apps)
|
|
16
18
|
|
|
17
|
-
- Node.js
|
|
18
|
-
- Capacitor
|
|
19
|
+
- Node.js 22+ (Latest LTS version is recommended)
|
|
20
|
+
- Capacitor 8
|
|
21
|
+
- iOS 15+ (Xcode 26 + HealthKit + SwiftPM toolchain)
|
|
22
|
+
- Android 16+ (Android Studio Otter 2025.2.1 + Health Connect 1.2.0-alpha02 + Gradle 8.13.0 + Kotlin 2.2.20)
|
|
19
23
|
|
|
20
24
|
## Features
|
|
21
25
|
|
|
@@ -23,22 +27,34 @@ Thanks [@mley](https://github.com/mley) for the ground work. The goal of this fo
|
|
|
23
27
|
- Request and verify health permissions
|
|
24
28
|
- Query aggregated data like steps or calories
|
|
25
29
|
- Retrieve workout sessions with optional route and heart rate data
|
|
26
|
-
- Fetch the latest
|
|
30
|
+
- Fetch the latest samples for steps, distance (incl. cycling), calories (active/total/basal), heart‑rate, resting HR, HRV, respiratory rate, blood pressure, oxygen saturation, blood glucose, body temperature (basal + core), body fat, height, weight, flights climbed, sleep, and exercise time.
|
|
31
|
+
|
|
32
|
+
### Supported data types (parity iOS + Android)
|
|
33
|
+
- Activity: steps, distance, distance‑cycling, exercise time (Apple Exercise Time), workouts (with routes/steps/calories), flights climbed
|
|
34
|
+
- Energy: active calories, total calories, basal calories
|
|
35
|
+
- Vitals: heart rate, resting heart rate, HRV, respiratory rate, blood pressure, oxygen saturation, blood glucose, body temperature, basal body temperature
|
|
36
|
+
- Body: weight, height, body fat
|
|
37
|
+
- Sessions: mindfulness, sleep
|
|
27
38
|
|
|
28
39
|
## Install
|
|
29
40
|
|
|
30
41
|
```bash
|
|
31
|
-
npm install capacitor-health-extended
|
|
42
|
+
npm install @flomentumsolutions/capacitor-health-extended
|
|
32
43
|
npx cap sync
|
|
33
44
|
```
|
|
34
45
|
|
|
35
|
-
## Setup
|
|
46
|
+
## Setup Consuming Apps
|
|
36
47
|
|
|
37
48
|
### iOS
|
|
38
49
|
|
|
50
|
+
Capacitor 8 resolves iOS plugins via SwiftPM. Running `npx cap sync ios` will
|
|
51
|
+
add the `FlomentumSolutionsCapacitorHealthExtended` package (backed by
|
|
52
|
+
`capacitor-swift-pm`) to your Xcode project. If you are pinned to Capacitor 7,
|
|
53
|
+
you can keep using the CocoaPods spec `FlomentumSolutionsCapacitorHealthExtended`.
|
|
54
|
+
|
|
39
55
|
* Make sure your app id has the 'HealthKit' entitlement when this plugin is installed (see iOS dev center).
|
|
40
56
|
* Also, make sure your app and App Store description comply with the Apple review guidelines.
|
|
41
|
-
* There are two keys to be added to the info.plist file: NSHealthShareUsageDescription and NSHealthUpdateUsageDescription.
|
|
57
|
+
* There are two keys to be added to the info.plist file: NSHealthShareUsageDescription and NSHealthUpdateUsageDescription.
|
|
42
58
|
|
|
43
59
|
### Android
|
|
44
60
|
|
|
@@ -61,9 +77,19 @@ npx cap sync
|
|
|
61
77
|
<uses-permission android:name="android.permission.health.READ_HEIGHT" />
|
|
62
78
|
<uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" />
|
|
63
79
|
<uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE" />
|
|
80
|
+
<uses-permission android:name="android.permission.health.READ_MINDFULNESS" />
|
|
81
|
+
<uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE" />
|
|
82
|
+
<uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE" />
|
|
83
|
+
<uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" />
|
|
84
|
+
<uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" />
|
|
85
|
+
<uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" />
|
|
86
|
+
<uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" />
|
|
87
|
+
<uses-permission android:name="android.permission.health.READ_BODY_FAT" />
|
|
88
|
+
<uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
|
|
89
|
+
<uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" />
|
|
90
|
+
<uses-permission android:name="android.permission.health.READ_SLEEP" />
|
|
64
91
|
```
|
|
65
92
|
|
|
66
|
-
|
|
67
93
|
* Android Manifest in application tag
|
|
68
94
|
```xml
|
|
69
95
|
<!-- Handle Health Connect rationale (Android 13-) -->
|
|
@@ -99,6 +125,69 @@ npx cap sync
|
|
|
99
125
|
</application>
|
|
100
126
|
```
|
|
101
127
|
|
|
128
|
+
* Create `com.my.app.PermissionsRationaleActivity.kt` with:
|
|
129
|
+
```xml
|
|
130
|
+
package com.my.app
|
|
131
|
+
|
|
132
|
+
import android.os.Bundle
|
|
133
|
+
import android.util.Log
|
|
134
|
+
import android.webkit.WebChromeClient
|
|
135
|
+
import android.webkit.WebView
|
|
136
|
+
import android.webkit.WebViewClient
|
|
137
|
+
import androidx.activity.addCallback
|
|
138
|
+
import androidx.appcompat.app.AppCompatActivity
|
|
139
|
+
|
|
140
|
+
class PermissionsRationaleActivity : AppCompatActivity() {
|
|
141
|
+
private lateinit var webView: WebView
|
|
142
|
+
|
|
143
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
144
|
+
super.onCreate(savedInstanceState)
|
|
145
|
+
|
|
146
|
+
supportActionBar?.apply {
|
|
147
|
+
title = "Privacy Policy"
|
|
148
|
+
setDisplayHomeAsUpEnabled(true)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
webView = WebView(this).apply {
|
|
152
|
+
settings.apply {
|
|
153
|
+
javaScriptEnabled = true
|
|
154
|
+
domStorageEnabled = true
|
|
155
|
+
useWideViewPort = true
|
|
156
|
+
loadWithOverviewMode = true
|
|
157
|
+
}
|
|
158
|
+
webChromeClient = WebChromeClient()
|
|
159
|
+
webViewClient = object : WebViewClient() {
|
|
160
|
+
override fun shouldOverrideUrlLoading(view: WebView, request: android.webkit.WebResourceRequest) = false
|
|
161
|
+
override fun onReceivedError(
|
|
162
|
+
view: WebView,
|
|
163
|
+
request: android.webkit.WebResourceRequest,
|
|
164
|
+
error: android.webkit.WebResourceError
|
|
165
|
+
) {
|
|
166
|
+
Log.e("WebView", "Failed to load: ${error.description}")
|
|
167
|
+
}
|
|
168
|
+
override fun onPageFinished(view: WebView, url: String) {
|
|
169
|
+
Log.d("WebView", "Loaded: $url")
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
loadUrl("https://mywebsite.com/privacy-policy")
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
setContentView(webView)
|
|
176
|
+
|
|
177
|
+
// Device back button behavior
|
|
178
|
+
onBackPressedDispatcher.addCallback(this) {
|
|
179
|
+
finish()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Toolbar Up button behavior
|
|
184
|
+
override fun onSupportNavigateUp(): Boolean {
|
|
185
|
+
finish()
|
|
186
|
+
return true
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
102
191
|
* Create `res/xml/network_security_config.xml` with:
|
|
103
192
|
|
|
104
193
|
```xml
|
|
@@ -244,6 +333,13 @@ Query aggregated data
|
|
|
244
333
|
|
|
245
334
|
**Returns:** <code>Promise<<a href="#queryaggregatedresponse">QueryAggregatedResponse</a>></code>
|
|
246
335
|
|
|
336
|
+
- Blood-pressure aggregates return the systolic average in `value` plus `systolic`, `diastolic`, and `unit`.
|
|
337
|
+
- On iOS `total-calories` is derived as active + basal energy (Android uses Health Connect's total calories when available).
|
|
338
|
+
- Weight/height aggregation returns the latest sample per day (no averaging).
|
|
339
|
+
- Android aggregation currently supports daily buckets; unsupported buckets will be rejected.
|
|
340
|
+
- Android `distance-cycling` aggregates distance recorded during biking exercise sessions (requires distance + workouts permissions).
|
|
341
|
+
- Daily `bucket: "day"` queries use calendar-day boundaries in the device time zone (start-of-day through the next start-of-day) instead of a trailing 24-hour window. For “today,” send `startDate` at today’s start-of-day and `endDate` at now or tomorrow’s start-of-day.
|
|
342
|
+
|
|
247
343
|
--------------------
|
|
248
344
|
|
|
249
345
|
|
|
@@ -340,7 +436,7 @@ Query latest steps sample
|
|
|
340
436
|
|
|
341
437
|
| Prop | Type |
|
|
342
438
|
| ----------------- | ------------------------------------------ |
|
|
343
|
-
| **`permissions`** | <code>
|
|
439
|
+
| **`permissions`** | <code>Record<HealthPermission, boolean></code> |
|
|
344
440
|
|
|
345
441
|
|
|
346
442
|
#### PermissionsRequest
|
|
@@ -359,21 +455,24 @@ Query latest steps sample
|
|
|
359
455
|
|
|
360
456
|
#### AggregatedSample
|
|
361
457
|
|
|
362
|
-
| Prop
|
|
363
|
-
|
|
|
364
|
-
| **`startDate`**
|
|
365
|
-
| **`endDate`**
|
|
366
|
-
| **`value`**
|
|
458
|
+
| Prop | Type |
|
|
459
|
+
| ----------------- | ------------------- |
|
|
460
|
+
| **`startDate`** | <code>string</code> |
|
|
461
|
+
| **`endDate`** | <code>string</code> |
|
|
462
|
+
| **`value`** | <code>number</code> |
|
|
463
|
+
| **`systolic`** | <code>number</code> |
|
|
464
|
+
| **`diastolic`** | <code>number</code> |
|
|
465
|
+
| **`unit`** | <code>string</code> |
|
|
367
466
|
|
|
368
467
|
|
|
369
468
|
#### QueryAggregatedRequest
|
|
370
469
|
|
|
371
|
-
| Prop | Type
|
|
372
|
-
| --------------- |
|
|
373
|
-
| **`startDate`** | <code>string</code>
|
|
374
|
-
| **`endDate`** | <code>string</code>
|
|
375
|
-
| **`dataType`** | <code>'steps' \| 'active-calories' \| 'mindfulness' \| 'hrv' \| 'blood-pressure'</code> |
|
|
376
|
-
| **`bucket`** | <code>string</code>
|
|
470
|
+
| Prop | Type |
|
|
471
|
+
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
472
|
+
| **`startDate`** | <code>string</code> |
|
|
473
|
+
| **`endDate`** | <code>string</code> |
|
|
474
|
+
| **`dataType`** | <code>'steps' \| 'active-calories' \| 'total-calories' \| 'basal-calories' \| 'distance' \| 'distance-cycling' \| 'weight' \| 'height' \| 'heart-rate' \| 'resting-heart-rate' \| 'respiratory-rate' \| 'oxygen-saturation' \| 'blood-glucose' \| 'body-temperature' \| 'basal-body-temperature' \| 'body-fat' \| 'flights-climbed' \| 'exercise-time' \| 'sleep' \| 'mindfulness' \| 'hrv' \| 'blood-pressure'</code> |
|
|
475
|
+
| **`bucket`** | <code>string</code> |
|
|
377
476
|
|
|
378
477
|
|
|
379
478
|
#### QueryWorkoutResponse
|
package/android/build.gradle
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
2
|
+
|
|
1
3
|
ext {
|
|
2
4
|
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
5
|
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
|
4
|
-
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.
|
|
5
|
-
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.
|
|
6
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
|
|
7
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
buildscript {
|
|
9
11
|
ext {
|
|
10
|
-
kotlin_version = '2.2.
|
|
12
|
+
kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '2.2.20'
|
|
11
13
|
}
|
|
12
14
|
repositories {
|
|
13
15
|
google()
|
|
14
16
|
mavenCentral()
|
|
15
17
|
}
|
|
16
18
|
dependencies {
|
|
17
|
-
classpath 'com.android.tools.build:gradle:8.
|
|
19
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
18
20
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
19
21
|
}
|
|
20
22
|
}
|
|
@@ -23,8 +25,8 @@ apply plugin: 'com.android.library'
|
|
|
23
25
|
apply plugin: 'org.jetbrains.kotlin.android'
|
|
24
26
|
|
|
25
27
|
android {
|
|
26
|
-
namespace "com.
|
|
27
|
-
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
28
|
+
namespace = "com.flomentumsolutions.health.capacitor"
|
|
29
|
+
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
28
30
|
defaultConfig {
|
|
29
31
|
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 36
|
|
30
32
|
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
|
@@ -39,14 +41,17 @@ android {
|
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
lintOptions {
|
|
42
|
-
abortOnError false
|
|
44
|
+
abortOnError = false
|
|
43
45
|
}
|
|
44
46
|
compileOptions {
|
|
45
47
|
sourceCompatibility JavaVersion.VERSION_21
|
|
46
48
|
targetCompatibility JavaVersion.VERSION_21
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
kotlin {
|
|
53
|
+
compilerOptions {
|
|
54
|
+
jvmTarget = JvmTarget.JVM_21
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
|
|
@@ -61,7 +66,7 @@ dependencies {
|
|
|
61
66
|
implementation project(':capacitor-android')
|
|
62
67
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
63
68
|
|
|
64
|
-
implementation 'androidx.health.connect:connect-client:1.
|
|
69
|
+
implementation 'androidx.health.connect:connect-client:1.2.0-alpha02'
|
|
65
70
|
implementation 'androidx.core:core-ktx:1.13.1'
|
|
66
71
|
|
|
67
72
|
testImplementation "junit:junit:$junitVersion"
|