@flomentumsolutions/capacitor-health-extended 0.0.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.
@@ -0,0 +1,86 @@
1
+ /**
2
+ * ──────────────────────────────────────────────────────────────────────────────
3
+ * IMPORTANT SETUP NOTICE FOR HEALTH CONNECT PERMISSIONS RATIONALE ACTIVITY
4
+ * ──────────────────────────────────────────────────────────────────────────────
5
+ *
6
+ * This `PermissionsRationaleActivity` class must be copied into your **end-user app**
7
+ * (typically at: `android/app/src/main/java/<your-app-package>/PermissionsRationaleActivity.kt`)
8
+ * and registered in your app's `AndroidManifest.xml`.
9
+ *
10
+ * WHY THIS IS NECESSARY:
11
+ * Health Connect requires this Activity to be declared in the final **merged manifest**.
12
+ * Android will not recognize it if it's only inside a Capacitor plugin or library module.
13
+ * If this class is not present in the main app project, the following issues will occur:
14
+ *
15
+ * - `Health Connect rationale screen not found` warnings
16
+ * - The Health Connect permissions dialog may silently fail to appear
17
+ * - Permissions will never be granted, breaking health data access on Android
18
+ *
19
+ * ──────────────────────────────────────────────────────────────────────────────
20
+ * TO FIX:
21
+ * 1. Copy this file to your app's native Android directory.
22
+ * 2. Add the `<activity>` and `<activity-alias>` declarations for this class
23
+ * into your AndroidManifest.xml file (in the app module). --> You can find an example manifest block in the plugin README.
24
+ * 3. Rebuild and re-deploy your app.
25
+ *
26
+ */
27
+
28
+ // package com.[YOUR_ORGANIZATION].[YOUR_APP...]
29
+
30
+ import android.os.Bundle
31
+ import android.util.Log
32
+ import android.webkit.WebChromeClient
33
+ import android.webkit.WebView
34
+ import android.webkit.WebViewClient
35
+ import androidx.activity.addCallback
36
+ import androidx.appcompat.app.AppCompatActivity
37
+
38
+ class PermissionsRationaleActivity : AppCompatActivity() {
39
+ private lateinit var webView: WebView
40
+
41
+ override fun onCreate(savedInstanceState: Bundle?) {
42
+ super.onCreate(savedInstanceState)
43
+
44
+ supportActionBar?.apply {
45
+ title = "Privacy Policy"
46
+ setDisplayHomeAsUpEnabled(true)
47
+ }
48
+
49
+ webView = WebView(this).apply {
50
+ settings.apply {
51
+ javaScriptEnabled = true
52
+ domStorageEnabled = true
53
+ useWideViewPort = true
54
+ loadWithOverviewMode = true
55
+ }
56
+ webChromeClient = WebChromeClient()
57
+ webViewClient = object : WebViewClient() {
58
+ override fun shouldOverrideUrlLoading(view: WebView, request: android.webkit.WebResourceRequest) = false
59
+ override fun onReceivedError(
60
+ view: WebView,
61
+ request: android.webkit.WebResourceRequest,
62
+ error: android.webkit.WebResourceError
63
+ ) {
64
+ Log.e("WebView", "Failed to load: ${error.description}")
65
+ }
66
+ override fun onPageFinished(view: WebView, url: String) {
67
+ Log.d("WebView", "Loaded: $url")
68
+ }
69
+ }
70
+ loadUrl("https://flomentumsolutions.com/privacy-policy")
71
+ }
72
+
73
+ setContentView(webView)
74
+
75
+ // Device back button behavior
76
+ onBackPressedDispatcher.addCallback(this) {
77
+ finish()
78
+ }
79
+ }
80
+
81
+ // Toolbar Up button behavior
82
+ override fun onSupportNavigateUp(): Boolean {
83
+ finish()
84
+ return true
85
+ }
86
+ }
File without changes
@@ -0,0 +1,110 @@
1
+ export interface HealthPlugin {
2
+ /**
3
+ * Checks if health API is available.
4
+ * Android: If false is returned, the Google Health Connect app is probably not installed.
5
+ * See showHealthConnectInPlayStore()
6
+ *
7
+ */
8
+ isHealthAvailable(): Promise<{
9
+ available: boolean;
10
+ }>;
11
+ /**
12
+ * Android only: Returns for each given permission, if it was granted by the underlying health API
13
+ * @param permissions permissions to query
14
+ */
15
+ checkHealthPermissions(permissions: PermissionsRequest): Promise<PermissionResponse>;
16
+ /**
17
+ * Requests the permissions from the user.
18
+ *
19
+ * Android: Apps can ask only a few times for permissions, after that the user has to grant them manually in
20
+ * the Health Connect app. See openHealthConnectSettings()
21
+ *
22
+ * iOS: If the permissions are already granted or denied, this method will just return without asking the user. In iOS
23
+ * we can't really detect if a user granted or denied a permission. The return value reflects the assumption that all
24
+ * permissions were granted.
25
+ *
26
+ * @param permissions permissions to request
27
+ */
28
+ requestHealthPermissions(permissions: PermissionsRequest): Promise<PermissionResponse>;
29
+ /**
30
+ * Opens the apps settings, which is kind of wrong, because health permissions are configured under:
31
+ * Settings > Apps > (Apple) Health > Access and Devices > [app-name]
32
+ * But we can't go there directly.
33
+ */
34
+ openAppleHealthSettings(): Promise<void>;
35
+ /**
36
+ * Opens the Google Health Connect app
37
+ */
38
+ openHealthConnectSettings(): Promise<void>;
39
+ /**
40
+ * Opens the Google Health Connect app in PlayStore
41
+ */
42
+ showHealthConnectInPlayStore(): Promise<void>;
43
+ /**
44
+ * Query aggregated data
45
+ * @param request
46
+ */
47
+ queryAggregated(request: QueryAggregatedRequest): Promise<QueryAggregatedResponse>;
48
+ /**
49
+ * Query workouts
50
+ * @param request
51
+ */
52
+ queryWorkouts(request: QueryWorkoutRequest): Promise<QueryWorkoutResponse>;
53
+ }
54
+ export declare type HealthPermission = 'READ_STEPS' | 'READ_WORKOUTS' | 'READ_ACTIVE_CALORIES' | 'READ_TOTAL_CALORIES' | 'READ_DISTANCE' | 'READ_HEART_RATE' | 'READ_ROUTE' | 'READ_MINDFULNESS';
55
+ export interface PermissionsRequest {
56
+ permissions: HealthPermission[];
57
+ }
58
+ export interface PermissionResponse {
59
+ permissions: {
60
+ [key: string]: boolean;
61
+ }[];
62
+ }
63
+ export interface QueryWorkoutRequest {
64
+ startDate: string;
65
+ endDate: string;
66
+ includeHeartRate: boolean;
67
+ includeRoute: boolean;
68
+ includeSteps: boolean;
69
+ }
70
+ export interface HeartRateSample {
71
+ timestamp: string;
72
+ bpm: number;
73
+ }
74
+ export interface RouteSample {
75
+ timestamp: string;
76
+ lat: number;
77
+ lng: number;
78
+ alt?: number;
79
+ }
80
+ export interface QueryWorkoutResponse {
81
+ workouts: Workout[];
82
+ }
83
+ export interface Workout {
84
+ startDate: string;
85
+ endDate: string;
86
+ workoutType: string;
87
+ sourceName: string;
88
+ id?: string;
89
+ duration: number;
90
+ distance?: number;
91
+ steps?: number;
92
+ calories: number;
93
+ sourceBundleId: string;
94
+ route?: RouteSample[];
95
+ heartRate?: HeartRateSample[];
96
+ }
97
+ export interface QueryAggregatedRequest {
98
+ startDate: string;
99
+ endDate: string;
100
+ dataType: 'steps' | 'active-calories' | 'mindfulness';
101
+ bucket: string;
102
+ }
103
+ export interface QueryAggregatedResponse {
104
+ aggregatedData: AggregatedSample[];
105
+ }
106
+ export interface AggregatedSample {
107
+ startDate: string;
108
+ endDate: string;
109
+ value: number;
110
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface HealthPlugin {\n /**\n * Checks if health API is available.\n * Android: If false is returned, the Google Health Connect app is probably not installed.\n * See showHealthConnectInPlayStore()\n *\n */\n isHealthAvailable(): Promise<{ available: boolean }>;\n\n /**\n * Android only: Returns for each given permission, if it was granted by the underlying health API\n * @param permissions permissions to query\n */\n checkHealthPermissions(permissions: PermissionsRequest): Promise<PermissionResponse>;\n\n /**\n * Requests the permissions from the user.\n *\n * Android: Apps can ask only a few times for permissions, after that the user has to grant them manually in\n * the Health Connect app. See openHealthConnectSettings()\n *\n * iOS: If the permissions are already granted or denied, this method will just return without asking the user. In iOS\n * we can't really detect if a user granted or denied a permission. The return value reflects the assumption that all\n * permissions were granted.\n *\n * @param permissions permissions to request\n */\n requestHealthPermissions(permissions: PermissionsRequest): Promise<PermissionResponse>;\n\n /**\n * Opens the apps settings, which is kind of wrong, because health permissions are configured under:\n * Settings > Apps > (Apple) Health > Access and Devices > [app-name]\n * But we can't go there directly.\n */\n openAppleHealthSettings(): Promise<void>;\n\n /**\n * Opens the Google Health Connect app\n */\n openHealthConnectSettings(): Promise<void>;\n\n /**\n * Opens the Google Health Connect app in PlayStore\n */\n showHealthConnectInPlayStore(): Promise<void>;\n\n /**\n * Query aggregated data\n * @param request\n */\n queryAggregated(request: QueryAggregatedRequest): Promise<QueryAggregatedResponse>;\n\n /**\n * Query workouts\n * @param request\n */\n queryWorkouts(request: QueryWorkoutRequest): Promise<QueryWorkoutResponse>;\n}\n\nexport declare type HealthPermission =\n | 'READ_STEPS'\n | 'READ_WORKOUTS'\n | 'READ_ACTIVE_CALORIES'\n | 'READ_TOTAL_CALORIES'\n | 'READ_DISTANCE'\n | 'READ_HEART_RATE'\n | 'READ_ROUTE'\n | 'READ_MINDFULNESS';\n\nexport interface PermissionsRequest {\n permissions: HealthPermission[];\n}\n\nexport interface PermissionResponse {\n permissions: { [key: string]: boolean }[];\n}\n\nexport interface QueryWorkoutRequest {\n startDate: string;\n endDate: string;\n includeHeartRate: boolean;\n includeRoute: boolean;\n includeSteps: boolean;\n}\n\nexport interface HeartRateSample {\n timestamp: string;\n bpm: number;\n}\n\nexport interface RouteSample {\n timestamp: string;\n lat: number;\n lng: number;\n alt?: number;\n}\n\nexport interface QueryWorkoutResponse {\n workouts: Workout[];\n}\n\nexport interface Workout {\n startDate: string;\n endDate: string;\n workoutType: string;\n sourceName: string;\n id?: string;\n duration: number;\n distance?: number;\n steps?: number;\n calories: number;\n sourceBundleId: string;\n route?: RouteSample[];\n heartRate?: HeartRateSample[];\n}\n\nexport interface QueryAggregatedRequest {\n startDate: string;\n endDate: string;\n dataType: 'steps' | 'active-calories' | 'mindfulness';\n bucket: string;\n}\n\nexport interface QueryAggregatedResponse {\n aggregatedData: AggregatedSample[];\n}\n\nexport interface AggregatedSample {\n startDate: string;\n endDate: string;\n value: number;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { HealthPlugin } from './definitions';
2
+ export declare const Health: HealthPlugin;
3
+ export * from './definitions';
@@ -0,0 +1,4 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ export const Health = registerPlugin('HealthPlugin', {});
3
+ export * from './definitions';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,CAAC,MAAM,MAAM,GAAG,cAAc,CAAe,cAAc,EAAE,EAAE,CAAC,CAAC;AAEvE,cAAc,eAAe,CAAA","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { HealthPlugin } from './definitions';\n\nexport const Health = registerPlugin<HealthPlugin>('HealthPlugin', {});\n\nexport * from './definitions'\n"]}
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var core = require('@capacitor/core');
6
+
7
+ const Health = core.registerPlugin('HealthPlugin', {});
8
+
9
+ exports.Health = Health;
10
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nexport const Health = registerPlugin('HealthPlugin', {});\nexport * from './definitions';\n//# sourceMappingURL=index.js.map"],"names":["registerPlugin"],"mappings":";;;;;;AACY,MAAC,MAAM,GAAGA,mBAAc,CAAC,cAAc,EAAE,EAAE;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,13 @@
1
+ var capacitorHealthPlugin = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const Health = core.registerPlugin('HealthPlugin', {});
5
+
6
+ exports.Health = Health;
7
+
8
+ Object.defineProperty(exports, '__esModule', { value: true });
9
+
10
+ return exports;
11
+
12
+ })({}, capacitorExports);
13
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nexport const Health = registerPlugin('HealthPlugin', {});\nexport * from './definitions';\n//# sourceMappingURL=index.js.map"],"names":["registerPlugin"],"mappings":";;;AACY,OAAC,MAAM,GAAGA,mBAAc,CAAC,cAAc,EAAE,EAAE;;;;;;;;;;;;"}