health_kit_reporter 2.3.0 copy "health_kit_reporter: ^2.3.0" to clipboard
health_kit_reporter: ^2.3.0 copied to clipboard

PlatformiOS

Helps to write or read data from Apple Health via HealthKit framework.

example/lib/main.dart

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:health_kit_reporter/health_kit_reporter.dart';
import 'package:health_kit_reporter/model/payload/category.dart';
import 'package:health_kit_reporter/model/payload/correlation.dart';
import 'package:health_kit_reporter/model/payload/date_components.dart';
import 'package:health_kit_reporter/model/payload/device.dart';
import 'package:health_kit_reporter/model/payload/preferred_unit.dart';
import 'package:health_kit_reporter/model/payload/quantity.dart';
import 'package:health_kit_reporter/model/payload/source.dart';
import 'package:health_kit_reporter/model/payload/source_revision.dart';
import 'package:health_kit_reporter/model/payload/workout.dart';
import 'package:health_kit_reporter/model/payload/workout_activity_type.dart';
import 'package:health_kit_reporter/model/payload/workout_event.dart';
import 'package:health_kit_reporter/model/payload/workout_event_type.dart';
import 'package:health_kit_reporter/model/predicate.dart';
import 'package:health_kit_reporter/model/type/activity_summary_type.dart';
import 'package:health_kit_reporter/model/type/category_type.dart';
import 'package:health_kit_reporter/model/type/characteristic_type.dart';
import 'package:health_kit_reporter/model/type/clinical_type.dart';
import 'package:health_kit_reporter/model/type/correlation_type.dart';
import 'package:health_kit_reporter/model/type/electrocardiogram_type.dart';
import 'package:health_kit_reporter/model/type/quantity_type.dart';
import 'package:health_kit_reporter/model/type/series_type.dart';
import 'package:health_kit_reporter/model/type/workout_type.dart';
import 'package:health_kit_reporter/model/update_frequency.dart';

void main() {
  runApp(MyApp());
}

