Giter Club home page Giter Club logo

nativescript-health-data's Introduction

Health Data plugin for NativeScript

This is a NativeScript plugin that abstracts Apple HealthKit and Google Fit to read health data from the user's device.

Build Status NPM version Downloads Twitter Follow

Prerequisites

Android

Google Fit API Key - Go to the Google Developers Console, create a project, and enable the Fitness API. Then under Credentials, create a Fitness API OAuth2 client ID for an Android App (select User data and press the What credentials do I need? button). If you are using Linux/maxOS, generate your SHA1-key with the code below.

keytool -exportcert -keystore path-to-debug-or-production-keystore -list -v

Note that the default (debug) keystore password is empty.

iOS

Make sure you enable the HealthKit entitlement in your app ID.

Installation

Install the plugin using the NativeScript CLI:

tns plugin add nativescript-health-data

API

The examples below are all in TypeScript, and the demo was developed in Nativescript w/ Angular.

This is how you can import and instantiate the plugin, all examples expect this setup:

import { AggregateBy, HealthData, HealthDataType } from 'nativescript-health-data';

export class MyHealthyClass {
	private healthData: HealthData;

	constructor() {
		this.healthData = new HealthData();
	}
}

isAvailable

This tells you whether or not the device supports Health Data. On iOS this is probably always true. On Android the user will be prompted to (automatically) update their Play Services version in case it's not sufficiently up to date. If you don't want this behavior, pass false to this function, as shown below.

this.healthData.isAvailable(false).then((available) => console.log(available));

isAuthorized

This function (and the next one) takes an Array of HealthDataType's. Each of those has a name and an accessType.

  • The name can be one of the 'Available Data Types'.
  • The accessType can be one of read, write, or readAndWrite (note that this plugin currently only supports reading data, but that will change).

iOS is a bit silly here: if you've only requested 'read' access, you'll never get a true response from this method. Details here.

this.healthData
	.isAuthorized([<HealthDataType>{ name: 'steps', accessType: 'read' }])
	.then((authorized) => console.log(authorized));

requestAuthorization

This function takes the same argument as isAuthorized, and will trigger a consent screen in case the user hasn't previously authorized your app to access any of the passed HealthDataType's.

Note that this plugin currently only supports reading data, but that will change.

const types: Array<HealthDataType> = [
	{ name: 'height', accessType: 'write' },
	{ name: 'weight', accessType: 'readAndWrite' },
	{ name: 'steps', accessType: 'read' },
	{ name: 'distance', accessType: 'read' },
];

this.healthData
	.requestAuthorization(types)
	.then((authorized) => console.log(authorized))
	.catch((error) => console.log('Request auth error: ', error));

query

Mandatory properties are startData, endDate, and dataType. The dataType must be one of the 'Available Data Types'.

By default data is not aggregated, so all individual datapoints are returned. This plugin however offers a way to aggregate the data by either hour, day, or sourceAndDay, the latter will enable you to read daily data per source (Fitbit, Nike Run Club, manual entry, etc).

If you didn't run requestAuthorization before running query, the plugin will run requestAuthorization for you (for the requested dataType). You're welcome. ๐Ÿ˜‰

this.healthData
	.query({
		startDate: new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000), // 3 days ago
		endDate: new Date(), // now
		dataType: 'steps', // equal to the 'name' property of 'HealthDataType'
		unit: 'count', // make sure this is compatible with the 'dataType' (see below)
		aggregateBy: 'day', // optional, one of: "hour", "day", "sourceAndDay"
		sortOrder: 'desc', // optional, default "asc"
	})
	.then((result) => console.log(JSON.stringify(result)))
	.catch((error) => (this.resultToShow = error));

queryAggregateData

Difference between query and queryAggregateData: if you use query, you will probably find that the number of steps (or other types of data) do not match those shown by the Google Fit and Apple Health apps. If you wanted to accurately compute the user's data then use: queryAggregateData

Mandatory properties are startData, endDate, and dataType. The dataType must be one of the 'Available Data Types'.

By default data is aggregated by day. This plugin however offers a way to aggregate the data by either hour and day. (month and year available soon)

Note that queryAggregateData only supports steps, calories and distance on Android. (More data types available soon).

If you didn't run requestAuthorization before running query, the plugin will run requestAuthorization for you (for the requested dataType). You're welcome. ๐Ÿ˜‰

this.healthData
	.queryAggregateData({
		startDate: new Date(new Date().getTime() - 3 * 24 * 60 * 60 * 1000), // 3 days ago
		endDate: new Date(), // now
		dataType: 'steps', // equal to the 'name' property of 'HealthDataType'
		unit: 'count', // make sure this is compatible with the 'dataType' (see below)
		aggregateBy: 'day', // optional, one of: "hour", "day" ; default: "day"
	})
	.then((result) => console.log(JSON.stringify(result)))
	.catch((error) => (this.resultToShow = error));

