@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.
@@ -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 = '14.0'
16
- s.dependency 'Capacitor', '~> 7.0'
17
- s.dependency 'CapacitorCordova', '~> 7.0'
18
- # Match the Swift shipped with Xcode 16
19
- s.swift_version = '5.10'
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 20+** and is compatible
5
- with **Capacitor 7**.
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.,com/mley/capacitor-health) and as such...
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 20 or newer
18
- - Capacitor 7
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 sample for steps, heart‑rate, or weight
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&lt;<a href="#queryaggregatedresponse">QueryAggregatedResponse</a>&gt;</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>{ [key: string]: boolean; }[]</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 | Type |
363
- | --------------- | ------------------- |
364
- | **`startDate`** | <code>string</code> |
365
- | **`endDate`** | <code>string</code> |
366
- | **`value`** | <code>number</code> |
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
@@ -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.2.1'
5
- androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
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.0'
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.11.1'
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.flomentum.health.capacitor"
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
- kotlinOptions {
49
- jvmTarget = '21'
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.1.0-rc03'
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"
@@ -1,3 +1,3 @@
1
- <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.flomentum.health.capacitor">
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.flomentumsolutions.health.capacitor">
2
2
 
3
3
  </manifest>