diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3a16afd3..67a4974c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,62 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
The changes documented here do not include those from the original repository.
+## [2.0.0]
+
+### 2024-04-05
+- Fix privacy policy opening for Android <= 13 (https://outsystemsrd.atlassian.net/browse/RMET-3134).
+
+### 2024-04-04
+- Update the iOS framework. This adds the Privacy Manifest file (https://outsystemsrd.atlassian.net/browse/RMET-3280).
+- Update GSON version to remove vulnerability (https://outsystemsrd.atlassian.net/browse/RMET-3134).
+
+### 2024-04-01
+- Remove old code and re-arrange file structure (https://outsystemsrd.atlassian.net/browse/RMET-3134).
+
+### 2024-03-22
+- Fixed hook for ODC (https://outsystemsrd.atlassian.net/browse/RMET-3191).
+
+### 2024-03-18
+- Implemented the usage of the Activity Transition Recognition API for background jobs (https://outsystemsrd.atlassian.net/browse/RMET-3246).
+
+### 2024-03-14
+- Implemented the usage of exact alarms for background jobs (https://outsystemsrd.atlassian.net/browse/RMET-3190).
+
+### 2024-02-28
+- Implemented `Open Health Connect App` (https://outsystemsrd.atlassian.net/browse/RMET-3158).
+
+### 2024-02-27
+- Implemented hook for permissions (https://outsystemsrd.atlassian.net/browse/RMET-3142).
+
+### 2024-02-26
+- Implemented `Show app's privacy policy dialog` (https://outsystemsrd.atlassian.net/browse/RMET-3145).
+
+### 2024-02-23
+- Re-implement `DeleteBackgroundJob` feature (https://outsystemsrd.atlassian.net/browse/RMET-3068).
+
+### 2024-02-20
+- Deprecated `DisableGoogleFit` feature and implemented `DisableHealthConnect` feature (https://outsystemsrd.atlassian.net/browse/RMET-3070).
+- Re-implemented UpdateBackgroundJob feature (https://outsystemsrd.atlassian.net/browse/RMET-3067).
+- Re-implemented SetBackgroundJob feature (https://outsystemsrd.atlassian.net/browse/RMET-3050).
+
+### 2024-02-09
+- Re-implemented AdvanceQuery feature (https://outsystemsrd.atlassian.net/browse/RMET-3047).
+
+### 2024-02-09
+- Re-implemented ListBackgroundJobs feature (https://outsystemsrd.atlassian.net/browse/RMET-3069).
+
+### 2024-02-08
+- Re-implement `GetLastRecord` feature:
+ - GetFitnessData (https://outsystemsrd.atlassian.net/browse/RMET-3048)
+ - GetHealthData (https://outsystemsrd.atlassian.net/browse/RMET-3065)
+ - GetProfileData (https://outsystemsrd.atlassian.net/browse/RMET-3066)
+
+### 2024-02-05
+- Re-implemented WriteProfieleData feature (https://outsystemsrd.atlassian.net/browse/RMET-3049).
+
+### 2024-02-01
+- Re-implemented RequestPermissions feature (https://outsystemsrd.atlassian.net/browse/RMET-3046).
+
## [Version 1.4.0]
## 2023-08-25
@@ -18,6 +74,8 @@ The changes documented here do not include those from the original repository.
### 16-12-2022
- Replaced jcenter with more up to date mavenCentral [RMET-2036](https://outsystemsrd.atlassian.net/browse/RMET-2036)
+## [Version 1.3.0]
+- Feat: [iOS] Add a method to retrieve workouts raw data from HealthKit (https://outsystemsrd.atlassian.net/browse/RMET-2128).
## [Version 1.2.11]
- Fix: [iOS] Replace the old `OSCore` framework for the new `OSCommonPluginLib` pod.
diff --git a/hooks/androidCopyPreferencesPermissions.js b/hooks/androidCopyPreferencesPermissions.js
new file mode 100644
index 00000000..c272ee9b
--- /dev/null
+++ b/hooks/androidCopyPreferencesPermissions.js
@@ -0,0 +1,341 @@
+const fs = require('fs');
+const path = require('path');
+const { ConfigParser } = require('cordova-common');
+const { DOMParser, XMLSerializer } = require('xmldom');
+
+const READ = "Read"
+const WRITE = "Write"
+const READWRITE = "ReadWrite"
+
+let permissions = {
+ HeartRate: {
+ variableName: "HeartRate",
+ readPermission: "android.permission.health.READ_HEART_RATE",
+ writePermission: "android.permission.health.WRITE_HEART_RATE",
+ configValue: undefined,
+ // we'll use these to know if we should write group permissions or not
+ wasSet: false
+ },
+ Steps: {
+ variableName: "Steps",
+ readPermission: "android.permission.health.READ_STEPS",
+ writePermission: "android.permission.health.WRITE_STEPS",
+ configValue: undefined,
+ wasSet: false
+ },
+ Weight: {
+ variableName: "Weight",
+ readPermission: "android.permission.health.READ_WEIGHT",
+ writePermission: "android.permission.health.WRITE_WEIGHT",
+ configValue: undefined,
+ wasSet: false
+ },
+ Height: {
+ variableName: "Height",
+ readPermission: "android.permission.health.READ_HEIGHT",
+ writePermission: "android.permission.health.WRITE_HEIGHT",
+ configValue: undefined,
+ wasSet: false
+ },
+ CaloriesBurned: {
+ variableName: "CaloriesBurned",
+ readPermission: "android.permission.health.READ_TOTAL_CALORIES_BURNED",
+ writePermission: "android.permission.health.WRITE_TOTAL_CALORIES_BURNED",
+ configValue: undefined,
+ wasSet: false
+ },
+ Sleep: {
+ variableName: "Sleep",
+ readPermission: "android.permission.health.READ_SLEEP",
+ writePermission: "android.permission.health.WRITE_SLEEP",
+ configValue: undefined,
+ wasSet: false
+ },
+ BloodPressure: {
+ variableName: "BloodPressure",
+ readPermission: "android.permission.health.READ_BLOOD_PRESSURE",
+ writePermission: "android.permission.health.WRITE_BLOOD_PRESSURE",
+ configValue: undefined,
+ wasSet: false
+ },
+ BloodGlucose: {
+ variableName: "BloodGlucose",
+ readPermission: "android.permission.health.READ_BLOOD_GLUCOSE",
+ writePermission: "android.permission.health.WRITE_BLOOD_GLUCOSE",
+ configValue: undefined,
+ wasSet: false
+ },
+ BodyFatPercentage: {
+ variableName: "BodyFatPercentage",
+ readPermission: "android.permission.health.READ_BODY_FAT",
+ writePermission: "android.permission.health.WRITE_BODY_FAT",
+ configValue: undefined,
+ wasSet: false
+ },
+ BasalMetabolicRate: {
+ variableName: "BasalMetabolicRate",
+ readPermission: "android.permission.health.READ_BASAL_METABOLIC_RATE",
+ writePermission: "android.permission.health.WRITE_BASAL_METABOLIC_RATE",
+ configValue: undefined,
+ wasSet: false
+ },
+ WalkingSpeed: {
+ variableName: "WalkingSpeed",
+ readPermission: "android.permission.health.READ_SPEED",
+ writePermission: "android.permission.health.WRITE_SPEED",
+ configValue: undefined,
+ wasSet: false
+ },
+ Distance: {
+ variableName: "Distance",
+ readPermission: "android.permission.health.READ_DISTANCE",
+ writePermission: "android.permission.health.WRITE_DISTANCE",
+ configValue: undefined,
+ wasSet: false
+ }
+}
+
+let groupPermissions = {
+ AllVariables: {
+ variableName: "AllVariables",
+ configValue: undefined,
+ wasSet: false,
+ groupVariables: []
+ },
+ FitnessVariables: {
+ variableName: "FitnessVariables",
+ configValue: undefined,
+ // we'll use these to know if we should set individual permissions or not
+ // e.g. when checking HeartRate, if all healthVariables were already set, we don't need to add it again
+ wasSet: false,
+ groupVariables: ["Steps", "CaloriesBurned", "WalkingSpeed", "Distance"]
+ },
+ HealthVariables: {
+ variableName: "HealthVariables",
+ configValue: undefined,
+ wasSet: false,
+ groupVariables: ["HeartRate", "Sleep", "BloodPressure", "BloodGlucose"]
+ },
+ ProfileVariables: {
+ variableName: "ProfileVariables",
+ configValue: undefined,
+ wasSet: false,
+ groupVariables: ["Weight", "Height", "BodyFatPercentage", "BasalMetabolicRate"]
+ }
+}
+
+module.exports = async function (context) {
+ const projectRoot = context.opts.cordova.project ? context.opts.cordova.project.root : context.opts.projectRoot;
+ const configXML = path.join(projectRoot, 'config.xml');
+ const configParser = new ConfigParser(configXML);
+ const parser = new DOMParser();
+
+ // add health connect permissions to AndroidManifest.xml and health_permissions.xml files
+ addHealthConnectPermissionsToXmlFiles(configParser, projectRoot, parser);
+
+ // add background job permissions to AndroidManifest.xml
+ addBackgroundJobPermissionsToManifest(configParser, projectRoot, parser);
+
+ // copy notification title and content for notificaiton for Foreground Service
+ copyNotificationContent(configParser, projectRoot, parser);
+};
+
+function addHealthConnectPermissionsToXmlFiles(configParser, projectRoot, parser) {
+
+ for(const key in permissions){
+ permissions[key].configValue = configParser.getPlatformPreference(permissions[key].variableName, 'android');
+ }
+
+ for(const key in groupPermissions){
+ groupPermissions[key].configValue = configParser.getPlatformPreference(groupPermissions[key].variableName, 'android');
+ }
+
+ // Android >= 14 dependencies should be included directly in the AndroidManifest.xml file
+ // Read the AndroidManifest.xml file
+ const manifestFilePath = path.join(projectRoot, 'platforms/android/app/src/main/AndroidManifest.xml');
+ const manifestXmlString = fs.readFileSync(manifestFilePath, 'utf-8');
+
+ // Parse the XML string
+ const manifestXmlDoc = parser.parseFromString(manifestXmlString, 'text/xml');
+
+ // Android <= 13 dependencies should be included in a separate XML file
+ // Create the health_permissions.xml file
+ const permissionsXmlDoc = parser.parseFromString('', 'text/xml');
+
+ // Get the element
+ const arrayElement = permissionsXmlDoc.getElementsByTagName('array')[0];
+
+ // process each individual variable
+ for(const key in permissions){
+ let p = permissions[key]
+ if (p.configValue == READWRITE || p.configValue == READ) {
+ p.wasSet = true;
+ processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, p.readPermission)
+ }
+ if (p.configValue == READWRITE || p.configValue == WRITE) {
+ p.wasSet = true;
+ processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, p.writePermission)
+ }
+ }
+
+ // process group variables
+ for(const key in groupPermissions){
+ let p = groupPermissions[key]
+ if (p.configValue == READWRITE || p.configValue == READ) {
+ p.wasSet = true;
+ p.groupVariables.forEach( v => {
+ if (!permissions[v].wasSet) {
+ processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, permissions[v].readPermission)
+ }
+ })
+ }
+ if (p.configValue == READWRITE || p.configValue == WRITE) {
+ p.wasSet = true;
+ p.groupVariables.forEach( v => {
+ if (!permissions[v].wasSet) {
+ processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, permissions[v].writePermission)
+ }
+ })
+ }
+ }
+
+ let permissionValues = Object.values(permissions)
+ let groupPermissionValues = Object.values(groupPermissions)
+
+ // process AllVariables
+ if (groupPermissions.AllVariables.configValue == READWRITE || groupPermissions.AllVariables.configValue == READ) {
+ processAllVariables(manifestXmlDoc, permissionsXmlDoc, arrayElement, READ, groupPermissionValues)
+
+ }
+
+ if ((groupPermissions.AllVariables.configValue == READWRITE || groupPermissions.AllVariables.configValue == WRITE)) {
+ processAllVariables(manifestXmlDoc, permissionsXmlDoc, arrayElement, WRITE, groupPermissionValues)
+ }
+
+ let numberOfPermissions = permissionValues.filter(p => p.configValue != "").length + groupPermissionValues.filter(p => p.configValue != "").length
+
+ // if there is no AllVariables nor anything else, then by default we add all the permissions
+ if (numberOfPermissions == 0) {
+ permissionValues.forEach( p => {
+ processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, p.readPermission)
+ processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, p.writePermission)
+ })
+ }
+
+ // Serialize the updated XML document back to string
+ const serializer = new XMLSerializer();
+
+ // Android >= 14
+ const updatedManifestXmlString = serializer.serializeToString(manifestXmlDoc);
+
+ // Write the updated XML string back to the same file
+ fs.writeFileSync(manifestFilePath, updatedManifestXmlString, 'utf-8');
+
+ // Android <= 13
+ const updatedPermissionsXmlString = serializer.serializeToString(permissionsXmlDoc);
+ const permissionsXmlFilePath = path.join(projectRoot, 'platforms/android/app/src/main/res/values/health_permissions.xml');
+
+ // Write the updated XML string back to the same file
+ fs.writeFileSync(permissionsXmlFilePath, updatedPermissionsXmlString, 'utf-8');
+
+}
+
+function processAllVariables(manifestXmlDoc, permissionsXmlDoc, arrayElement, permissionOperation, groupPermissionsValues) {
+ groupPermissionsValues.forEach(p => {
+ p.groupVariables.forEach( v => {
+ if (!p.wasSet && !permissions[v].wasSet) {
+ processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, permissionOperation == READ ? permissions[v].readPermission : permissions[v].writePermission)
+ }
+ })
+ })
+}
+
+function processPermission(manifestXmlDoc, permissionsXmlDoc, arrayElement, permissionOperation) {
+ addEntryToManifest(manifestXmlDoc, permissionOperation)
+ addEntryToPermissionsXML(permissionsXmlDoc, arrayElement, permissionOperation)
+}
+
+function addBackgroundJobPermissionsToManifest(configParser, projectRoot, parser) {
+
+ const disableBackgroundJobs = configParser.getPlatformPreference('DisableBackgroundJobs', 'android');
+
+ // we want to include the permissions by default
+ // if disableBackgroundJobs == true then we don't want to include the permissions in the manfiest
+ if (disableBackgroundJobs !== "true") {
+
+ const manifestFilePath = path.join(projectRoot, 'platforms/android/app/src/main/AndroidManifest.xml');
+ const manifestXmlString = fs.readFileSync(manifestFilePath, 'utf-8');
+
+ // Parse the XML string
+ const manifestXmlDoc = parser.parseFromString(manifestXmlString, 'text/xml');
+
+ // add permissions to XML document
+ addEntryToManifest(manifestXmlDoc, 'android.permission.POST_NOTIFICATIONS')
+ addEntryToManifest(manifestXmlDoc, 'android.permission.ACTIVITY_RECOGNITION')
+ addEntryToManifest(manifestXmlDoc, 'com.google.android.gms.permission.ACTIVITY_RECOGNITION') // necessary for API 28 and below
+ addEntryToManifest(manifestXmlDoc, 'android.permission.FOREGROUND_SERVICE')
+ addEntryToManifest(manifestXmlDoc, 'android.permission.FOREGROUND_SERVICE_HEALTH')
+ addEntryToManifest(manifestXmlDoc, 'android.permission.HIGH_SAMPLING_RATE_SENSORS')
+ addEntryToManifest(manifestXmlDoc, 'android.permission.SCHEDULE_EXACT_ALARM')
+
+ // serialize the updated XML document back to string
+ const serializer = new XMLSerializer();
+ const updatedManifestXmlString = serializer.serializeToString(manifestXmlDoc);
+
+ // write the updated XML string back to the same file
+ fs.writeFileSync(manifestFilePath, updatedManifestXmlString, 'utf-8');
+ }
+
+}
+
+function addEntryToManifest(manifestXmlDoc, permission) {
+ const newPermission = manifestXmlDoc.createElement('uses-permission');
+ newPermission.setAttribute('android:name', permission);
+ manifestXmlDoc.documentElement.appendChild(newPermission);
+}
+
+function addEntryToPermissionsXML(permissionsXmlDoc, arrayElement, permission) {
+ const newItem = permissionsXmlDoc.createElement('item');
+ const textNode = permissionsXmlDoc.createTextNode(permission);
+ newItem.appendChild(textNode);
+ arrayElement.appendChild(newItem);
+}
+
+function copyNotificationContent(configParser, projectRoot, parser) {
+
+ // get values from config.xml
+ var notificationTitle = configParser.getPlatformPreference('BackgroundNotificationTitle', 'android');
+ var notificationDescription = configParser.getPlatformPreference('BackgroundNotificationDescription', 'android');
+
+ if (notificationTitle == "") {
+ notificationTitle = "Measuring your health and fitness data."
+ }
+
+ if (notificationDescription == "") {
+ notificationDescription = "The app is running in the background."
+ }
+
+ // insert values in strings.xml
+ const stringsXmlPath = path.join(projectRoot, 'platforms/android/app/src/main/res/values/strings.xml');
+ const stringsXmlString = fs.readFileSync(stringsXmlPath, 'utf-8');
+ const stringsXmlDoc = parser.parseFromString(stringsXmlString, 'text/xml')
+ const stringElements = stringsXmlDoc.getElementsByTagName('string');
+
+ // set text for each element
+ for (let i = 0; i < stringElements.length; i++) {
+ const name = stringElements[i].getAttribute('name');
+ if (name == "background_notification_title") {
+ stringElements[i].textContent = notificationTitle;
+ }
+ else if (name == "background_notification_description") {
+ stringElements[i].textContent = notificationDescription;
+ }
+ }
+
+ // serialize the updated XML document back to string
+ const serializer = new XMLSerializer();
+ const updatedXmlString = serializer.serializeToString(stringsXmlDoc);
+
+ // write the updated XML string back to the same file
+ fs.writeFileSync(stringsXmlPath, updatedXmlString, 'utf-8');
+}
diff --git a/hooks/androidCopyPrivacyUrlEnv.js b/hooks/androidCopyPrivacyUrlEnv.js
new file mode 100644
index 00000000..ec290c29
--- /dev/null
+++ b/hooks/androidCopyPrivacyUrlEnv.js
@@ -0,0 +1,60 @@
+"use strict";
+
+const fs = require('fs');
+const path = require('path');
+const { ConfigParser } = require('cordova-common');
+const et = require('elementtree');
+const { fileExists } = require('./utils');
+let fileNamePrivacyPolicy = "HealthConnect_PrivacyPolicy.txt";
+
+module.exports = async function (context) {
+ const projectRoot = context.opts.cordova.project ? context.opts.cordova.project.root : context.opts.projectRoot;
+ const platformPath = path.join(projectRoot, `platforms/android/app/src/main/assets/www/${fileNamePrivacyPolicy}`);
+
+ if (fileExists(platformPath) || policyFileExists()) {
+ const configXML = path.join(projectRoot, 'config.xml');
+ const configParser = new ConfigParser(configXML);
+
+ setPrivacyPolicyUrl(configParser, projectRoot);
+ } else {
+ throw new Error("Privacy Policy file not found in the resources folder.");
+ }
+};
+
+function setPrivacyPolicyUrl(configParser, projectRoot) {
+ const hostname = configParser.getPreference('hostname', 'android');
+ const applicationNameUrl = configParser.getPreference('DefaultApplicationURL', 'android');
+
+ if (hostname && applicationNameUrl) {
+ const url = `https://${hostname}/${applicationNameUrl}/${fileNamePrivacyPolicy}`;
+ const stringsPath = path.join(projectRoot, 'platforms/android/app/src/main/res/values/strings.xml');
+ const stringsFile = fs.readFileSync(stringsPath).toString();
+ const etreeStrings = et.parse(stringsFile);
+
+ let privacyPolicyUrl = etreeStrings.find('./string[@name="privacy_policy_url"]');
+ if (!privacyPolicyUrl) {
+ console.error('Privacy policy URL string not found in strings.xml');
+ return;
+ }
+ privacyPolicyUrl.text = url;
+ const resultXmlStrings = etreeStrings.write({method: 'xml'});
+ fs.writeFileSync(stringsPath, resultXmlStrings);
+ } else {
+ throw new Error("Error getting the environment variables.");
+ }
+}
+
+function policyFileExists() {
+ const directoryPath = 'platforms/android/app/src/main/assets/www';
+ const searchString = 'HealthConnect_PrivacyPolicy';
+ try {
+ const files = fs.readdirSync(directoryPath);
+ const matchingFiles = files.filter(fileName => fileName.includes(searchString));
+
+ // return true if there are matching files, false otherwise
+ return matchingFiles.length > 0;
+ } catch (error) {
+ console.error('An error occurred:', error);
+ return false;
+ }
+}
diff --git a/hooks/utils.js b/hooks/utils.js
new file mode 100644
index 00000000..1b92dea1
--- /dev/null
+++ b/hooks/utils.js
@@ -0,0 +1,11 @@
+"use strict"
+
+var fs = require("fs");
+
+function fileExists(filePath) {
+ return fs.existsSync(filePath);
+}
+
+module.exports = {
+ fileExists
+};
diff --git a/package.json b/package.json
index ee9bb79f..96f20b20 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "com.outsystems.plugins.healthfitness",
- "version": "1.4.0",
+ "version": "2.0.0",
"description": "Health & Fitness cordova plugin for OutSystems applications.",
"keywords": [
"ecosystem:cordova",
@@ -14,5 +14,8 @@
"ios"
]
},
- "engines": []
+ "engines": [],
+ "dependencies": {
+ "xmldom": "^0.6.0"
+ }
}
diff --git a/plugin.xml b/plugin.xml
index cfc36e3e..465b88ef 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -1,5 +1,5 @@
-
+
HealthFitness
Health & Fitness cordova plugin for OutSystems applications.
OutSystems Inc
@@ -8,6 +8,9 @@
+
+
+
@@ -18,12 +21,11 @@
-
-
-
-
-
-
+
+ PRIVACY_POLICY_URL
+
+
+
diff --git a/src/android/build.gradle b/src/android/build.gradle
index d3f5ff46..6b2f368a 100644
--- a/src/android/build.gradle
+++ b/src/android/build.gradle
@@ -17,16 +17,30 @@ allprojects {
}
dependencies{
- implementation("com.google.android.gms:play-services-fitness:20.0.0")
implementation("com.google.android.gms:play-services-auth:19.2.0")
- implementation("com.google.code.gson:gson:2.8.8")
+ implementation("com.google.android.gms:play-services-location:19.0.1")
+ implementation("com.google.code.gson:gson:2.8.9")
implementation 'com.google.code.findbugs:jsr305:1.3.9'
implementation("com.github.outsystems:oscore-android:1.2.0@aar")
- implementation("com.github.outsystems:oscordova-android:1.2.0@aar")
- implementation("com.github.outsystems:oshealthfitness-android:1.2.0@aar")
+ implementation("com.github.outsystems:oscordova-android:2.0.1@aar")
+ implementation("com.github.outsystems:oshealthfitness-android:2.0.0@aar")
implementation("com.github.outsystems:osnotificationpermissions-android:0.0.4@aar")
+
+ // activity
+ implementation "androidx.activity:activity-ktx:1.8.2"
+
+ // appcompact
+ implementation "androidx.appcompat:appcompat:1.6.1"
+
+ // health connect sdk
+ implementation "androidx.health.connect:connect-client:1.1.0-alpha07"
+
+ // compose
+ implementation 'androidx.activity:activity-compose:1.8.2'
+ implementation 'androidx.compose.material3:material3:1.2.0'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0'
def roomVersion = "2.4.2"
implementation("androidx.room:room-runtime:$roomVersion")
diff --git a/src/android/com/outsystems/plugins/healthfitness/OSHealthFitness.kt b/src/android/com/outsystems/plugins/healthfitness/OSHealthFitness.kt
index e2b11d66..9d787f0a 100755
--- a/src/android/com/outsystems/plugins/healthfitness/OSHealthFitness.kt
+++ b/src/android/com/outsystems/plugins/healthfitness/OSHealthFitness.kt
@@ -1,10 +1,12 @@
package com.outsystems.plugins.healthfitness
import android.Manifest
+import android.app.AlarmManager
+import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.os.Build
import android.os.Build.VERSION.SDK_INT
+import android.provider.Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
import androidx.core.content.ContextCompat
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
@@ -13,23 +15,77 @@ import com.outsystems.osnotificationpermissions.*
import com.outsystems.plugins.healthfitness.background.BackgroundJobParameters
import com.outsystems.plugins.healthfitness.background.DatabaseManager
import com.outsystems.plugins.healthfitness.background.UpdateBackgroundJobParameters
+import com.outsystems.plugins.healthfitness.data.Constants
+import com.outsystems.plugins.healthfitness.data.HealthFitnessError
+import com.outsystems.plugins.healthfitness.data.HealthRecord
+import com.outsystems.plugins.healthfitness.data.types.HealthAdvancedQueryParameters
+import com.outsystems.plugins.healthfitness.data.types.HealthFitnessGroupPermission
+import com.outsystems.plugins.healthfitness.data.types.HealthFitnessPermission
+import com.outsystems.plugins.healthfitness.helpers.ActivityTransitionHelper
+import com.outsystems.plugins.healthfitness.helpers.AlarmManagerHelper
+import com.outsystems.plugins.healthfitness.helpers.HealthConnectHelper
+import com.outsystems.plugins.healthfitness.repository.HealthConnectRepository
import com.outsystems.plugins.healthfitness.store.*
+import com.outsystems.plugins.healthfitness.viewmodel.HealthConnectDataManager
+import com.outsystems.plugins.healthfitness.viewmodel.HealthConnectViewModel
import com.outsystems.plugins.oscordova.CordovaImplementation
import org.apache.cordova.*
import org.json.JSONArray
+import org.json.JSONException
class OSHealthFitness : CordovaImplementation() {
override var callbackContext: CallbackContext? = null
- var healthStore: HealthStoreInterface? = null
val gson by lazy { Gson() }
- var notificationPermissions = OSNotificationPermissions()
+ private lateinit var healthConnectViewModel: HealthConnectViewModel
+ private lateinit var healthConnectRepository: HealthConnectRepository
+ private lateinit var healthConnectDataManager: HealthConnectDataManager
+ private lateinit var healthConnectHelper: HealthConnectHelper
+ private lateinit var alarmManagerHelper: AlarmManagerHelper
+ private lateinit var activityTransitionHelper: ActivityTransitionHelper
+ private lateinit var backgroundParameters: BackgroundJobParameters
+
+ private lateinit var alarmManager: AlarmManager
+
+ // we need this variable because onResume is being called when
+ // returning from the SCHEDULE_EXACT_ALARM permission screen
+ private var requestingExactAlarmPermission = false
+
+ // variables to hold foreground notification title and description
+ // these values are defined in build time so we only need to read
+ // them once on the initialize method
+ private lateinit var foregroundNotificationTitle: String
+ private lateinit var foregroundNotificationDescription: String
override fun initialize(cordova: CordovaInterface, webView: CordovaWebView) {
super.initialize(cordova, webView)
- val manager = HealthFitnessManager(cordova.context, cordova.activity)
val database = DatabaseManager(cordova.context)
- healthStore = HealthStore(cordova.context.applicationContext.packageName, manager, database)
+
+ healthConnectDataManager = HealthConnectDataManager(database)
+ healthConnectRepository = HealthConnectRepository(healthConnectDataManager)
+ healthConnectHelper = HealthConnectHelper()
+ alarmManagerHelper = AlarmManagerHelper()
+ activityTransitionHelper = ActivityTransitionHelper()
+ healthConnectViewModel =
+ HealthConnectViewModel(healthConnectRepository, healthConnectHelper, alarmManagerHelper, activityTransitionHelper)
+ alarmManager = getContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager
+
+ // get foreground notification title and description from resources (strings.xml)
+ foregroundNotificationTitle = getContext().resources.getString(
+ getActivity().resources.getIdentifier(
+ "background_notification_title",
+ "string",
+ getActivity().packageName
+ )
+ )
+ foregroundNotificationDescription = getContext().resources.getString(
+ getActivity().resources.getIdentifier(
+ "background_notification_description",
+ "string",
+ getActivity().packageName
+ )
+ )
+
}
override fun execute(
@@ -37,10 +93,11 @@ class OSHealthFitness : CordovaImplementation() {
args: JSONArray,
callbackContext: CallbackContext
): Boolean {
+
this.callbackContext = callbackContext
- if(!areGooglePlayServicesAvailable()) {
- return false;
+ if (!areGooglePlayServicesAvailable()) {
+ return false
}
when (action) {
@@ -68,77 +125,81 @@ class OSHealthFitness : CordovaImplementation() {
"updateBackgroundJob" -> {
updateBackgroundJob(args)
}
- "disconnectFromGoogleFit" -> {
- disconnectFromGoogleFit()
+ "disconnectFromHealthConnect" -> {
+ disconnectFromHealthConnect()
+ }
+ "openHealthConnect" -> {
+ openHealthConnect()
}
}
return true
}
- //create array of permission oauth
- private fun initAndRequestPermissions(args : JSONArray) {
- val customPermissions = args.getString(0)
- val allVariables = args.getString(1)
- val fitnessVariables = args.getString(2)
- val healthVariables = args.getString(3)
- val profileVariables = args.getString(4)
- val summaryVariables = args.getString(5)
+ // onResume is called when returning from the SCHEDULE_EXACT_ALARM permission screen
+ override fun onResume(multitasking: Boolean) {
+ if (requestingExactAlarmPermission) {
+ requestingExactAlarmPermission = false
+ onScheduleExactAlarmPermissionResult()
+ }
+ }
+ private fun initAndRequestPermissions(args: JSONArray) {
try {
- healthStore?.initAndRequestPermissions(
- customPermissions,
- allVariables,
- fitnessVariables,
- healthVariables,
- profileVariables,
- summaryVariables)
- checkAndGrantPermissions()
- }
- catch (hse : HealthStoreException) {
+ healthConnectViewModel.initAndRequestPermissions(
+ getActivity(),
+ gson.fromJson(args.getString(0), Array::class.java),
+ gson.fromJson(args.getString(1), HealthFitnessGroupPermission::class.java),
+ gson.fromJson(args.getString(2), HealthFitnessGroupPermission::class.java),
+ gson.fromJson(args.getString(3), HealthFitnessGroupPermission::class.java),
+ gson.fromJson(args.getString(4), HealthFitnessGroupPermission::class.java),
+ privacyPolicyUrl = getActivity().resources.getString(getActivity().resources.getIdentifier("privacy_policy_url", "string", getActivity().packageName)),
+ {
+ setAsActivityResultCallback()
+ },
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
+ }
+ )
+ } catch (hse: HealthStoreException) {
sendPluginResult(null, Pair(hse.error.code.toString(), hse.error.message))
+ } catch (e: JSONException) {
+ sendPluginResult(
+ null,
+ Pair(
+ HealthFitnessError.PARSING_PARAMETERS_ERROR.code.toString(),
+ HealthFitnessError.PARSING_PARAMETERS_ERROR.message
+ )
+ )
+ } catch (e: Exception) {
+ sendPluginResult(
+ null,
+ Pair(
+ HealthFitnessError.REQUEST_PERMISSIONS_GENERAL_ERROR.code.toString(),
+ HealthFitnessError.REQUEST_PERMISSIONS_GENERAL_ERROR.message
+ )
+ )
}
}
+
private fun areAndroidPermissionsGranted(permissions: List): Boolean {
permissions.forEach {
- if (ContextCompat.checkSelfPermission(cordova.activity, it) != PackageManager.PERMISSION_GRANTED) {
+ if (ContextCompat.checkSelfPermission(
+ getActivity(),
+ it
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
return false
}
}
return true
}
- private fun checkAndGrantPermissions(){
- val permissions = mutableListOf(
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.BODY_SENSORS
- )
-
- if(SDK_INT >= Build.VERSION_CODES.Q) {
- permissions.add(Manifest.permission.ACTIVITY_RECOGNITION)
- }
-
- if (areAndroidPermissionsGranted(permissions)) {
- if(!healthStore!!.areGoogleFitPermissionsGranted()){
- setAsActivityResultCallback()
- }
- if(healthStore?.requestGoogleFitPermissions() == true) {
- sendPluginResult("success")
- }
- }
- else {
- PermissionHelper.requestPermissions(
- this,
- ACTIVITY_LOCATION_PERMISSIONS_REQUEST_CODE,
- permissions.toTypedArray()
- )
- }
- }
-
- private fun advancedQuery(args : JSONArray) {
- val parameters = gson.fromJson(args.getString(0), AdvancedQueryParameters::class.java)
- healthStore?.advancedQueryAsync(
+ private fun advancedQuery(args: JSONArray) {
+ val parameters = gson.fromJson(args.getString(0), HealthAdvancedQueryParameters::class.java)
+ healthConnectViewModel.advancedQuery(
parameters,
+ getContext(),
{ response ->
val pluginResponseJson = gson.toJson(response)
sendPluginResult(pluginResponseJson)
@@ -150,94 +211,161 @@ class OSHealthFitness : CordovaImplementation() {
}
private fun writeData(args: JSONArray) {
+ try {
+ val variable = args.getString(0)
+ val healthRecord = HealthRecord.valueOf(variable)
+ val value = args.getDouble(1)
- //process parameters
- val variable = args.getString(0)
- val value = args.getDouble(1).toFloat()
+ healthConnectViewModel.writeData(
+ healthRecord,
+ value,
+ getActivity().packageName,
+ {
+ sendPluginResult("success", null)
+ },
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
+ }
+ )
+ } catch (e: Exception) {
+ sendPluginResult(null, Pair(HealthFitnessError.VARIABLE_NOT_AVAILABLE_ERROR.code.toString(), HealthFitnessError.VARIABLE_NOT_AVAILABLE_ERROR.message))
+ }
+ }
- healthStore?.updateDataAsync(
- variable,
- value,
- { response ->
- sendPluginResult(response)
- },
- { error ->
- sendPluginResult(null, Pair(error.code.toString(), error.message))
+ private fun getLastRecord(args: JSONArray) {
+ try {
+ healthConnectViewModel.getLastRecord(
+ HealthRecord.valueOf(args.getString(0)),
+ {
+ sendPluginResult(it, null)
+ },
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
+ }
+ )
+ } catch (e: Exception) {
+ sendPluginResult(null, Pair(HealthFitnessError.VARIABLE_NOT_AVAILABLE_ERROR.code.toString(), HealthFitnessError.VARIABLE_NOT_AVAILABLE_ERROR.message))
+ }
+
+ }
+
+ /**
+ * Navigates to the permission screen for exact alarms or
+ * skips it and request the other necessary permissions.
+ * Also stores the background job parameters in a global variable to be used later.
+ */
+ private fun setBackgroundJob(args: JSONArray) {
+ // save arguments for later use
+ backgroundParameters = gson.fromJson(args.getString(0), BackgroundJobParameters::class.java)
+
+ //request permission for exact alarms if necessary
+ if (!Constants.ACTIVITY_VARIABLES.contains(backgroundParameters.variable) && SDK_INT >= 31 && !alarmManager.canScheduleExactAlarms()) {
+ requestingExactAlarmPermission = true
+ // we only need to request this permission if exact alarms need to be used
+ // when the variable is an activity variable (e.g. steps),
+ // we use the Activity Recognition Transition API instead of exact alarms.
+ getContext().startActivity(Intent(ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
+ } else { // we can move on to other permissions if we don't need to request exact alarm permissions
+ requestBackgroundJobPermissions()
+ }
+ }
+
+ /**
+ * Requests the POST_NOTIFICATIONS and ACTIVITY_RECOGNITION permissions.
+ */
+ private fun requestBackgroundJobPermissions() {
+ val permissions = mutableListOf().apply {
+ if (SDK_INT >= 33) {
+ add(Manifest.permission.POST_NOTIFICATIONS)
+ }
+ if (SDK_INT >= 29) {
+ add(Manifest.permission.ACTIVITY_RECOGNITION)
}
+ }.toTypedArray()
- )
+ PermissionHelper.requestPermissions(this, BACKGROUND_JOB_PERMISSIONS_REQUEST_CODE, permissions)
}
- private fun getLastRecord(args: JSONArray) {
- //process parameters
- val variable = args.getString(0)
- healthStore?.getLastRecordAsync(
- variable,
- { response ->
- val pluginResponseJson = gson.toJson(response)
- sendPluginResult(pluginResponseJson)
- },
- { error ->
- sendPluginResult(null, Pair(error.code.toString(), error.message))
- })
+ /**
+ * Handles user response to exact alarm permission request.
+ *
+ */
+ private fun onScheduleExactAlarmPermissionResult() {
+ val permissionDenied = SDK_INT >= 31 && !alarmManager.canScheduleExactAlarms()
+ if (permissionDenied) {
+ // send plugin result with error
+ sendPluginResult(
+ null,
+ Pair(
+ HealthFitnessError.BACKGROUND_JOB_EXACT_ALARM_PERMISSION_DENIED_ERROR.code.toString(),
+ HealthFitnessError.BACKGROUND_JOB_EXACT_ALARM_PERMISSION_DENIED_ERROR.message
+ )
+ )
+ return
+ }
+ requestBackgroundJobPermissions()
}
- private fun setBackgroundJob(args: JSONArray) {
- notificationPermissions.requestNotificationPermission(this, ACTIVITY_NOTIFICATION_PERMISSIONS_REQUEST_CODE)
-
- //process parameters
- val parameters = gson.fromJson(args.getString(0), BackgroundJobParameters::class.java)
- healthStore?.setBackgroundJob(
+ /**
+ * Sets a background job by calling the setBackgroundJob method of the ViewModel
+ */
+ private fun setBackgroundJobWithParameters(parameters: BackgroundJobParameters) {
+ healthConnectViewModel.setBackgroundJob(
parameters,
- { response ->
- sendPluginResult(response)
+ foregroundNotificationTitle,
+ foregroundNotificationDescription,
+ getContext(),
+ {
+ sendPluginResult("success", null)
},
- { error ->
- sendPluginResult(null, Pair(error.code.toString(), error.message))
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
}
)
}
private fun deleteBackgroundJob(args: JSONArray) {
- val parameters = args.getString(0)
- healthStore?.deleteBackgroundJob(
- parameters,
- { response ->
- sendPluginResult(response)
+ val jobId = args.getString(0)
+ healthConnectViewModel.deleteBackgroundJob(
+ jobId,
+ getContext(),
+ {
+ sendPluginResult("success", null)
},
- { error ->
- sendPluginResult(null, Pair(error.code.toString(), error.message))
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
}
)
}
-
+
private fun listBackgroundJobs() {
- healthStore?.listBackgroundJobs(
- { response ->
- val pluginResponseJson = gson.toJson(response)
+ healthConnectViewModel.listBackgroundJobs(
+ {
+ val pluginResponseJson = gson.toJson(it)
sendPluginResult(pluginResponseJson)
},
- { error ->
- sendPluginResult(null, Pair(error.code.toString(), error.message))
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
}
)
}
private fun updateBackgroundJob(args: JSONArray) {
val parameters = gson.fromJson(args.getString(0), UpdateBackgroundJobParameters::class.java)
- healthStore?.updateBackgroundJob(
+ healthConnectViewModel.updateBackgroundJob(
parameters,
- { response ->
- sendPluginResult(response)
+ {
+ sendPluginResult("success", null)
},
- { error ->
- sendPluginResult(null, Pair(error.code.toString(), error.message))
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
}
)
}
-
- private fun disconnectFromGoogleFit() {
- healthStore?.disconnectFromGoogleFit(
+
+ private fun disconnectFromHealthConnect() {
+ healthConnectViewModel.disconnectFromHealthConnect(
+ getActivity(),
{
sendPluginResult("success", null)
},
@@ -247,28 +375,47 @@ class OSHealthFitness : CordovaImplementation() {
)
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent) {
- //super.onActivityResult(requestCode, resultCode, intent)
- try {
- healthStore?.handleActivityResult(requestCode, resultCode, intent)
- }
- catch(hse : HealthStoreException) {
- val error = hse.error
- sendPluginResult(null, Pair(error.code.toString(), error.message))
- }
+ private fun openHealthConnect() {
+ healthConnectViewModel.openHealthConnect(
+ getContext(),
+ {
+ sendPluginResult("success", null)
+ },
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
+ }
+ )
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
+ super.onActivityResult(requestCode, resultCode, intent)
+ healthConnectViewModel.handleActivityResult(requestCode, resultCode, intent,
+ {
+ sendPluginResult("success", null)
+ },
+ {
+ sendPluginResult(null, Pair(it.code.toString(), it.message))
+ }
+ )
}
override fun areGooglePlayServicesAvailable(): Boolean {
val googleApiAvailability = GoogleApiAvailability.getInstance()
- val status = googleApiAvailability.isGooglePlayServicesAvailable(cordova.activity)
+ val status = googleApiAvailability.isGooglePlayServicesAvailable(getActivity())
if (status != ConnectionResult.SUCCESS) {
var result: Pair? = null
result = if (googleApiAvailability.isUserResolvableError(status)) {
- googleApiAvailability.getErrorDialog(cordova.activity, status, 1)?.show()
- Pair(HealthFitnessError.GOOGLE_SERVICES_RESOLVABLE_ERROR.code.toString(), HealthFitnessError.GOOGLE_SERVICES_RESOLVABLE_ERROR.message)
+ googleApiAvailability.getErrorDialog(getActivity(), status, 1)?.show()
+ Pair(
+ HealthFitnessError.GOOGLE_SERVICES_RESOLVABLE_ERROR.code.toString(),
+ HealthFitnessError.GOOGLE_SERVICES_RESOLVABLE_ERROR.message
+ )
} else {
- Pair(HealthFitnessError.GOOGLE_SERVICES_ERROR.code.toString(), HealthFitnessError.GOOGLE_SERVICES_ERROR.message)
+ Pair(
+ HealthFitnessError.GOOGLE_SERVICES_ERROR.code.toString(),
+ HealthFitnessError.GOOGLE_SERVICES_ERROR.message
+ )
}
sendPluginResult(null, result)
return false
@@ -279,23 +426,28 @@ class OSHealthFitness : CordovaImplementation() {
override fun onRequestPermissionResult(
requestCode: Int,
permissions: Array,
- grantResults: IntArray) {
+ grantResults: IntArray
+ ) {
when (requestCode) {
- ACTIVITY_LOCATION_PERMISSIONS_REQUEST_CODE -> {
- // If request is cancelled, the result arrays are empty.
- if (grantResults.isNotEmpty() &&
- grantResults[0] == PackageManager.PERMISSION_GRANTED
- ) {
- checkAndGrantPermissions()
- } else {
+ BACKGROUND_JOB_PERMISSIONS_REQUEST_CODE -> {
+ for (result in grantResults) {
+ if (result == PackageManager.PERMISSION_DENIED) {
+ sendPluginResult(
+ null,
+ Pair(
+ HealthFitnessError.BACKGROUND_JOB_PERMISSIONS_DENIED_ERROR.code.toString(),
+ HealthFitnessError.BACKGROUND_JOB_PERMISSIONS_DENIED_ERROR.message
+ )
+ )
+ return
+ }
}
- return
+ setBackgroundJobWithParameters(backgroundParameters)
}
}
}
companion object {
- const val ACTIVITY_LOCATION_PERMISSIONS_REQUEST_CODE = 1
- const val ACTIVITY_NOTIFICATION_PERMISSIONS_REQUEST_CODE = 2
+ const val BACKGROUND_JOB_PERMISSIONS_REQUEST_CODE = 2
}
}
\ No newline at end of file
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeDirectory b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeDirectory
new file mode 100644
index 00000000..5bc08c34
Binary files /dev/null and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeDirectory differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeRequirements b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeRequirements
new file mode 100644
index 00000000..799807a4
Binary files /dev/null and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeRequirements differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeRequirements-1 b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeRequirements-1
new file mode 100644
index 00000000..8ea874ed
Binary files /dev/null and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeRequirements-1 differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeResources b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeResources
new file mode 100644
index 00000000..de7d57c7
--- /dev/null
+++ b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeResources
@@ -0,0 +1,563 @@
+
+
+
+
+ files
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.mom
+
+ WmEy7tCqK7VdDvPp1L+Zcjcv15A=
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.omo
+
+ ajrZlaH1WIiSvtK4zjYmN1cfJGg=
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel.mom
+
+ W6x/EHmIpxBSwBMDHQE5fB5k6os=
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/VersionInfo.plist
+
+ XiC0ivyLo+mC+FqE+19bvMOLCgI=
+
+ ios-arm64/OSHealthFitnessLib.framework/Headers/OSHealthFitnessLib-Swift.h
+
+ tFh7jOwfvsXhkmxPjq/nCoGuxbo=
+
+ ios-arm64/OSHealthFitnessLib.framework/Info.plist
+
+ hymD3FrEV6d/JaIyz8WZ1EcbbUw=
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.abi.json
+
+ vhy6jg03VOYB5O2yjEoA5QhssDY=
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.private.swiftinterface
+
+ 5L5A07FVaUIJD1lME3KxbDKm6i8=
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.swiftdoc
+
+ JbJUJqorr7ZbNbYJqqYWMWq+V84=
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.swiftinterface
+
+ 5L5A07FVaUIJD1lME3KxbDKm6i8=
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/module.modulemap
+
+ sw87f2yJ3lU2kd25gEKxIZALetM=
+
+ ios-arm64/OSHealthFitnessLib.framework/OSHealthFitnessLib
+
+ uJrT8ZJyE2dTWzQ1gsydYL5ZHoo=
+
+ ios-arm64/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
+
+ MiuKzpVIs0pYdHP2HzUd3nlWjzM=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.mom
+
+ WmEy7tCqK7VdDvPp1L+Zcjcv15A=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.omo
+
+ ajrZlaH1WIiSvtK4zjYmN1cfJGg=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel.mom
+
+ W6x/EHmIpxBSwBMDHQE5fB5k6os=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/VersionInfo.plist
+
+ XiC0ivyLo+mC+FqE+19bvMOLCgI=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Headers/OSHealthFitnessLib-Swift.h
+
+ Tzi/2WcpwfKL4Ps8ZU7n6sHzJks=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Info.plist
+
+ OlBN7pQMeLN9ByFYKpm0E/JK1KI=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.abi.json
+
+ vhy6jg03VOYB5O2yjEoA5QhssDY=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface
+
+ lxY3837m7v+jDwXrqL5APkU3b2s=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.swiftdoc
+
+ fZYiyx+/nzg0xqorND2Rfo7dd2k=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.swiftinterface
+
+ lxY3837m7v+jDwXrqL5APkU3b2s=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.abi.json
+
+ vhy6jg03VOYB5O2yjEoA5QhssDY=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface
+
+ dyXCAwDZuYrRMZSETrDm77QfhYQ=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
+
+ yze2Ljf7/YaHLG3a+vjW1sMIp6Q=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
+
+ dyXCAwDZuYrRMZSETrDm77QfhYQ=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/module.modulemap
+
+ sw87f2yJ3lU2kd25gEKxIZALetM=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/OSHealthFitnessLib
+
+ cKFP4c+JZDhH+KYadY4FSxqP22M=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
+
+ MiuKzpVIs0pYdHP2HzUd3nlWjzM=
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/_CodeSignature/CodeResources
+
+ YtGbLkVkBjDjKDVuX3aS2NG1YRY=
+
+
+ files2
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.mom
+
+ hash
+
+ WmEy7tCqK7VdDvPp1L+Zcjcv15A=
+
+ hash2
+
+ R4LfpjsuiJ+AuPKAvLjBqjrmeFDFxB7VVraRKh8eNBY=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.omo
+
+ hash
+
+ ajrZlaH1WIiSvtK4zjYmN1cfJGg=
+
+ hash2
+
+ vd3kQHM3ZF1tQrX39KE2AsvW8IBF8a+4a2+459bZvk0=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel.mom
+
+ hash
+
+ W6x/EHmIpxBSwBMDHQE5fB5k6os=
+
+ hash2
+
+ qRJigHLv9rlYsVac/moYMl5ly9UbGTmlNInvZGu7yeU=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/BackgroundModel.momd/VersionInfo.plist
+
+ hash
+
+ XiC0ivyLo+mC+FqE+19bvMOLCgI=
+
+ hash2
+
+ 9Wei4k8LCmjUieFX4fzHhZSc+DoajysUC8LuTDd52IY=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/Headers/OSHealthFitnessLib-Swift.h
+
+ hash
+
+ tFh7jOwfvsXhkmxPjq/nCoGuxbo=
+
+ hash2
+
+ vNT8+lqW6PkwQRPttcnTQLHIjBIeD5ERyRM0qEC0dVs=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/Info.plist
+
+ hash
+
+ hymD3FrEV6d/JaIyz8WZ1EcbbUw=
+
+ hash2
+
+ TqDxrB0jxcaArOvfnWpbi9aaRZ4RN+NcmFPFZyZJhlI=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.abi.json
+
+ hash
+
+ vhy6jg03VOYB5O2yjEoA5QhssDY=
+
+ hash2
+
+ xUYeELV1++5cy/tsWv++R6V7LZ1FgDg+N4864w3qyPs=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.private.swiftinterface
+
+ hash
+
+ 5L5A07FVaUIJD1lME3KxbDKm6i8=
+
+ hash2
+
+ pKaiDC/O/A05qM8c3FXoMkNdetRzUn8lME2j8U/o9IE=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.swiftdoc
+
+ hash
+
+ JbJUJqorr7ZbNbYJqqYWMWq+V84=
+
+ hash2
+
+ irAYQkwaczEfAdWuH8B4+Z+foraBbKTbO8WpSVi/e0A=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios.swiftinterface
+
+ hash
+
+ 5L5A07FVaUIJD1lME3KxbDKm6i8=
+
+ hash2
+
+ pKaiDC/O/A05qM8c3FXoMkNdetRzUn8lME2j8U/o9IE=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/Modules/module.modulemap
+
+ hash
+
+ sw87f2yJ3lU2kd25gEKxIZALetM=
+
+ hash2
+
+ P7SE820E52XFwuSc9IyT2YlJFy1uZqPxi8tOPOxwGfg=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/OSHealthFitnessLib
+
+ hash
+
+ uJrT8ZJyE2dTWzQ1gsydYL5ZHoo=
+
+ hash2
+
+ 2nCWtsV5vs+n14nQpvSsnNKKmnugQYzVhPql/eF0VpQ=
+
+
+ ios-arm64/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
+
+ hash
+
+ MiuKzpVIs0pYdHP2HzUd3nlWjzM=
+
+ hash2
+
+ tJsHvjtv5Yj/fAdXa5lrQhNxNvF1CYow/Bte4ARYb4I=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.mom
+
+ hash
+
+ WmEy7tCqK7VdDvPp1L+Zcjcv15A=
+
+ hash2
+
+ R4LfpjsuiJ+AuPKAvLjBqjrmeFDFxB7VVraRKh8eNBY=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel 2.omo
+
+ hash
+
+ ajrZlaH1WIiSvtK4zjYmN1cfJGg=
+
+ hash2
+
+ vd3kQHM3ZF1tQrX39KE2AsvW8IBF8a+4a2+459bZvk0=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/BackgroundModel.mom
+
+ hash
+
+ W6x/EHmIpxBSwBMDHQE5fB5k6os=
+
+ hash2
+
+ qRJigHLv9rlYsVac/moYMl5ly9UbGTmlNInvZGu7yeU=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/BackgroundModel.momd/VersionInfo.plist
+
+ hash
+
+ XiC0ivyLo+mC+FqE+19bvMOLCgI=
+
+ hash2
+
+ 9Wei4k8LCmjUieFX4fzHhZSc+DoajysUC8LuTDd52IY=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Headers/OSHealthFitnessLib-Swift.h
+
+ hash
+
+ Tzi/2WcpwfKL4Ps8ZU7n6sHzJks=
+
+ hash2
+
+ 37W0F4g9c0cOUjZ4zv35kFosbGcfrrLN0Fi35ttffWY=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Info.plist
+
+ hash
+
+ OlBN7pQMeLN9ByFYKpm0E/JK1KI=
+
+ hash2
+
+ GPl1xNhlKlNqJqhvPPPt/DsxBWbgaxe4ZTwTtMe6H5w=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.abi.json
+
+ hash
+
+ vhy6jg03VOYB5O2yjEoA5QhssDY=
+
+ hash2
+
+ xUYeELV1++5cy/tsWv++R6V7LZ1FgDg+N4864w3qyPs=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface
+
+ hash
+
+ lxY3837m7v+jDwXrqL5APkU3b2s=
+
+ hash2
+
+ WYiBdk+I7U8Pxk4rkg0ihFDHE8iWSNW4izebMztdSGA=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.swiftdoc
+
+ hash
+
+ fZYiyx+/nzg0xqorND2Rfo7dd2k=
+
+ hash2
+
+ B4o2qQ3qSCDLeOKuTN97+QK/02u8/9jDksMfnRR9Pso=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.swiftinterface
+
+ hash
+
+ lxY3837m7v+jDwXrqL5APkU3b2s=
+
+ hash2
+
+ WYiBdk+I7U8Pxk4rkg0ihFDHE8iWSNW4izebMztdSGA=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.abi.json
+
+ hash
+
+ vhy6jg03VOYB5O2yjEoA5QhssDY=
+
+ hash2
+
+ xUYeELV1++5cy/tsWv++R6V7LZ1FgDg+N4864w3qyPs=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface
+
+ hash
+
+ dyXCAwDZuYrRMZSETrDm77QfhYQ=
+
+ hash2
+
+ Uh7kksBEhd2YGS1lLGC0CNDrJe9WXnGu9+8mlrJCOWs=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.swiftdoc
+
+ hash
+
+ yze2Ljf7/YaHLG3a+vjW1sMIp6Q=
+
+ hash2
+
+ MU/Yaw9Xd8dvRYhZ6+yRxp0lgReWigV+Q04ycLpfSbY=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/OSHealthFitnessLib.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
+
+ hash
+
+ dyXCAwDZuYrRMZSETrDm77QfhYQ=
+
+ hash2
+
+ Uh7kksBEhd2YGS1lLGC0CNDrJe9WXnGu9+8mlrJCOWs=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Modules/module.modulemap
+
+ hash
+
+ sw87f2yJ3lU2kd25gEKxIZALetM=
+
+ hash2
+
+ P7SE820E52XFwuSc9IyT2YlJFy1uZqPxi8tOPOxwGfg=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/OSHealthFitnessLib
+
+ hash
+
+ cKFP4c+JZDhH+KYadY4FSxqP22M=
+
+ hash2
+
+ yKPto2v6HemlmGb7M5LUjI8D7VPnk7Bs85i9DvbL+eI=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
+
+ hash
+
+ MiuKzpVIs0pYdHP2HzUd3nlWjzM=
+
+ hash2
+
+ tJsHvjtv5Yj/fAdXa5lrQhNxNvF1CYow/Bte4ARYb4I=
+
+
+ ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/_CodeSignature/CodeResources
+
+ hash
+
+ YtGbLkVkBjDjKDVuX3aS2NG1YRY=
+
+ hash2
+
+ ITOUOiQb8+QEv9LQ2NNGNv3L6rLR9q95EE7lYbW+TNo=
+
+
+
+ rules
+
+ ^.*
+
+ ^.*\.lproj/
+
+ optional
+
+ weight
+ 1000
+
+ ^.*\.lproj/locversion.plist$
+
+ omit
+
+ weight
+ 1100
+
+ ^Base\.lproj/
+
+ weight
+ 1010
+
+ ^version.plist$
+
+
+ rules2
+
+ .*\.dSYM($|/)
+
+ weight
+ 11
+
+ ^(.*/)?\.DS_Store$
+
+ omit
+
+ weight
+ 2000
+
+ ^.*
+
+ ^.*\.lproj/
+
+ optional
+
+ weight
+ 1000
+
+ ^.*\.lproj/locversion.plist$
+
+ omit
+
+ weight
+ 1100
+
+ ^Base\.lproj/
+
+ weight
+ 1010
+
+ ^Info\.plist$
+
+ omit
+
+ weight
+ 20
+
+ ^PkgInfo$
+
+ omit
+
+ weight
+ 20
+
+ ^embedded\.provisionprofile$
+
+ weight
+ 20
+
+ ^version\.plist$
+
+ weight
+ 20
+
+
+
+
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeSignature b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeSignature
new file mode 100644
index 00000000..0355c148
Binary files /dev/null and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/_CodeSignature/CodeSignature differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/Info.plist b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/Info.plist
index 67458372..028b1234 100644
Binary files a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/Info.plist and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/Info.plist differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/OSHealthFitnessLib b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/OSHealthFitnessLib
index d3a5fbb4..a32e2151 100755
Binary files a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/OSHealthFitnessLib and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/OSHealthFitnessLib differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
new file mode 100644
index 00000000..48582894
--- /dev/null
+++ b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
@@ -0,0 +1,59 @@
+
+
+
+
+ NSPrivacyTracking
+
+
+ NSPrivacyTrackingDomains
+
+
+ NSPrivacyCollectedDataTypes
+
+
+ NSPrivacyCollectedDataType
+ NSPrivacyCollectedDataTypeHealth
+
+ NSPrivacyCollectedDataTypeLinked
+
+
+ NSPrivacyCollectedDataTypeTracking
+
+
+ NSPrivacyCollectedDataTypePurposes
+
+ NSPrivacyCollectedDataTypePurposeAppFunctionality
+
+
+
+
+ NSPrivacyCollectedDataType
+ NSPrivacyCollectedDataTypeFitness
+
+ NSPrivacyCollectedDataTypeLinked
+
+
+ NSPrivacyCollectedDataTypeTracking
+
+
+ NSPrivacyCollectedDataTypePurposes
+
+ NSPrivacyCollectedDataTypePurposeAppFunctionality
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
+
+
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Info.plist b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Info.plist
index 3697806d..d3a8510f 100644
Binary files a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Info.plist and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/Info.plist differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/OSHealthFitnessLib b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/OSHealthFitnessLib
index 026571b2..725c7b4e 100755
Binary files a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/OSHealthFitnessLib and b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/OSHealthFitnessLib differ
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
new file mode 100644
index 00000000..48582894
--- /dev/null
+++ b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/PrivacyInfo.xcprivacy
@@ -0,0 +1,59 @@
+
+
+
+
+ NSPrivacyTracking
+
+
+ NSPrivacyTrackingDomains
+
+
+ NSPrivacyCollectedDataTypes
+
+
+ NSPrivacyCollectedDataType
+ NSPrivacyCollectedDataTypeHealth
+
+ NSPrivacyCollectedDataTypeLinked
+
+
+ NSPrivacyCollectedDataTypeTracking
+
+
+ NSPrivacyCollectedDataTypePurposes
+
+ NSPrivacyCollectedDataTypePurposeAppFunctionality
+
+
+
+
+ NSPrivacyCollectedDataType
+ NSPrivacyCollectedDataTypeFitness
+
+ NSPrivacyCollectedDataTypeLinked
+
+
+ NSPrivacyCollectedDataTypeTracking
+
+
+ NSPrivacyCollectedDataTypePurposes
+
+ NSPrivacyCollectedDataTypePurposeAppFunctionality
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
+
+
diff --git a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/_CodeSignature/CodeResources b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/_CodeSignature/CodeResources
index 5f6f7bcb..03d83321 100644
--- a/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/_CodeSignature/CodeResources
+++ b/src/ios/frameworks/OSHealthFitnessLib.xcframework/ios-arm64_x86_64-simulator/OSHealthFitnessLib.framework/_CodeSignature/CodeResources
@@ -26,7 +26,7 @@
Info.plist
- P953UGaWh0AJIzLmDo8gOMYd9W8=
+ OlBN7pQMeLN9ByFYKpm0E/JK1KI=
Modules/OSHealthFitnessLib.swiftmodule/arm64-apple-ios-simulator.abi.json
@@ -72,6 +72,10 @@
sw87f2yJ3lU2kd25gEKxIZALetM=
+ PrivacyInfo.xcprivacy
+
+ MiuKzpVIs0pYdHP2HzUd3nlWjzM=
+
files2
@@ -187,6 +191,13 @@
P7SE820E52XFwuSc9IyT2YlJFy1uZqPxi8tOPOxwGfg=
+ PrivacyInfo.xcprivacy
+
+ hash2
+
+ tJsHvjtv5Yj/fAdXa5lrQhNxNvF1CYow/Bte4ARYb4I=
+
+
rules
diff --git a/www/OSHealthFitness.js b/www/OSHealthFitness.js
index a1b23040..4a9a78b4 100644
--- a/www/OSHealthFitness.js
+++ b/www/OSHealthFitness.js
@@ -8,11 +8,10 @@ exports.requestPermissions = function (success, error, params) {
fitnessVariables,
healthVariables,
profileVariables,
- summaryVariables,
workoutVariables
} = params;
- var args = [customPermissions, allVariables, fitnessVariables, healthVariables, profileVariables, summaryVariables, workoutVariables];
+ var args = [customPermissions, allVariables, fitnessVariables, healthVariables, profileVariables, workoutVariables];
exec(success, error, 'OSHealthFitness', 'requestPermissions', args);
};
@@ -57,6 +56,10 @@ exports.updateBackgroundJob = function (success, error, params) {
exec(success, error, 'OSHealthFitness', 'updateBackgroundJob', [params]);
};
-exports.disconnectFromGoogleFit = function (success, error) {
- exec(success, error, 'OSHealthFitness', 'disconnectFromGoogleFit');
+exports.disconnectFromHealthConnect = function (success, error) {
+ exec(success, error, 'OSHealthFitness', 'disconnectFromHealthConnect');
+};
+
+exports.openHealthConnect = function (success, error) {
+ exec(success, error, 'OSHealthFitness', 'openHealthConnect');
};