Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@theankur/cordova-plugin-health
Advanced tools
A plugin that abstracts fitness and health repositories like Apple HealthKit or Google Fit
A plugin that abstracts fitness and health repositories like Apple HealthKit or Google Fit.
This work is based on cordova plugin googlefit and on cordova healthkit plugin
For an introduction about Google Fit versus HealthKit see this very good article.
This plugin is kept up to date and requires a recent version of cordova (6 and on) as well as recent iOS and Android SDKs.
If you have any question or small issue, please use the gitter channel.
Google is rolling out a new, stricter, policy for using their Fitness API. Read about it here. The API has also introduced new ways for retrieving heart rate and sleep, but these have not been implemented yet in this plugin (help is appreciated!).
In Cordova:
cordova plugin add @theankur/cordova-plugin-health --variable HEALTH_READ_PERMISSION='App needs read access' --variable HEALTH_WRITE_PERMISSION='App needs write access'
HEALTH_READ_PERMISSION
and HEALTH_WRITE_PERMISSION
are shown when the app tries to grant access to data in HealthKit.
FIT_API_VERSION
and PLAY_AUTH_VERSION
allow you to override the google services version.
Phonegap Build config.xml
:
<!-- Health plugin -->
<plugin name="@theankur/cordova-plugin-health" source="npm">
<variable name="HEALTH_READ_PERMISSION" value="App needs read access"/>
<variable name="HEALTH_WRITE_PERMISSION" value="App needs write access"/>
<variable name="PLAY_AUTH_VERSION" value="19.0.0"/>
<variable name="FIT_API_VERSION" value="20.0.0"/>
</plugin>
<!-- Only if iOS -->
<!-- Read access -->
<config-file platform="ios" parent="NSHealthShareUsageDescription">
<string>App needs read access</string>
</config-file>
<!-- Write access -->
<config-file platform="ios" parent="NSHealthUpdateUsageDescription">
<string>App needs write access</string>
</config-file>
If, for some reason, the Info.plist loses the HEALTH_READ_PERMISSION and HEALTH_WRITE_PERMISSION, you probably need to add the following to your project's package.json:
{
"cordova": {
"plugins": {
"@theankur/cordova-plugin-health": {
"HEALTH_READ_PERMISSION": "App needs read access",
"HEALTH_WRITE_PERMISSION": "App needs write access"
},
},
}
}
This is known to happen when using the Ionic Package cloud service.
NSHealthShareUsageDescription
and NSHealthUpdateUsageDescription
. These are assigned with a default string by the plugin, but you may want to contextualise them for your app.keytool -list -printcert -jarfile yourapp.apk
.FIT_API_VERSION
variable in config.xml
and the version of the Auth API using PLAY_AUTH_VERSION
. By default it will use version 20.0.0
for play-services-fitness and version 19.0.0
for play-services-auth (see release notes). From version 15 of the Play Services you don't have to use the same version accross all your cordova plugins. You can track google services releases here.As HealthKit does not allow adding custom data types, only a subset of data types supported by HealthKit has been chosen.
Data type | Unit | HealthKit equivalent | Google Fit equivalent |
---|---|---|---|
steps | count | HKQuantityTypeIdentifierStepCount | TYPE_STEP_COUNT_DELTA |
stairs | count | HKQuantityTypeIdentifierFlightsClimbed | NA |
distance | m | HKQuantityTypeIdentifierDistanceWalkingRunning + HKQuantityTypeIdentifierDistanceCycling | TYPE_DISTANCE_DELTA |
appleExerciseTime | min | HKQuantityTypeIdentifierAppleExerciseTime | NA |
calories | kcal | HKQuantityTypeIdentifierActiveEnergyBurned + HKQuantityTypeIdentifierBasalEnergyBurned | TYPE_CALORIES_EXPENDED |
calories.active | kcal | HKQuantityTypeIdentifierActiveEnergyBurned | TYPE_CALORIES_EXPENDED - (TYPE_BASAL_METABOLIC_RATE * time window) |
calories.basal | kcal | HKQuantityTypeIdentifierBasalEnergyBurned | TYPE_BASAL_METABOLIC_RATE * time window |
activity | activityType | HKWorkoutTypeIdentifier + HKCategoryTypeIdentifierSleepAnalysis | TYPE_ACTIVITY_SEGMENT |
height | m | HKQuantityTypeIdentifierHeight | TYPE_HEIGHT |
weight | kg | HKQuantityTypeIdentifierBodyMass | TYPE_WEIGHT |
bmi | count | HKQuantityTypeIdentifierBodyMassIndex | NA |
heart_rate | count/min | HKQuantityTypeIdentifierHeartRate | TYPE_HEART_RATE_BPM |
heart_rate.resting | count/min | HKQuantityTypeIdentifierRestingHearRate | TBD |
heart_rate.variability | ms | HKQuantityTypeIdentifierHeartRateVariabilitySDNN | NA |
resp_rate | count/min | HKQuantityTypeIdentifierRespiratoryRate | TBD |
oxygen_saturation | % | HKQuantityTypeIdentifierOxygenSaturation | TYPE_OXYGEN_SATURATION |
vo2max | ml/(kg * min) | HKQuantityTypeIdentifierVO2Max | TBD |
temperature | Celsius | HKQuantityTypeIdentifierBodyTemperature | TBD |
fat_percentage | % | HKQuantityTypeIdentifierBodyFatPercentage | TYPE_BODY_FAT_PERCENTAGE |
waist_circumference | m | HKQuantityTypeIdentifierWaistCircumference | NA |
blood_glucose | mmol/L | HKQuantityTypeIdentifierBloodGlucose | TYPE_BLOOD_GLUCOSE |
insulin | IU | HKQuantityTypeIdentifierInsulinDelivery | NA |
blood_pressure | mmHg | HKCorrelationTypeIdentifierBloodPressure | TYPE_BLOOD_PRESSURE |
blood_pressure_systolic | mmHg | HKQuantityTypeIdentifierBloodPressureSystolic | NA |
blood_pressure_diastolic | mmHg | HKQuantityTypeIdentifierBloodPressureDiastolic | NA |
gender | HKCharacteristicTypeIdentifierBiologicalSex | NA | |
date_of_birth | HKCharacteristicTypeIdentifierDateOfBirth | NA | |
mindfulness | sec | HKCategoryTypeIdentifierMindfulSession | NA |
nutrition | HKCorrelationTypeIdentifierFood | TYPE_NUTRITION | |
UVexposure | count | HKQuantityTypeIdentifierUVExposure | NA |
nutrition.calories | kcal | HKQuantityTypeIdentifierDietaryEnergyConsumed | TYPE_NUTRITION, NUTRIENT_CALORIES |
nutrition.fat.total | g | HKQuantityTypeIdentifierDietaryFatTotal | TYPE_NUTRITION, NUTRIENT_TOTAL_FAT |
nutrition.fat.saturated | g | HKQuantityTypeIdentifierDietaryFatSaturated | TYPE_NUTRITION, NUTRIENT_SATURATED_FAT |
nutrition.fat.unsaturated | g | NA | TYPE_NUTRITION, NUTRIENT_UNSATURATED_FAT |
nutrition.fat.polyunsaturated | g | HKQuantityTypeIdentifierDietaryFatPolyunsaturated | TYPE_NUTRITION, NUTRIENT_POLYUNSATURATED_FAT |
nutrition.fat.monounsaturated | g | HKQuantityTypeIdentifierDietaryFatMonounsaturated | TYPE_NUTRITION, NUTRIENT_MONOUNSATURATED_FAT |
nutrition.fat.trans | g | NA | TYPE_NUTRITION, NUTRIENT_TRANS_FAT (g) |
nutrition.cholesterol | mg | HKQuantityTypeIdentifierDietaryCholesterol | TYPE_NUTRITION, NUTRIENT_CHOLESTEROL |
nutrition.sodium | mg | HKQuantityTypeIdentifierDietarySodium | TYPE_NUTRITION, NUTRIENT_SODIUM |
nutrition.potassium | mg | HKQuantityTypeIdentifierDietaryPotassium | TYPE_NUTRITION, NUTRIENT_POTASSIUM |
nutrition.carbs.total | g | HKQuantityTypeIdentifierDietaryCarbohydrates | TYPE_NUTRITION, NUTRIENT_TOTAL_CARBS |
nutrition.dietary_fiber | g | HKQuantityTypeIdentifierDietaryFiber | TYPE_NUTRITION, NUTRIENT_DIETARY_FIBER |
nutrition.sugar | g | HKQuantityTypeIdentifierDietarySugar | TYPE_NUTRITION, NUTRIENT_SUGAR |
nutrition.protein | g | HKQuantityTypeIdentifierDietaryProtein | TYPE_NUTRITION, NUTRIENT_PROTEIN |
nutrition.vitamin_a | mcg (HK), IU (GF) | HKQuantityTypeIdentifierDietaryVitaminA | TYPE_NUTRITION, NUTRIENT_VITAMIN_A |
nutrition.vitamin_c | mg | HKQuantityTypeIdentifierDietaryVitaminC | TYPE_NUTRITION, NUTRIENT_VITAMIN_C |
nutrition.calcium | mg | HKQuantityTypeIdentifierDietaryCalcium | TYPE_NUTRITION, NUTRIENT_CALCIUM |
nutrition.iron | mg | HKQuantityTypeIdentifierDietaryIron | TYPE_NUTRITION, NUTRIENT_IRON |
nutrition.water | ml | HKQuantityTypeIdentifierDietaryWater | TYPE_HYDRATION |
nutrition.caffeine | g | HKQuantityTypeIdentifierDietaryCaffeine | NA |
Note: units of measurement are fixed!
Returned objects contain a set of fixed fields:
Example values:
Data type | Value |
---|---|
steps | 34 |
distance | 101.2 |
appleExerciseTime | 24 Notes: only available on iOS |
calories | 245.3 |
activity | "walking" Notes: recognized activities and their mappings in Google Fit / HealthKit can be found here the query also returns calories (kcal) and distance (m) Warning If you want to fetch activities you also have to request permission for 'calories' and 'distance' (Android). |
height | 1.85 |
weight | 83.3 |
heart_rate | 66 |
heart_rate.resting | 63 |
heart_rate.variability | 100 |
resp_rate | 12 |
vo2max | 34 |
temperature | 36.2 |
fat_percentage | 0.312 |
waist_circumference | 0.65 |
blood_glucose | { glucose: 5.5, meal: 'breakfast', sleep: 'fully_awake', source: 'capillary_blood' } Notes: to convert to mg/dL, multiply by 18.01559 (The molar mass of glucose is 180.1559)meal can be: 'before_meal' (iOS only), 'after_meal' (iOS only), 'fasting', 'breakfast', 'dinner', 'lunch', 'snack', 'unknown', 'before_breakfast', 'before_dinner', 'before_lunch', 'before_snack', 'after_breakfast', 'after_dinner', 'after_lunch', 'after_snack'sleep can be: 'fully_awake', 'before_sleep', 'on_waking', 'during_sleep'source can be: 'capillary_blood' ,'interstitial_fluid', 'plasma', 'serum', 'tears', whole_blood' |
insulin | { insulin: 2.3, reason: 'bolus' } Notes: only available on iOS reason can be 'bolus' or 'basal' |
blood_pressure | { systolic: 110, diastolic: 70 } |
blood_pressure_systolic | 110 |
blood_pressure_diastolic | 70 |
gender | "male" Notes: only available on iOS |
date_of_birth | { day: 3, month: 12, year: 1978 } Notes: currently only available on iOS |
mindfulness | 1800 Notes: only available on iOS |
nutrition | { item: "cheese", meal_type: "lunch", brand_name: "McDonald's", nutrients: { nutrition.fat.saturated: 11.5, nutrition.calories: 233.1 } } Note: the brand_name property is only available on iOS |
nutrition.X | 12.4 |
sleep | 'sleep.light' Notes: can be sleep, sleep.awake, sleep.outOfBed, sleep.deep, sleep.light, sleep.rem recognized sleep stages and their mappings in Google Fit / HealthKit can be found here |
Tells if either Google Fit or HealthKit are available.
navigator.health.isAvailable(successCallback, errorCallback)
<package android:name="com.google.android.apps.fitness" />
under queries
to AndroidManifest.xml via config.xml. See this article for infoChecks if recent Google Play Services and Google Fit are installed. If the play services are not installed, or are obsolete, it will show a pop-up suggesting to download them. If Google Fit is not installed, it will open the Play Store at the location of the Google Fit app. The plugin does not wait until the missing packages are installed, it will return immediately. If both Play Services and Google Fit are available, this function just returns without any visible effect.
This function is only available on Android.
navigator.health.promptInstallFit(successCallback, errorCallback)
Requests read and write access to a set of data types. It is recommendable to always explain why the app needs access to the data before asking the user to authorize it.
Important: this method must be called before using the query and store methods, even if the authorization has already been given at some point in the past. Failure to do so may cause your app to crash, or in the case of Android, Google Fit may not be ready.
navigator.health.requestAuthorization(datatypes, successCallback, errorCallback)
[
"calories",
"distance", // Read and write permissions
{
read: ["steps"], // Read only permission
write: ["height", "weight"], // Write only permission
},
];
activity
also includes sleep. If you want to get authorization only for workouts, you can specify workouts
as datatype, but be aware that this is only availabe in iOS.Check if the app has authorization to read/write a set of datatypes.
navigator.health.isAuthorized(datatypes, successCallback, errorCallback)
Removes authorization from the app. Works only on Android.
navigator.health.disconnect(successCallback, errorCallback)
Gets all the data points of a certain data type within a certain time window.
Warning: if the time span is big, it can generate long arrays!
navigator.health.query({
startDate: new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000), // three days ago
endDate: new Date(), // now
dataType: 'height',
limit: 1000
}, successCallback, errorCallback)
ascending: true
to your query object.workouts
datatype, but be aware that this will only be availabe in iOS.filtered: true
.Gets aggregated data in a certain time window. Usually the sum is returned for the given quantity.
navigator.health.queryAggregated({
startDate: new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000), // three days ago
endDate: new Date(), // now
dataType: 'steps',
bucket: 'day'
}, successCallback, errorCallback)
Not all data types are supported for aggregated queries. The following table shows what types are supported and examples of the returned object:
Data type | Example of returned object |
---|---|
steps | { startDate: Date, endDate: Date, value: 5780, unit: 'count' } |
distance | { startDate: Date, endDate: Date, value: 12500.0, unit: 'm' } |
calories | { startDate: Date, endDate: Date, value: 25698.1, unit: 'kcal' } |
calories.active | { startDate: Date, endDate: Date, value: 3547.4, unit: 'kcal' } |
calories.basal | { startDate: Date, endDate: Date, value: 13146.1, unit: 'kcal' } |
activity | { startDate: Date, endDate: Date, value: { still: { duration: 520000, calories: 30, distance: 0 }, walking: { duration: 223000, calories: 20, distance: 15 }}, unit: 'activitySummary' } Note: duration is expressed in milliseconds, distance in meters and calories in kcal |
nutrition | { startDate: Date, endDate: Date, value: { nutrition.fat.saturated: 11.5, nutrition.calories: 233.1 }, unit: 'nutrition' } Note: units of measurement for nutrients are fixed according to the table at the beginning of this README |
nutrition.x | { startDate: Date, endDate: Date, value: 23, unit: 'mg'} |
filtered: true
to the query object. This returns the steps as filtered out by Google Fit, or the non-manual ones from HealthKit.Stores a data point.
navigator.health.store({
startDate: new Date(new Date().getTime() - 3 * 60 * 1000), // three minutes ago
endDate: new Date(),
dataType: 'steps',
value: 180,
sourceBundleId: 'com.example.my_app'
}, successCallback, errorCallback)
dataType: 'activity', value: 'walking', calories: 20, distance: 520
. Distance is set as DistanceWalkingRunning unless an additional cycling: true
is added to the object. Be aware that you need permission to write calories and distance first, or the call will fail.cycling: true
.Deletes a range of data points.
navigator.health.delete({
startDate: new Date(new Date().getTime() - 3 * 60 * 1000), // three minutes ago
endDate: new Date(),
dataType: 'steps'
}, successCallback, errorCallback)
cycling: true
.unit
attribute, you can find the comprehensive list of possible units from the Apple Developers documentation.Short term:
Long term:
Any help is more than welcome!
I don't know Objective C and I am not interested in learning it now, so I would particularly appreciate someone who could give me a hand with the iOS part. Also, I would love to know from you if the plugin is currently used in any app actually available online. Just send me an email to my_username at gmail.com. For donations, you can use my monzo.me account.
Thanks!
FAQs
A plugin that abstracts fitness and health repositories like Apple HealthKit or Google Fit
We found that @theankur/cordova-plugin-health demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.