startMonitoring (iOS only, for now)

If you want to be notified when health data was changed, you can monitor specific types. This even works when your app is in the background, with enableBackgroundUpdates: true. Note that iOS will wake up your app so you can act upon this notification (in the onUpdate function by fi. querying recent changes to this data type), but in return you are responsible for telling iOS you're done. So make sure you invoke the completionHandler as shown below.

Not all data types support backgroundUpdateFrequency: "immediate", so your app may not always be invoked immediately when data is added/deleted in HealthKit.

Background notifications probably don't work on the iOS simulator, so please test those on a real device.

this.healthData
	.startMonitoring({
		dataType: 'heartRate',
		enableBackgroundUpdates: true,
		backgroundUpdateFrequency: 'immediate',
		onUpdate: (completionHandler: () => void) => {
			console.log('Our app was notified that health data changed, so querying...');
			this.getData('heartRate', 'count/min').then(() => completionHandler());
		},
	})
	.then(() => (this.resultToShow = `Started monitoring heartRate`))
	.catch((error) => (this.resultToShow = error));

stopMonitoring (iOS only, for now)

It's best to call this method in case you no longer wish to receive notifications when health data changes.

this.healthData
	.stopMonitoring({
		dataType: 'heartRate',
	})
	.then(() => (this.resultToShow = `Stopped monitoring heartRate`))
	.catch((error) => (this.resultToShow = error));

Available Data Types

With version 1.0.0 these are the supported types of data you can read. Also, make sure you pass in the correct unit.

Note that you are responsible for passing the correct unit, although there's only 1 option for each type. Well actually, the unit is ignored on Android at the moment, and on iOS there are undocumented types you can pass in (fi. mi for distance).

The reason is I intend to support more units per type, but that is yet to be implemented... so it's for the sake of future backward-compatibility! ๐Ÿคฏ

TypeOfData Unit GoogleFit Data Type Apple HealthKit Data Type
distance m TYPE_DISTANCE_DELTA HKQuantityTypeIdentifierDistanceWalkingRunning
steps count TYPE_STEP_COUNT_DELTA HKQuantityTypeIdentifierStepCount
calories count TYPE_CALORIES_EXPENDED HKQuantityTypeIdentifierActiveEnergyBurned
height m TYPE_HEIGHT HKQuantityTypeIdentifierHeight
weight kg TYPE_WEIGHT HKQuantityTypeIdentifierBodyMass
heartRate count/min TYPE_HEART_RATE_BPM HKQuantityTypeIdentifierHeartRate
fatPercentage % TYPE_BODY_FAT_PERCENTAGE HKQuantityTypeIdentifierBodyFatPercentage

Credits

  • Filipe Mendes for a superb first version of this repo, while working for SPMS, Shared Services for Ministry of Health (of Portugal). He kindly transferred this repo to me when he no longer had time to maintain it.
  • Daniel Leal, for a great PR.

nativescript-health-data's People

Contributors

brad avatar cjohn001 avatar danielgek avatar dmatora avatar eddyverbruggen avatar farfromrefug avatar filipemendes1994 avatar nunopedrosa avatar sebalopezz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nativescript-health-data's Issues

Support for biologicalSex and dateOfBirth would be awesome :)

Thanks for this great repo.
I was shortly able to get data for the supported data types like weight, height, steps etc.
I searched up a bit in the source code and saw that there are all types of data types listed.

It would be awesome if you could also implement biologicalSex and dateOfBirth to the allowed types to use.

Or am I missing something?
How could I get the data for biologicalSex and dateOfBirth in an NativeScript/Angular App on ios?

Best regards

Daniel

Request AndroidManifest.xml permissions

Request permissions for:
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_NETWORK_STATE
android.permission.GET_ACCOUNTS
android.permission.BODY_SENSORS

Support for prior iOS versions

Hi!
A few types in
https://github.com/EddyVerbruggen/nativescript-health-data/blob/master/src/health-data.ios.ts
are breaking compatibility with older iOS versions (plenty of devices running iOS 9.3.5...).

distanceSwimming: HKQuantityTypeIdentifierDistanceSwimming, // iOS 10.0+
distanceWheelChair: HKQuantityTypeIdentifierDistanceWheelchair, // iOS 10.0+
pushCount: HKQuantityTypeIdentifierPushCount, // iOS 10.0+
swimmingStrokeCount: HKQuantityTypeIdentifierSwimmingStrokeCount,  // iOS 10.0+
wheelchairUse: HKCharacteristicTypeIdentifierWheelchairUse,  // iOS 10.0+
mindfulSession: HKCategoryTypeIdentifierMindfulSession, //  iOS 10.0+