mixin HealthKitReporterMixin {
  Predicate get predicate => Predicate(
        DateTime.now().add(Duration(days: -365)),
        DateTime.now(),
      );

  Device get device => Device(
        'FlutterTracker',
        'kvs',
        'T-800',
        '3',
        '3.0',
        '1.1.1',
        'kvs.sample.app',
        '444-888-555',
      );

  Source get source => Source(
        'myApp',
        'com.kvs.health_kit_reporter_example',
      );

  OperatingSystem get operatingSystem => OperatingSystem(
        1,
        2,
        3,
      );

  SourceRevision get sourceRevision => SourceRevision(
        source,
        '5',
        'fit',
        '4',
        operatingSystem,
      );
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

  @override
  void initState() {
    super.initState();
    final initializationSettingsIOs = IOSInitializationSettings();
    final initSettings = InitializationSettings(iOS: initializationSettingsIOs);
    _flutterLocalNotificationsPlugin.initialize(initSettings,
        onSelectNotification: (string) {
      print(string);
      return Future.value(string);
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 4,
        child: Scaffold(
          appBar: AppBar(
            title: Text('Health Kit Reporter'),
            actions: [
              IconButton(
                onPressed: () => _authorize(),
                icon: Icon(Icons.login),
                tooltip: 'Authorizes HealthKit',
              ),
              IconButton(
                onPressed: () => _authorizeClinicalRecords(),
                icon: Icon(Icons.login),
                tooltip: 'Authorizes clinical records',
                color: Colors.blue,
              ),
            ],
            bottom: TabBar(
              tabs: [
                Tab(
                  icon: Icon(Icons.book),
                  text: 'Read',
                ),
                Tab(
                  icon: Icon(Icons.edit),
                  text: 'Write',
                ),
                Tab(
                  icon: Icon(Icons.monitor),
                  text: 'Observe',
                ),
                Tab(
                  icon: Icon(Icons.delete),
                  text: 'Delete',
                ),
              ],
            ),
          ),
          body: TabBarView(
            children: [
              _ReadView(),
              _WriteView(),
              _ObserveView(
                flutterLocalNotificationsPlugin:
                    _flutterLocalNotificationsPlugin,
              ),
              _DeleteView(),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _authorize() async {
    try {
      final readTypes = <String>[];
      readTypes.addAll(ActivitySummaryType.values.map((e) => e.identifier));
      readTypes.addAll(CategoryType.values.map((e) => e.identifier));
      readTypes.addAll(CharacteristicType.values.map((e) => e.identifier));
      readTypes.addAll(QuantityType.values.map((e) => e.identifier));
      readTypes.addAll(WorkoutType.values.map((e) => e.identifier));
      readTypes.addAll(SeriesType.values.map((e) => e.identifier));
      readTypes.addAll(ElectrocardiogramType.values.map((e) => e.identifier));
      final writeTypes = <String>[
        QuantityType.stepCount.identifier,
        WorkoutType.workoutType.identifier,
        CategoryType.sleepAnalysis.identifier,
        CategoryType.mindfulSession.identifier,
        QuantityType.bloodPressureDiastolic.identifier,
        QuantityType.bloodPressureSystolic.identifier,
        //CorrelationType.bloodPressure.identifier,
      ];
      final isRequested =
          await HealthKitReporter.requestAuthorization(readTypes, writeTypes);
      print('isRequested auth: $isRequested');
    } catch (e) {
      print(e);
    }
  }

  Future<void> _authorizeClinicalRecords() async {
    try {
      final readTypes =
          ClinicalType.values.map((type) => type.identifier).toList();
      final isRequested =
          await HealthKitReporter.requestAuthorization(readTypes, []);
      print('isRequested auth: $isRequested');
    } catch (e) {
      print(e);
    }
  }
}

class _ReadView extends StatelessWidget with HealthKitReporterMixin {
  const _ReadView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        TextButton(
            onPressed: () {
              handleQuantitySamples();
            },
            child: Text('preferredUnit:quantity:statistics')),
        TextButton(
            onPressed: () {
              queryCharacteristics();
            },
            child: Text('characteristics')),
        TextButton(
            onPressed: () {
              queryClinicalRecords();
            },
            child: Text('Clinical Records')),
        TextButton(
            onPressed: () {
              queryCategory();
            },
            child: Text('categories')),
        TextButton(
            onPressed: () {
              queryWorkout();
            },
            child: Text('workouts')),
        TextButton(
            onPressed: () {
              querySamples();
            },
            child: Text('samples')),
        TextButton(
            onPressed: () {
              queryHeartbeatSeries();
            },
            child: Text('heartbeatSeriesQuery')),
        TextButton(
            onPressed: () {
              workoutRouteQuery();
            },
            child: Text('workoutRouteQuery')),
        TextButton(
            onPressed: () {
              querySources();
            },
            child: Text('sources')),
        TextButton(
            onPressed: () {
              queryCorrelations();
            },
            child: Text('correlations')),
        TextButton(
            onPressed: () {
              queryElectrocardiograms();
            },
            child: Text('electrocardiograms')),
        TextButton(
            onPressed: () {
              queryActivitySummary();
            },
            child: Text('activitySummary')),
        TextButton(
            onPressed: () {
              multipleQuery();
            },
            child: Text('multipleQuery')),
      ],
    );
  }

  void multipleQuery() async {
    final prefUnits =
        await HealthKitReporter.preferredUnits([QuantityType.heartRate]);
    final hrUnits = prefUnits.first.unit;

    final now = DateTime.now();

    for (int _ in List.generate(10, (index) => index + 1)) {
      final hbQuery = await HealthKitReporter.quantityQuery(
          QuantityType.heartRate,
          hrUnits,
          Predicate(now.subtract(Duration(seconds: 120 * 60 * 24)), now));
      print(hbQuery.map((e) => e.harmonized.value));
    }
  }

  void querySamples() async {
    try {
      final samples = await HealthKitReporter.sampleQuery(
          QuantityType.stepCount.identifier, predicate);
      print('samples: ${samples.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }

  void queryClinicalRecords() async {
    try {
      final samples = await HealthKitReporter.sampleQuery(
        ClinicalType.allergyRecord.identifier,
        Predicate(
          DateTime.now().add(Duration(days: -7000)),
          DateTime.now(),
        ),
      );
      print('clinicalRecords: ${samples.map((e) => e.map).toList()}');
    } catch (e, stackTrace) {
      print("$e\n$stackTrace");
    }
  }

  void queryCategory() async {
    try {
      final categories = await HealthKitReporter.categoryQuery(
          CategoryType.sleepAnalysis, predicate);
      print('categories: ${categories.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }

  void queryWorkout() async {
    try {
      final workouts = await HealthKitReporter.workoutQuery(predicate);
      print('workouts: ${workouts.map((e) => e.map).toList()}');
      for (final q in workouts) {
        print('q: ${json.encode(q.map)}');
      }
    } catch (e) {
      print(e);
    }
  }

  void queryHeartbeatSeries() async {
    try {
      final series = await HealthKitReporter.heartbeatSeriesQuery(predicate);
      print('heartbeatSeries: ${series.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }

  void workoutRouteQuery() async {
    try {
      final series = await HealthKitReporter.workoutRouteQuery(predicate);
      print('workoutRoutes: ${series.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }

  void queryCharacteristics() async {
    try {
      final characteristics = await HealthKitReporter.characteristicsQuery();
      print('characteristics: ${characteristics.map}');
    } catch (e) {
      print(e);
    }
  }

  void handleQuantitySamples() async {
    try {
      final preferredUnits = await HealthKitReporter.preferredUnits([
        QuantityType.stepCount,
      ]);
      preferredUnits.forEach((preferredUnit) async {
        final identifier = preferredUnit.identifier;
        final unit = preferredUnit.unit;
        print('preferredUnit: ${preferredUnit.map}');
        final type = QuantityTypeFactory.from(identifier);
        try {
          final quantities =
              await HealthKitReporter.quantityQuery(type, unit, predicate);
          print('quantity: ${quantities.map((e) => e.map).toList()}');
          final statistics =
              await HealthKitReporter.statisticsQuery(type, unit, predicate);
          print('statistics: ${statistics.map}');
        } catch (e) {
          print(e);
        }
      });
    } catch (e) {
      print(e);
    }
  }

  void queryActivitySummary() async {
    try {
      final activitySummary =
          await HealthKitReporter.queryActivitySummary(predicate);
      print('activitySummary: ${activitySummary.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }

  void queryElectrocardiograms() async {
    try {
      final electrocardiograms = await HealthKitReporter.electrocardiogramQuery(
          predicate,
          withVoltageMeasurements: true);
      print(
          'electrocardiograms: ${electrocardiograms.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }

  void queryCorrelations() async {
    try {
      final correlations = await HealthKitReporter.correlationQuery(
          CorrelationType.bloodPressure.identifier, predicate);
      print('correlations: ${correlations.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }

  void querySources() async {
    try {
      final sources = await HealthKitReporter.sourceQuery(
          QuantityType.stepCount.identifier, predicate);
      print('sources: ${sources.map((e) => e.map).toList()}');
    } catch (e) {
      print(e);
    }
  }
}

class _WriteView extends StatelessWidget with HealthKitReporterMixin {
  const _WriteView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        TextButton(
          onPressed: () {
            saveWorkout();
          },
          child: Text('saveWorkout'),
        ),
        TextButton(
          onPressed: () {
            saveSteps();
          },
          child: Text('saveSteps'),
        ),
        TextButton(
          onPressed: () {
            saveMindfulMinutes();
          },
          child: Text('saveMindfulMinutes'),
        ),
        TextButton(
          onPressed: () {
            saveBloodPressureCorrelation();
          },
          child: Text('saveBloodPressureCorrelation'),
        ),
      ],
    );
  }

  void saveSteps() async {
    try {
      final canWrite = await HealthKitReporter.isAuthorizedToWrite(
          QuantityType.stepCount.identifier);
      if (canWrite) {
        final now = DateTime.now();
        final minuteAgo = now.add(Duration(minutes: -1));
        final harmonized = QuantityHarmonized(100, 'count', null);
        final steps = Quantity(
            'testStepsUUID',
            QuantityType.stepCount.identifier,
            minuteAgo.millisecondsSinceEpoch,
            now.millisecondsSinceEpoch,
            device,
            sourceRevision,
            harmonized);
        print('try to save: ${steps.map}');
        final saved = await HealthKitReporter.save(steps);
        print('stepsSaved: $saved');
      } else {
        print('error canWrite steps: $canWrite');
      }
    } catch (e) {
      print(e);
    }
  }

  void saveWorkout() async {
    try {
      final canWrite = await HealthKitReporter.isAuthorizedToWrite(
          WorkoutType.workoutType.identifier);
      if (canWrite) {
        final harmonized = WorkoutHarmonized(
          WorkoutActivityType.badminton,
          1.2,
          'kcal',
          123,
          'm',
          0,
          'count',
          0,
          'count',
          null,
        );
        final now = DateTime.now();
        final duration = 60;
        final eventHarmonized = WorkoutEventHarmonized(WorkoutEventType.pause);
        final events = [
          WorkoutEvent(
            now.millisecondsSinceEpoch,
            now.millisecondsSinceEpoch,
            duration,
            eventHarmonized,
          )
        ];
        final minuteAgo = now.add(Duration(seconds: -duration));
        final workout = Workout(
          'testWorkoutUUID',
          'basketball',
          minuteAgo.millisecondsSinceEpoch,
          now.millisecondsSinceEpoch,
          device,
          sourceRevision,
          harmonized,
          duration,
          events,
        );
        print('try to save: ${workout.map}');
        final saved = await HealthKitReporter.save(workout);
        print('workoutSaved: $saved');
      } else {
        print('error canWrite workout: $canWrite');
      }
    } catch (e) {
      print(e);
    }
  }

  void saveMindfulMinutes() async {
    try {
      final canWrite = await HealthKitReporter.isAuthorizedToWrite(
          CategoryType.mindfulSession.identifier);
      if (canWrite) {
        final now = DateTime.now();
        final minuteAgo = now.add(Duration(minutes: -1));
        final harmonized = CategoryHarmonized(
          0,
          'HKCategoryValue',
          'Not Aplicable',
          {},
        );
        final mindfulMinutes = Category(
          'testMindfulMinutesUUID',
          CategoryType.mindfulSession.identifier,
          minuteAgo.millisecondsSinceEpoch,
          now.millisecondsSinceEpoch,
          device,
          sourceRevision,
          harmonized,
        );
        print('try to save: ${mindfulMinutes.map}');
        final saved = await HealthKitReporter.save(mindfulMinutes);
        print('mindfulMinutesSaved: $saved');
      } else {
        print('error canWrite mindfulMinutes: $canWrite');
      }
    } catch (e) {
      print(e);
    }
  }

  void saveBloodPressureCorrelation() async {
    try {
      final now = DateTime.now();
      final minuteAgo = now.add(Duration(minutes: -1));
      final sys = Quantity(
          'testSysUUID234',
          QuantityType.bloodPressureSystolic.identifier,
          minuteAgo.millisecondsSinceEpoch,
          now.millisecondsSinceEpoch,
          device,
          sourceRevision,
          QuantityHarmonized(123, 'mmHg', null));
      final dia = Quantity(
          'testDiaUUID456',
          QuantityType.bloodPressureDiastolic.identifier,
          minuteAgo.millisecondsSinceEpoch,
          now.millisecondsSinceEpoch,
          device,
          sourceRevision,
          QuantityHarmonized(89, 'mmHg', null));
      final correlationJarmonized = CorrelationHarmonized([sys, dia], [], null);
      final correlation = Correlation(
          'test',
          CorrelationType.bloodPressure.identifier,
          minuteAgo.millisecondsSinceEpoch,
          now.millisecondsSinceEpoch,
          device,
          sourceRevision,
          correlationJarmonized);
      final saved = await HealthKitReporter.save(correlation);
      print('BloodPressureCorrelationSaved: $saved');
    } catch (e) {
      print(e);
    }
  }
}

class _ObserveView extends StatelessWidget with HealthKitReporterMixin {
  const _ObserveView({
    Key? key,
    required this.flutterLocalNotificationsPlugin,
  }) : super(key: key);

  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        TextButton(
            onPressed: () {
              observerQuery([
                QuantityType.stepCount.identifier,
                QuantityType.heartRate.identifier,
              ]);
            },
            child: Text('observerQuery - STEPS and HR')),
        TextButton(
            onPressed: () {
              anchoredObjectQuery([
                QuantityType.stepCount.identifier,
                QuantityType.heartRate.identifier,
              ]);
            },
            child: Text('anchoredObjectQuery - STEPS and HR')),
        TextButton(
            onPressed: () {
              queryActivitySummaryUpdates();
            },
            child: Text('queryActivitySummaryUpdates')),
        TextButton(
            onPressed: () {
              statisticsCollectionQuery();
            },
            child: Text('statisticsCollectionQuery')),
      ],
    );
  }

  void observerQuery(List<String> identifiers) async {
    try {
      final sub = HealthKitReporter.observerQuery(identifiers, null,
          onUpdate: (identifier) async {
        print('Updates for observerQuerySub - $identifier');
        print(identifier);
        final iOSDetails = IOSNotificationDetails();
        final details = NotificationDetails(iOS: iOSDetails);
        await flutterLocalNotificationsPlugin.show(
            0, 'Observer', identifier, details);
      });
      print('$identifiers observerQuerySub: $sub');
      for (final identifier in identifiers) {
        final isSet = await HealthKitReporter.enableBackgroundDelivery(
            identifier, UpdateFrequency.immediate);
        print('$identifier enableBackgroundDelivery: $isSet');
      }
    } catch (e) {
      print(e);
    }
  }

  void anchoredObjectQuery(List<String> identifiers) {
    try {
      final sub = HealthKitReporter.anchoredObjectQuery(identifiers, predicate,
          onUpdate: (samples, deletedObjects) {
        print('Updates for anchoredObjectQuerySub');
        print(samples.map((e) => e.map).toList());
        print(deletedObjects.map((e) => e.map).toList());
      });
      print('$identifiers anchoredObjectQuerySub: $sub');
    } catch (e) {
      print(e);
    }
  }

  void queryActivitySummaryUpdates() {
    try {
      final sub = HealthKitReporter.queryActivitySummaryUpdates(predicate,
          onUpdate: (samples) {
        print('Updates for activitySummaryUpdatesSub');
        print(samples.map((e) => e.map).toList());
      });
      print('activitySummaryUpdatesSub: $sub');
    } catch (e) {
      print(e);
    }
  }

  void statisticsCollectionQuery() {
    try {
      final anchorDate = DateTime.utc(2020, 2, 1, 12, 30, 30);
      final enumerateFrom = DateTime.utc(2020, 3, 1, 12, 30, 30);
      final enumerateTo = DateTime.utc(2020, 12, 31, 12, 30, 30);
      final intervalComponents = DateComponents(month: 1);
      final sub = HealthKitReporter.statisticsCollectionQuery(
        [
          PreferredUnit(
            QuantityType.stepCount.identifier,
            'count',
          ),
        ],
        predicate,
        anchorDate,
        enumerateFrom,
        enumerateTo,
        intervalComponents,
        onUpdate: (statistics) {
          print('Updates for statisticsCollectionQuerySub');
          print(statistics.map);
        },
      );
      print('statisticsCollectionQuery: $sub');
    } catch (e) {
      print(e);
    }
  }
}

class _DeleteView extends StatelessWidget with HealthKitReporterMixin {
  const _DeleteView({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView(
      children: [
        TextButton(
            onPressed: () {
              deleteSteps();
            },
            child: Text('deleteSteps')),
      ],
    );
  }

  void deleteSteps() async {
    try {
      final map = await HealthKitReporter.deleteObjects(
          QuantityType.stepCount.identifier,
          Predicate(
            DateTime.now().add(Duration(days: -1)),
            DateTime.now(),
          ));
      print(map);
    } catch (e) {
      print(e);
    }
  }
}
56
likes
150
points
2.66k
downloads

Publisher

unverified uploader

Weekly Downloads

Helps to write or read data from Apple Health via HealthKit framework.

Repository (GitHub)
Contributing

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on health_kit_reporter