@capgo/capacitor-health 7.0.0

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.
@@ -0,0 +1,18 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'CapgoCapacitorHealth'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license']
10
+ s.homepage = package['repository']['url']
11
+ s.author = package['author']
12
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '14.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ s.frameworks = 'HealthKit'
18
+ end
package/Package.swift ADDED
@@ -0,0 +1,31 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapgoCapacitorHealth",
6
+ platforms: [.iOS(.v14)],
7
+ products: [
8
+ .library(
9
+ name: "CapgoCapacitorHealth",
10
+ targets: ["HealthPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "HealthPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Sources/HealthPlugin",
23
+ linkerSettings: [
24
+ .linkedFramework("HealthKit")
25
+ ]),
26
+ .testTarget(
27
+ name: "HealthPluginTests",
28
+ dependencies: ["HealthPlugin"],
29
+ path: "ios/Tests/HealthPluginTests")
30
+ ]
31
+ )
package/README.md ADDED
@@ -0,0 +1,273 @@
1
+ # @capgo/capacitor-health
2
+ <a href="https://capgo.app/"><img src='https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png' alt='Capgo - Instant updates for capacitor'/></a>
3
+
4
+ <div align="center">
5
+ <h2><a href="https://capgo.app/?ref=plugin"> ➡️ Get Instant updates for your App with Capgo</a></h2>
6
+ <h2><a href="https://capgo.app/consulting/?ref=plugin"> Missing a feature? We’ll build the plugin for you 💪</a></h2>
7
+ </div>
8
+
9
+ Capacitor plugin to read and write health metrics via Apple HealthKit (iOS) and Health Connect (Android). The TypeScript API keeps the same data types and units across platforms so you can build once and deploy everywhere.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @capgo/capacitor-health
15
+ npx cap sync
16
+ ```
17
+
18
+ ## iOS Setup
19
+
20
+ 1. Open your Capacitor application's Xcode workspace and enable the **HealthKit** capability.
21
+ 2. Provide usage descriptions in `Info.plist` (update the copy for your product):
22
+
23
+ ```xml
24
+ <key>NSHealthShareUsageDescription</key>
25
+ <string>This app reads your health data to personalise your experience.</string>
26
+ <key>NSHealthUpdateUsageDescription</key>
27
+ <string>This app writes new health entries that you explicitly create.</string>
28
+ ```
29
+
30
+ ## Android Setup
31
+
32
+ This plugin now uses [Health Connect](https://developer.android.com/health-and-fitness/guides/health-connect) instead of Google Fit. Make sure your app meets the requirements below:
33
+
34
+ 1. **Min SDK 26+.** Health Connect is only available on Android 8.0 (API 26) and above. The plugin’s Gradle setup already targets this level.
35
+ 2. **Declare Health permissions.** The plugin manifest ships with the required `<uses-permission>` declarations (`READ_/WRITE_STEPS`, `READ_/WRITE_DISTANCE`, `READ_/WRITE_ACTIVE_CALORIES_BURNED`, `READ_/WRITE_HEART_RATE`, `READ_/WRITE_WEIGHT`). Your app does not need to duplicate them, but you must surface a user-facing rationale because the permissions are considered health sensitive.
36
+ 3. **Ensure Health Connect is installed.** Devices on Android 14+ include it by default. For earlier versions the user must install *Health Connect by Android* from the Play Store. The `Health.isAvailable()` helper exposes the current status so you can prompt accordingly.
37
+ 4. **Request runtime access.** The plugin opens the Health Connect permission UI when you call `requestAuthorization`. You should still handle denial flows (e.g., show a message if `checkAuthorization` reports missing scopes).
38
+
39
+ If you already used Google Fit in your project you can remove the associated dependencies (`play-services-fitness`, `play-services-auth`, OAuth configuration, etc.).
40
+
41
+ ## Usage
42
+
43
+ ```ts
44
+ import { Health } from '@capgo/capacitor-health';
45
+
46
+ // Verify that the native health SDK is present on this device
47
+ const availability = await Health.isAvailable();
48
+ if (!availability.available) {
49
+ console.warn('Health access unavailable:', availability.reason);
50
+ }
51
+
52
+ // Ask for separate read/write access scopes
53
+ await Health.requestAuthorization({
54
+ read: ['steps', 'heartRate', 'weight'],
55
+ write: ['weight'],
56
+ });
57
+
58
+ // Query the last 50 step samples from the past 24 hours
59
+ const { samples } = await Health.readSamples({
60
+ dataType: 'steps',
61
+ startDate: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
62
+ endDate: new Date().toISOString(),
63
+ limit: 50,
64
+ });
65
+
66
+ // Persist a new body-weight entry (kilograms by default)
67
+ await Health.saveSample({
68
+ dataType: 'weight',
69
+ value: 74.3,
70
+ });
71
+ ```
72
+
73
+ ### Supported data types
74
+
75
+ | Identifier | Default unit | Notes |
76
+ | ---------- | ------------- | ----- |
77
+ | `steps` | `count` | Step count deltas |
78
+ | `distance` | `meter` | Walking / running distance |
79
+ | `calories` | `kilocalorie` | Active energy burned |
80
+ | `heartRate`| `bpm` | Beats per minute |
81
+ | `weight` | `kilogram` | Body mass |
82
+
83
+ All write operations expect the default unit shown above. On Android the `metadata` option is currently ignored by Health Connect.
84
+
85
+ ## API
86
+
87
+ <docgen-index>
88
+
89
+ * [`isAvailable()`](#isavailable)
90
+ * [`requestAuthorization(...)`](#requestauthorization)
91
+ * [`checkAuthorization(...)`](#checkauthorization)
92
+ * [`readSamples(...)`](#readsamples)
93
+ * [`saveSample(...)`](#savesample)
94
+ * [Interfaces](#interfaces)
95
+ * [Type Aliases](#type-aliases)
96
+
97
+ </docgen-index>
98
+
99
+ <docgen-api>
100
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
101
+
102
+ ### isAvailable()
103
+
104
+ ```typescript
105
+ isAvailable() => Promise<AvailabilityResult>
106
+ ```
107
+
108
+ Returns whether the current platform supports the native health SDK.
109
+
110
+ **Returns:** <code>Promise&lt;<a href="#availabilityresult">AvailabilityResult</a>&gt;</code>
111
+
112
+ --------------------
113
+
114
+
115
+ ### requestAuthorization(...)
116
+
117
+ ```typescript
118
+ requestAuthorization(options: AuthorizationOptions) => Promise<AuthorizationStatus>
119
+ ```
120
+
121
+ Requests read/write access to the provided data types.
122
+
123
+ | Param | Type |
124
+ | ------------- | --------------------------------------------------------------------- |
125
+ | **`options`** | <code><a href="#authorizationoptions">AuthorizationOptions</a></code> |
126
+
127
+ **Returns:** <code>Promise&lt;<a href="#authorizationstatus">AuthorizationStatus</a>&gt;</code>
128
+
129
+ --------------------
130
+
131
+
132
+ ### checkAuthorization(...)
133
+
134
+ ```typescript
135
+ checkAuthorization(options: AuthorizationOptions) => Promise<AuthorizationStatus>
136
+ ```
137
+
138
+ Checks authorization status for the provided data types without prompting the user.
139
+
140
+ | Param | Type |
141
+ | ------------- | --------------------------------------------------------------------- |
142
+ | **`options`** | <code><a href="#authorizationoptions">AuthorizationOptions</a></code> |
143
+
144
+ **Returns:** <code>Promise&lt;<a href="#authorizationstatus">AuthorizationStatus</a>&gt;</code>
145
+
146
+ --------------------
147
+
148
+
149
+ ### readSamples(...)
150
+
151
+ ```typescript
152
+ readSamples(options: QueryOptions) => Promise<ReadSamplesResult>
153
+ ```
154
+
155
+ Reads samples for the given data type within the specified time frame.
156
+
157
+ | Param | Type |
158
+ | ------------- | ----------------------------------------------------- |
159
+ | **`options`** | <code><a href="#queryoptions">QueryOptions</a></code> |
160
+
161
+ **Returns:** <code>Promise&lt;<a href="#readsamplesresult">ReadSamplesResult</a>&gt;</code>
162
+
163
+ --------------------
164
+
165
+
166
+ ### saveSample(...)
167
+
168
+ ```typescript
169
+ saveSample(options: WriteSampleOptions) => Promise<void>
170
+ ```
171
+
172
+ Writes a single sample to the native health store.
173
+
174
+ | Param | Type |
175
+ | ------------- | ----------------------------------------------------------------- |
176
+ | **`options`** | <code><a href="#writesampleoptions">WriteSampleOptions</a></code> |
177
+
178
+ --------------------
179
+
180
+
181
+ ### Interfaces
182
+
183
+
184
+ #### AvailabilityResult
185
+
186
+ | Prop | Type | Description |
187
+ | --------------- | ---------------------------------------- | ------------------------------------------------------ |
188
+ | **`available`** | <code>boolean</code> | |
189
+ | **`platform`** | <code>'ios' \| 'android' \| 'web'</code> | Platform specific details (for debugging/diagnostics). |
190
+ | **`reason`** | <code>string</code> | |
191
+
192
+
193
+ #### AuthorizationStatus
194
+
195
+ | Prop | Type |
196
+ | --------------------- | ----------------------------- |
197
+ | **`readAuthorized`** | <code>HealthDataType[]</code> |
198
+ | **`readDenied`** | <code>HealthDataType[]</code> |
199
+ | **`writeAuthorized`** | <code>HealthDataType[]</code> |
200
+ | **`writeDenied`** | <code>HealthDataType[]</code> |
201
+
202
+
203
+ #### AuthorizationOptions
204
+
205
+ | Prop | Type | Description |
206
+ | ----------- | ----------------------------- | ------------------------------------------------------- |
207
+ | **`read`** | <code>HealthDataType[]</code> | Data types that should be readable after authorization. |
208
+ | **`write`** | <code>HealthDataType[]</code> | Data types that should be writable after authorization. |
209
+
210
+
211
+ #### ReadSamplesResult
212
+
213
+ | Prop | Type |
214
+ | ------------- | --------------------------- |
215
+ | **`samples`** | <code>HealthSample[]</code> |
216
+
217
+
218
+ #### HealthSample
219
+
220
+ | Prop | Type |
221
+ | ---------------- | --------------------------------------------------------- |
222
+ | **`dataType`** | <code><a href="#healthdatatype">HealthDataType</a></code> |
223
+ | **`value`** | <code>number</code> |
224
+ | **`unit`** | <code><a href="#healthunit">HealthUnit</a></code> |
225
+ | **`startDate`** | <code>string</code> |
226
+ | **`endDate`** | <code>string</code> |
227
+ | **`sourceName`** | <code>string</code> |
228
+ | **`sourceId`** | <code>string</code> |
229
+
230
+
231
+ #### QueryOptions
232
+
233
+ | Prop | Type | Description |
234
+ | --------------- | --------------------------------------------------------- | ------------------------------------------------------------------ |
235
+ | **`dataType`** | <code><a href="#healthdatatype">HealthDataType</a></code> | The type of data to retrieve from the health store. |
236
+ | **`startDate`** | <code>string</code> | Inclusive ISO 8601 start date (defaults to now - 1 day). |
237
+ | **`endDate`** | <code>string</code> | Exclusive ISO 8601 end date (defaults to now). |
238
+ | **`limit`** | <code>number</code> | Maximum number of samples to return (defaults to 100). |
239
+ | **`ascending`** | <code>boolean</code> | Return results sorted ascending by start date (defaults to false). |
240
+
241
+
242
+ #### WriteSampleOptions
243
+
244
+ | Prop | Type | Description |
245
+ | --------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
246
+ | **`dataType`** | <code><a href="#healthdatatype">HealthDataType</a></code> | |
247
+ | **`value`** | <code>number</code> | |
248
+ | **`unit`** | <code><a href="#healthunit">HealthUnit</a></code> | Optional unit override. If omitted, the default unit for the data type is used (count for `steps`, meter for `distance`, kilocalorie for `calories`, bpm for `heartRate`, kilogram for `weight`). |
249
+ | **`startDate`** | <code>string</code> | ISO 8601 start date for the sample. Defaults to now. |
250
+ | **`endDate`** | <code>string</code> | ISO 8601 end date for the sample. Defaults to startDate. |
251
+ | **`metadata`** | <code><a href="#record">Record</a>&lt;string, string&gt;</code> | Metadata key-value pairs forwarded to the native APIs where supported. |
252
+
253
+
254
+ ### Type Aliases
255
+
256
+
257
+ #### HealthDataType
258
+
259
+ <code>'steps' | 'distance' | 'calories' | 'heartRate' | 'weight'</code>
260
+
261
+
262
+ #### HealthUnit
263
+
264
+ <code>'count' | 'meter' | 'kilocalorie' | 'bpm' | 'kilogram'</code>
265
+
266
+
267
+ #### Record
268
+
269
+ Construct a type with a set of properties K of type T
270
+
271
+ <code>{
272
  [P in K]: T;
1
273
  }</code>
274
+
275
+ </docgen-api>
@@ -0,0 +1,72 @@
1
+ def kotlinVersion = '1.9.24'
2
+ project.ext.kotlinVersion = kotlinVersion
3
+
4
+ ext {
5
+ junitVersion = '4.13.2'
6
+ androidxAppCompatVersion = '1.7.0'
7
+ androidxJunitVersion = '1.2.1'
8
+ androidxEspressoCoreVersion = '3.6.1'
9
+ }
10
+
11
+ buildscript {
12
+ repositories {
13
+ google()
14
+ mavenCentral()
15
+ }
16
+ dependencies {
17
+ classpath 'com.android.tools.build:gradle:8.7.2'
18
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.24'
19
+ }
20
+ }
21
+
22
+ apply plugin: 'com.android.library'
23
+ apply plugin: 'org.jetbrains.kotlin.android'
24
+
25
+ android {
26
+ namespace "app.capgo.plugin.health"
27
+ compileSdk 35
28
+
29
+ defaultConfig {
30
+ minSdk 26
31
+ targetSdk 35
32
+ versionCode 1
33
+ versionName "1.0"
34
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
35
+ }
36
+ buildTypes {
37
+ release {
38
+ minifyEnabled false
39
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
40
+ }
41
+ }
42
+ lint {
43
+ abortOnError false
44
+ }
45
+ compileOptions {
46
+ sourceCompatibility JavaVersion.VERSION_21
47
+ targetCompatibility JavaVersion.VERSION_21
48
+ coreLibraryDesugaringEnabled true
49
+ }
50
+ kotlinOptions {
51
+ jvmTarget = JavaVersion.VERSION_21.toString()
52
+ }
53
+ }
54
+
55
+ repositories {
56
+ google()
57
+ mavenCentral()
58
+ }
59
+
60
+
61
+ dependencies {
62
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
63
+ implementation project(':capacitor-android')
64
+ implementation "androidx.appcompat:appcompat:${androidxAppCompatVersion}"
65
+ implementation ("org.jetbrains.kotlin:kotlin-stdlib:" + project.ext.kotlinVersion)
66
+ implementation 'androidx.health.connect:connect-client:1.1.0-alpha10'
67
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1'
68
+ coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
69
+ testImplementation "junit:junit:${junitVersion}"
70
+ androidTestImplementation "androidx.test.ext:junit:${androidxJunitVersion}"
71
+ androidTestImplementation "androidx.test.espresso:espresso-core:${androidxEspressoCoreVersion}"
72
+ }
@@ -0,0 +1,12 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <uses-permission android:name="android.permission.health.READ_STEPS" />
3
+ <uses-permission android:name="android.permission.health.WRITE_STEPS" />
4
+ <uses-permission android:name="android.permission.health.READ_DISTANCE" />
5
+ <uses-permission android:name="android.permission.health.WRITE_DISTANCE" />
6
+ <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />
7
+ <uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED" />
8
+ <uses-permission android:name="android.permission.health.READ_HEART_RATE" />
9
+ <uses-permission android:name="android.permission.health.WRITE_HEART_RATE" />
10
+ <uses-permission android:name="android.permission.health.READ_WEIGHT" />
11
+ <uses-permission android:name="android.permission.health.WRITE_WEIGHT" />
12
+ </manifest>
@@ -0,0 +1,11 @@
1
+ package app.capgo.plugin.health;
2
+
3
+ import com.getcapacitor.Logger;
4
+
5
+ public class Health {
6
+
7
+ public String echo(String value) {
8
+ Logger.info("Echo", value);
9
+ return value;
10
+ }
11
+ }
@@ -0,0 +1,34 @@
1
+ package app.capgo.plugin.health
2
+
3
+ import androidx.health.connect.client.permission.HealthPermission
4
+ import androidx.health.connect.client.records.ActiveCaloriesBurnedRecord
5
+ import androidx.health.connect.client.records.DistanceRecord
6
+ import androidx.health.connect.client.records.HeartRateRecord
7
+ import androidx.health.connect.client.records.Record
8
+ import androidx.health.connect.client.records.StepsRecord
9
+ import androidx.health.connect.client.records.WeightRecord
10
+ import kotlin.reflect.KClass
11
+
12
+ enum class HealthDataType(
13
+ val identifier: String,
14
+ val recordClass: KClass<out Record>,
15
+ val unit: String
16
+ ) {
17
+ STEPS("steps", StepsRecord::class, "count"),
18
+ DISTANCE("distance", DistanceRecord::class, "meter"),
19
+ CALORIES("calories", ActiveCaloriesBurnedRecord::class, "kilocalorie"),
20
+ HEART_RATE("heartRate", HeartRateRecord::class, "bpm"),
21
+ WEIGHT("weight", WeightRecord::class, "kilogram");
22
+
23
+ val readPermission: String
24
+ get() = HealthPermission.getReadPermission(recordClass)
25
+
26
+ val writePermission: String
27
+ get() = HealthPermission.getWritePermission(recordClass)
28
+
29
+ companion object {
30
+ fun from(identifier: String): HealthDataType? {
31
+ return entries.firstOrNull { it.identifier == identifier }
32
+ }
33
+ }
34
+ }