{"id":15527696,"url":"https://github.com/kvs-coder/health_kit_reporter","last_synced_at":"2026-01-11T04:52:39.442Z","repository":{"id":38128417,"uuid":"312024020","full_name":"kvs-coder/health_kit_reporter","owner":"kvs-coder","description":"A Flutter wrapper for the HealthKitReporter library","archived":false,"fork":false,"pushed_at":"2024-12-12T19:12:27.000Z","size":337,"stargazers_count":38,"open_issues_count":30,"forks_count":39,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-31T12:08:01.990Z","etag":null,"topics":["apple","apple-health","cocoapods","dart","flutter","health","healthkit","ios","swift"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/health_kit_reporter","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kvs-coder.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["VictorKachalov"]}},"created_at":"2020-11-11T16:17:04.000Z","updated_at":"2024-12-14T15:36:25.000Z","dependencies_parsed_at":"2024-02-21T19:28:28.366Z","dependency_job_id":"f5ba7a70-a460-4d12-9911-2575ec1dd238","html_url":"https://github.com/kvs-coder/health_kit_reporter","commit_stats":{"total_commits":128,"total_committers":10,"mean_commits":12.8,"dds":0.546875,"last_synced_commit":"4503566060677952669341cf9cbbae048e453874"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvs-coder%2Fhealth_kit_reporter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvs-coder%2Fhealth_kit_reporter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvs-coder%2Fhealth_kit_reporter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kvs-coder%2Fhealth_kit_reporter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kvs-coder","download_url":"https://codeload.github.com/kvs-coder/health_kit_reporter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247666015,"owners_count":20975788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apple","apple-health","cocoapods","dart","flutter","health","healthkit","ios","swift"],"created_at":"2024-10-02T11:08:34.558Z","updated_at":"2026-01-11T04:52:39.412Z","avatar_url":"https://github.com/kvs-coder.png","language":"Dart","funding_links":["https://github.com/sponsors/VictorKachalov"],"categories":[],"sub_categories":[],"readme":"# health_kit_reporter\n\n## Features\n\nA Flutter wrapper for [HealthKitReporter](https://cocoapods.org/pods/HealthKitReporter)\n\n- **iOS only usage**, since AppleHealth is not available on Android devices.\n\n- The library supports reading, writing, observing values from HealthKit repository.\n\n- All methods from **HealthKitReporter** original library are wrapped in Method and Event channels provided by **FlutterPlugin**\n\n## Getting Started\n\n- Go inside pubspec.yaml file\n- Add this to your package's pubspec.yaml file:\n``` Dart\ndependencies:\n     health_kit_reporter: ^3.1.0\n```\n\n**TEMPORARY:** Until the CocoaPods library this plugin relies on is upgraded to version 3.1.0 it is compulsory to modify your `ios/Podfile` like so:\n```\ntarget 'Runner' do\n  use_frameworks!\n  use_modular_headers!\n  ...\n  # TODO: This is temporary, until the PR to upgrade HealthKitReporter CocoaPods library to version 3.1.0 gets merged.\n  pod 'HealthKitReporter', :git =\u003e 'https://github.com/quentinleguennec/HealthKitReporter', :branch =\u003e 'feature_add_clinical_records', :tag =\u003e '3.1.0'\n  ...\n  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))\nend\n```\n\n- Get dependencies\n\n``` shell\nflutter pub get\n``` \n\n## How to use\n\n### Preparation\n\nIn Xcode, go to Runner \u003e Signing and Capabilities and add the entitlement for Health Kit.\nIf you want to read Clinical Records then also check \"Clinical Health Records\" under Health Kit.\n\n***NOTE:*** *You can only tick the \"Clinical Health Records\" checkmark if your development team has a paid Apple developer subscription. To test on a real device, or to publish your application, you will need a paid Apple subscription, but you can still test on the iOS simulator without a subscription by setting the Development Team to None.*\n\n\nThen in your app's info.plist file add permissions:\n\n```xml\n\u003ckey\u003eNSHealthShareUsageDescription\u003c/key\u003e\n\u003cstring\u003eWHY_YOU_NEED_TO_SHARE_DATA\u003c/string\u003e\n\u003ckey\u003eNSHealthUpdateUsageDescription\u003c/key\u003e\n\u003cstring\u003eWHY_YOU_NEED_TO_USE_DATA\u003c/string\u003e\n```\n\nIf you plan to use **WorkoutRoute** **Series** please provide additionally CoreLocation permissions:\n\n```xml\n\u003ckey\u003eNSLocationAlwaysAndWhenInUseUsageDescription\u003c/key\u003e\n\u003cstring\u003eWHY_YOU_NEED_TO_ALWAYS_SHARE_LOCATION\u003c/string\u003e\n\u003ckey\u003eNSLocationWhenInUseUsageDescription\u003c/key\u003e\n\u003cstring\u003eWHY_YOU_NEED_TO_SHARE_LOCATION\u003c/string\u003e\n```\n\nIf you plan to read **Clinical Records** please provide additionally:\n\n```xml\n\u003ckey\u003eNSHealthClinicalHealthRecordsShareUsageDescription\u003c/key\u003e\n\u003cstring\u003eWHY_YOU_NEED_TO_SHARE_DATA\u003c/string\u003e\n```\n\n### Common usage\n\nYou simply call a \u003ci\u003eHealthKitReporter\u003c/i\u003e methods surrounding by try catch blocks. \n\nWarning: If Apple Health is not supported by the device (i.e. iPad) the error result will occur.\n\nThe reporter supports following operations with **HealthKit**:\n* accessing to permissions\n* reading data \n* writing data \n* observing data changes\n\nIf you want to read, write data or observe data changes, you always need to be sure that the data types are authorized to be read/written/observed. In that case call authorization method and await for the result telling about the presentation of the authorization window. Notice that Apple Health Kit will show this window only once during the whole time app is installed on the device, in this case if some types were denied to be read or written, user should manually allow this in Apple Health App.\n\n### Requesting permissions\n\nAs was mentioned above, you need to provide HealthKit entitlements and extend the info.plist file of your App with HealthKit permissions. (see [Preparation](#preparation))\n\nCall the method: **requestAuthorization**\n\nFor this method you need to specify the strings identifiers of types you want to get access.\n\nIn the example, we want to read data for all **QuantityTypes** and write data for **QuantityType.stepCount**:\n```dart\nFuture\u003cvoid\u003e requestAuthorization() async {\n  try {\n    final readTypes = QuantityType.values.map((e) =\u003e e.identifier).toList();\n    final writeTypes = \u003cString\u003e[\n      QuantityType.stepCount.identifier,\n    ];\n    final isRequested =\n        await HealthKitReporter.requestAuthorization(readTypes, writeTypes);\n    if (isRequested) {\n      // read data/write data/observe data\n    }\n  } catch (e) {\n    print(e);\n  }\n}\n```\n\n**Warning: Please keep in mind, Apple Health Kit does not let anyone to know if reading permissions were provided.**\n\nUser can decline some of the reading permissions, but the result of the function will still be **true**.\nSee [Authorization status](https://developer.apple.com/documentation/healthkit/hkhealthstore/1614154-authorizationstatus) \n\n\n### Reading Data\n\nAfter authorization, you can try to start reading data.\n\n```dart\nFuture\u003cvoid\u003e read(bool isRequested) async {\n  if (isRequested) {\n    final preferredUnits =\n        await HealthKitReporter.preferredUnits([QuantityType.stepCount]);\n    for (final preferredUnit in preferredUnits) {\n      print('preferredUnit: ${preferredUnit.identifier}');\n      final type = QuantityTypeFactory.from(preferredUnit.identifier);\n      final quantities = await HealthKitReporter.quantityQuery(\n        type,\n        preferredUnit.unit,\n        _predicate,\n      );\n      print('quantity: ${quantities.map((e) =\u003e e.map).toList()}');\n      final statistics = await HealthKitReporter.statisticsQuery(\n        type,\n        preferredUnit.unit,\n        _predicate,\n      );\n      print('statistics: ${statistics.map}');\n    }\n    final characteristics = await HealthKitReporter.characteristicsQuery();\n    print('characteristics: ${characteristics.map}');\n    final categories = await HealthKitReporter.categoryQuery(\n      CategoryType.sleepAnalysis,\n      _predicate,\n    );\n    print('categories: ${categories.map((e) =\u003e e.map).toList()}');\n    final samples = await HealthKitReporter.sampleQuery(\n      QuantityType.stepCount.identifier,\n      _predicate,\n    );\n    print('samples: ${samples.map((e) =\u003e e.map).toList()}');\n    final sources = await HealthKitReporter.sourceQuery(\n      QuantityType.stepCount.identifier,\n      _predicate,\n    );\n    print('sources: ${sources.map((e) =\u003e e.map).toList()}');\n    final correlations = await HealthKitReporter.correlationQuery(\n      CorrelationType.bloodPressure.identifier,\n      _predicate,\n    );\n    print('correlations: ${correlations.map((e) =\u003e e.map).toList()}');\n  } else {\n    print('error isRequested: $isRequested');\n  }\n}\n```\n\nIn the example above, there is a call of **preferredUnits** function. You can provide identifiers to get preferred units for them and eventually receive properly calculated values from queries. The units will be chosen automatically based on you current localization. This is only required for **QuantityTypes**. If you will try to provide invalid unit for a type, you will get an error.\n\nThe usage of **sampleQuery** for quantity types will return nearly the same result as **quantityQuery**, but the units for the values will be used according to SI, while **quantityQuery** together with **preferredUnits** will handle values units according to thee current localization.\n\n### Writing Data\n\n***NOTE:*** *Clinical Records are read only, Health Kit does not allow writing any data to Clinical Records.*\n\nBefore writing data, you may need to check if writing is allowed by calling **isAuthorizedToWrite**.\n\nIf it is ok to write, you need to create a **Sample** object and call a **save** method.\n\n```dart\nfinal _device = Device(\n    'FlutterTracker',\n    'kvs',\n    'T-800',\n    '3',\n    '3.0',\n    '1.1.1',\n    'kvs.sample.app',\n    '444-888-555',\n  );\nfinal _source = Source(\n    'myApp',\n    'com.kvs.health_kit_reporter_example',\n  );\nfinal _operatingSystem = OperatingSystem(\n    1,\n    2,\n    3,\n  );\n\nSourceRevision get _sourceRevision =\u003e SourceRevision(\n    _source,\n   '5',\n   'fit',\n   '4',\n   _operatingSystem,\n  );\n\nvoid saveSteps() async {\n  try {\n    final canWrite = await HealthKitReporter.isAuthorizedToWrite(\n        QuantityType.stepCount.identifier);\n    if (canWrite) {\n      final now = DateTime.now();\n      final minuteAgo = now.add(Duration(minutes: -1));\n      final harmonized = QuantityHarmonized(100, 'count', null);\n      final steps = Quantity(\n          'testStepsUUID',\n          QuantityType.stepCount.identifier,\n          minuteAgo.millisecondsSinceEpoch,\n          now.millisecondsSinceEpoch,\n          _device,\n          _sourceRevision,\n          harmonized);\n      print('try to save: ${steps.map}');\n      final saved = await HealthKitReporter.save(steps);\n      print('stepsSaved: $saved');\n    } else {\n      print('error canWrite steps: $canWrite');\n    }\n  } catch (e) {\n    print(e);\n  }\n}\n```\n\n**Recommendation: As well as for reading, here will better as well to call preferredUnits first, to know what unit is valid for a type.**\n**Please see [HKUnit.init](https://developer.apple.com/documentation/healthkit/hkunit/1615733-init/)**\n\n**Warning: PLease be sure to provide valid values for the appropriate types. For example, HealthKit will not allow to save Quantity value for the QuantityType.stepCount if the value is 0**\n\n## Observing Data\n\nIf you want to know, that something was changed in HealthKit, you can observe the repository.\n\nTry simple **observerQuery** to get notifications if something is changed.\n\nThis call is a subscription for EventChannel of the plugin, so don't forget to cancel it as soon as you don't need it anymore.\n\n```dart\n Future\u003cvoid\u003e observerQuery() async {\n  final identifier = QuantityType.stepCount.identifier;\n  final sub = HealthKitReporter.observerQuery(\n    [identifier],\n    _predicate,\n    onUpdate: (identifier) async {\n      print('Updates for observerQuerySub');\n      print(identifier);\n    },\n  );\n  print('observerQuerySub: $sub');\n  final isSet = await HealthKitReporter.enableBackgroundDelivery(\n    identifier,\n    UpdateFrequency.immediate,\n  );\n  print('enableBackgroundDelivery: $isSet');\n}\n```\n\nAccording to [Observing Query](https://developer.apple.com/documentation/healthkit/hkobserverquery) and [Background Delivery](https://developer.apple.com/documentation/healthkit/hkhealthstore/1614175-enablebackgrounddelivery)\nyou might create an App which will be called every time by HealthKit, even if the app is in background, to notify, that some data was changed in HealthKit depending on frequency. But keep in mind that sometimes the desired frequency you set cannot be fulfilled by HealthKit. \n\nTo receive notifications when the app is killed by the system or in background:\n- provide an additional capability **Background Mode** and select **Background fetch**\n- with calling **observerQuery**, you need to call **enableBackgroundDelivery** function as well\n\nAs a recommendation set up the subscription inside **initState** or **build** methods of your widget or as more preferred in **main** function of your app.\n\nIf you want to stop observation, you need to:\n- remove the subscription for **observerQuery**\n- call **disableBackgroundDelivery** or **disableAllBackgroundDelivery**\n\n## Requirements\nThe library supports minimum iOS 11.\nSome features like **HeartbeatSeries** are available only starting with iOS 13.0 and like **Electrocardiogramm** starting with iOS 14.0.\nClinical Records are available only starting with iOS 12.0.\n\n## License\nUnder \u003ca href=https://github.com/VictorKachalov/localized/blob/master/LICENSE\u003eMIT License\u003c/a\u003e\n\n## Sponsorhip\nIf you think that my repo helped you to solve the issues you struggle with, please don't be shy and sponsor :-)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkvs-coder%2Fhealth_kit_reporter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkvs-coder%2Fhealth_kit_reporter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkvs-coder%2Fhealth_kit_reporter/lists"}