lucaspbordignon / rn-apple-healthkit

A React Native package for interacting with Apple HealthKit
https://www.npmjs.com/package/react-native-health
MIT License
519 stars 296 forks source link

[RFC] Gathering/observing data in the background and foreground #65

Open JulianKingman opened 5 years ago

JulianKingman commented 5 years ago

This feature will add background observers for an arbitrary number of types of data. Below are my notes and ideas for how to implement this. Your comments and ideas are welcome.

I propose the following:

  1. The app can be initialized with an additional option: observe E.g:
    let options = {
    permissions: {
    read: ["Height", "Weight", "StepCount", "DateOfBirth", "BodyMassIndex"],
    write: ["Weight", "StepCount", "BodyMassIndex"],
    },
    observers: [
    { type: "StepCount" },
    { type: "Weight" }
    ]
    };
    AppleHealthKit.initHealthKit(options);
  2. Observers (HKObserverQuery) run in the background, saving data to AsyncStorage, perhaps to the RNAppleHealthkit key. To retrieve it later you could run:
    const healthKitData = await AsyncStorage.getItem('RNAppleHealthkit');
    const steps = healthKitData.StepCount;
    // `steps` might contains something like:
    // [
    //    { date: '1 1 2019', value: 10000}
    // ]
  3. To make use of this most effectively, use react-native-background-fetch

    
    BackgroundFetch.configure({
    minimumFetchInterval: 15, // <-- minutes (15 is minimum allowed)
    }, () => {
    
    // Retrieve data
    const healthKitData = await AsyncStorage.getItem('RNAppleHealthkit');
    
    // Stop if there isn't any
    if (!healthKitData)  {
    BackgroundFetch.finish(BackgroundFetch.FETCH_RESULT_NO_DATA);
    }
    
    // Get steps
    const steps = healthKitData.StepCount;
    
    // Upload them
    await fetch('http://placetouploadsteps.com/steps', { method: 'POST', body: JSON.stringify({ steps });
    
    // No need to waste storage
    AsyncStorage.removeItem('RNAppleHealthkit');
    
    // Finish
    BackgroundFetch.finish(BackgroundFetch.FETCH_RESULT_NEW_DATA);

}, (error) => { console.log("[js] RNBackgroundFetch failed to start"); });

4. Event triggers still work, if your app is in the foreground (but with a simpler API)
Per https://github.com/terrillo/rn-apple-healthkit/blob/master/docs/initStepCountObserver().md
```javascript
import { EventEmitter } from 'rn-apple-healthkit';
EventEmitter.addListener(
  'change:StepCount',
  (evt) => {
    const steps = evt.data;
  }
);
EJohnF commented 5 years ago

I don't have time to find related page in healthKit docs, but I remember that it isn't possible to use react-native-background-fetch to get healthKit data while app in Background. We have to use a built-in HK mechanism for it.

JulianKingman commented 5 years ago

Yes, that’s true of getting the data. That’s why in step 2 it retrieves the data in the background (using healthkit’s HKOvserverQuery, the built-in mechanism) and stores it to AsyncStorage, because (I’m pretty sure) AsyncStorage is available with background fetch.

adcuz commented 5 years ago

AFAIK background fetch doesn't run if the device is locked.