Not sure about the best way to deal with this...
Does nativescript have some elegant way to detect whether some functionality is available, or does it really have to be some iOS version check?
Something like:

  import * as platformModule from "tns-core-modules/platform";

  var sdkVer=  parseFloat(platformModule.device.sdkVersion);
  if (sdkVer >= 10 ) {
          .....
  }

Can't Run Demo on iOS

I'm trying to run demo-ng using 'tns run ios'. After git clone of the project I'm getting the follow with no other changes to the source code.

file:///app/app.component.js:4:41: JS ERROR Error: Could not find module 'nativescript-health-data'.

Any help is greatly appreciated. Thanks!

Plugin breaks debugger

After adding the plugin to my project the command tns debug android no longer works as expected.

My project builds and is installed but the debugger cannot connect, I get the message:

Unable to apply changes on device: YYYYYYY. Error is: The application XXXXXXXXX is not installed on device with identifier YYYYYYY.

When I remove the plugin with tns plugin remove nativescript-health-data and run tns debug android I get another error:

Where:
Build file '/ZZZZZZZZ/platforms/android/app/build.gradle' line: 234

What went wrong:
A problem occurred evaluating project ':app'.
/ZZZZZZZZ/node_modules/nativescript-health-data/package.json (No such file or directory)

I have to delete the platforms directory and run tns debug android to do a full rebuild and my debugging starts working again as before installing the plugin.

Has anyone else seen this? What could be causing this?
Is the plugin changing my package id? This is the only clue I get when searching the first error message.

Android Authorization issue application.android.currentContext is undefined

application.android.currentContext is undefined.

var application = require("tns-core-modules/application");

There might be a change with the object application.
application.android.currentContext is undefined while application.android.context defined and gives context.

Getting the context with the way below also solved the issue for me.

var utilsAd = require("utils/utils").ad;
utilsAd.getApplicationContext();

build failed when added to TNS project

error ourput:

Execution failed for task ':transformClassesWithJarMergingForF0F1F2F3F4F5F6F7F8F9F10Debug'.
> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/google/android/gms/internal/zzbvd.class

Is not working on Android

When running the App I get this error: "nativescript Program type already present: com.google.android.gms.auth.api.zza"

new HealthData() is preventing my app from starting

Hello I installed the plugin and this specific line is preventing my app from starting, it gets stuck on splash screen and nothing happens, it doesn't let me open the debugger and doesn't give any errors at all
(Android) didn't try on IOS

this.healthData = new HealthData();

If I comment this line, everything works as expected but I'm not able to use the plugin

tns info
โˆš Getting NativeScript components versions information...
โˆš Component nativescript has 5.1.1 version and is up to date.
โˆš Component tns-core-modules has 5.2.0-rc-2018-12-14-145545-01 version and is up to date.
โˆš Component tns-android has 5.1.0 version and is up to date.

Missing value

I wonder why I am the only person complaining about it, but plugin doesn't return value

Sleep

What about sleep support?

HealthConnect

Are there any attempts use the new HealthConnect api on android?

Authorization issue in Android

The below error is shown on running this health-data plugin. How to solve this issue?
Request auth error: Error: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
com.google.android.gms.auth.api.signin.internal.zzo.zzbp(Unknown Source)
com.google.android.gms.auth.api.signin.GoogleSignIn.getLastSignedInAccount(Unknown Source)
com.tns.Runtime.callJSMethodNative(Native Method)
com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1209)
com.tns.Runtime.callJSMethodImpl(Runtime.java:1096)
com.tns.Runtime.callJSMethod(Runtime.java:1083)
com.tns.Runtime.callJSMethod(Runtime.java:1063)
com.tns.Runtime.callJSMethod(Runtime.java:1055)
com.tns.gen.java.lang.Object_vendor_143618_32_ClickListenerImpl.onClick(Object_vendor_143618_32_ClickListenerImpl.java:18)
android.view.View.performClick(View.java:5612)
android.view.View$PerformClick.run(View.java:22285)
android.os.Handler.handleCallback(Handler.java:751)
android.os.Handler.dispatchMessage(Handler.java:95)
android.os.Looper.loop(Looper.java:154)
android.app.ActivityThread.main(ActivityThread.java:6123)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

java.lang.NullPointerException with createClient()

I'm getting this error when trying to use createClient() in my application.
I use nativescript-vue with tralves' nativescript-vue-webpack-template.
Looks like it is related to the android context being undefined, but i don't know where to use it ?

Error: java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.Looper android.content.Context.getMainLooper()' on a null object reference

Authentication page not load on android

When I choose the account to log in and authenticate on Android, a new white rectangle opens with google's loading circle and then the upload circle loops.

thank you in advance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.