From d8fcf5a06a071011b1a58e2ec81e23f5d604904c Mon Sep 17 00:00:00 2001 From: MarioKaurin Date: Mon, 24 Feb 2025 13:55:49 +0100 Subject: [PATCH 01/10] [HEALTH] - move CARDIO_DANCE to both, as it is available for Android and ios --- packages/health/lib/src/heath_data_types.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/health/lib/src/heath_data_types.dart b/packages/health/lib/src/heath_data_types.dart index 0a1f8c400..7d268ec06 100644 --- a/packages/health/lib/src/heath_data_types.dart +++ b/packages/health/lib/src/heath_data_types.dart @@ -466,6 +466,7 @@ enum HealthWorkoutActivityType { BASKETBALL, BIKING, // This also entails the iOS version where it is called CYCLING BOXING, + CARDIO_DANCE, CRICKET, CROSS_COUNTRY_SKIING, CURLING, @@ -504,7 +505,6 @@ enum HealthWorkoutActivityType { // iOS only BARRE, BOWLING, - CARDIO_DANCE, CLIMBING, COOLDOWN, CORE_TRAINING, From 0a72448110cc572a9f8720efa67b9db819ce6a1d Mon Sep 17 00:00:00 2001 From: Nanda Kista Permana Date: Thu, 10 Apr 2025 14:21:01 +0700 Subject: [PATCH 02/10] Added deviceModel for iOS to identify data coming from iPhone, Watch, or Others --- .../health/ios/Classes/SwiftHealthPlugin.swift | 1 + packages/health/lib/health.g.dart | 2 ++ packages/health/lib/src/health_data_point.dart | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/health/ios/Classes/SwiftHealthPlugin.swift b/packages/health/ios/Classes/SwiftHealthPlugin.swift index 8b4fa1bbf..3a71a121e 100644 --- a/packages/health/ios/Classes/SwiftHealthPlugin.swift +++ b/packages/health/ios/Classes/SwiftHealthPlugin.swift @@ -902,6 +902,7 @@ public class SwiftHealthPlugin: NSObject, FlutterPlugin { "date_to": Int(sample.endDate.timeIntervalSince1970 * 1000), "source_id": sample.sourceRevision.source.bundleIdentifier, "source_name": sample.sourceRevision.source.name, + "device_model": sample.device?.model ?? "unknown", "recording_method": (sample.metadata?[HKMetadataKeyWasUserEntered] as? Bool == true) ? RecordingMethod.manual.rawValue : RecordingMethod.automatic.rawValue, diff --git a/packages/health/lib/health.g.dart b/packages/health/lib/health.g.dart index d985c19dc..701be9c5e 100644 --- a/packages/health/lib/health.g.dart +++ b/packages/health/lib/health.g.dart @@ -27,6 +27,7 @@ HealthDataPoint _$HealthDataPointFromJson(Map json) => : WorkoutSummary.fromJson( json['workoutSummary'] as Map), metadata: json['metadata'] as Map?, + deviceModel: json['deviceModel'] as String?, ); Map _$HealthDataPointToJson(HealthDataPoint instance) => @@ -45,6 +46,7 @@ Map _$HealthDataPointToJson(HealthDataPoint instance) => if (instance.workoutSummary?.toJson() case final value?) 'workoutSummary': value, if (instance.metadata case final value?) 'metadata': value, + if (instance.deviceModel case final value?) 'deviceModel': value, }; const _$HealthDataTypeEnumMap = { diff --git a/packages/health/lib/src/health_data_point.dart b/packages/health/lib/src/health_data_point.dart index 029af835c..70dc1d882 100644 --- a/packages/health/lib/src/health_data_point.dart +++ b/packages/health/lib/src/health_data_point.dart @@ -55,6 +55,11 @@ class HealthDataPoint { /// The metadata for this data point. Map? metadata; + /// The source of the data, whether from the iPhone or Watch or something else. + /// Only available fo iOS + /// On Android: always return null + String? deviceModel; + HealthDataPoint({ required this.uuid, required this.value, @@ -69,6 +74,7 @@ class HealthDataPoint { this.recordingMethod = RecordingMethod.unknown, this.workoutSummary, this.metadata, + this.deviceModel, }) { // set the value to minutes rather than the category // returned by the native API @@ -137,6 +143,7 @@ class HealthDataPoint { : Map.from(dataPoint['metadata'] as Map); final unit = dataTypeToUnit[dataType] ?? HealthDataUnit.UNKNOWN_UNIT; final String? uuid = dataPoint["uuid"] as String?; + final String? deviceModel = dataPoint["device_model"] as String?; // Set WorkoutSummary, if available. WorkoutSummary? workoutSummary; @@ -163,6 +170,7 @@ class HealthDataPoint { recordingMethod: RecordingMethod.fromInt(recordingMethod), workoutSummary: workoutSummary, metadata: metadata, + deviceModel: deviceModel, ); } @@ -180,7 +188,8 @@ class HealthDataPoint { sourceName: $sourceName recordingMethod: $recordingMethod workoutSummary: $workoutSummary - metadata: $metadata"""; + metadata: $metadata + deviceModel: $deviceModel"""; @override bool operator ==(Object other) => @@ -196,9 +205,10 @@ class HealthDataPoint { sourceId == other.sourceId && sourceName == other.sourceName && recordingMethod == other.recordingMethod && - metadata == other.metadata; + metadata == other.metadata && + deviceModel == other.deviceModel; @override int get hashCode => Object.hash(uuid, value, unit, dateFrom, dateTo, type, - sourcePlatform, sourceDeviceId, sourceId, sourceName, metadata); + sourcePlatform, sourceDeviceId, sourceId, sourceName, metadata, deviceModel); } From 47b11d9f29266677bee4b9e84ac2d057033f444b Mon Sep 17 00:00:00 2001 From: "IKEMOTO, Masahiro" Date: Fri, 18 Apr 2025 19:33:14 +0900 Subject: [PATCH 03/10] (Android) Add PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND handler. --- .../cachet/plugins/health/HealthPlugin.kt | 53 +++++++++++++++ .../android/app/src/main/AndroidManifest.xml | 3 + packages/health/example/lib/main.dart | 3 + packages/health/lib/src/health_plugin.dart | 64 +++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/packages/health/android/src/main/kotlin/cachet/plugins/health/HealthPlugin.kt b/packages/health/android/src/main/kotlin/cachet/plugins/health/HealthPlugin.kt index a9c23af2c..5fb0a5a79 100644 --- a/packages/health/android/src/main/kotlin/cachet/plugins/health/HealthPlugin.kt +++ b/packages/health/android/src/main/kotlin/cachet/plugins/health/HealthPlugin.kt @@ -15,6 +15,7 @@ import androidx.health.connect.client.HealthConnectFeatures import androidx.health.connect.client.PermissionController import androidx.health.connect.client.permission.HealthPermission import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_READ_HEALTH_DATA_HISTORY +import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND import androidx.health.connect.client.records.* import androidx.health.connect.client.records.MealType.MEAL_TYPE_BREAKFAST import androidx.health.connect.client.records.MealType.MEAL_TYPE_DINNER @@ -153,6 +154,9 @@ class HealthPlugin(private var channel: MethodChannel? = null) : "isHealthDataHistoryAvailable" -> isHealthDataHistoryAvailable(call, result) "isHealthDataHistoryAuthorized" -> isHealthDataHistoryAuthorized(call, result) "requestHealthDataHistoryAuthorization" -> requestHealthDataHistoryAuthorization(call, result) + "isHealthDataInBackgroundAvailable" -> isHealthDataInBackgroundAvailable(call, result) + "isHealthDataInBackgroundAuthorized" -> isHealthDataInBackgroundAuthorized(call, result) + "requestHealthDataInBackgroundAuthorization" -> requestHealthDataInBackgroundAuthorization(call, result) "hasPermissions" -> hasPermissions(call, result) "requestAuthorization" -> requestAuthorization(call, result) "revokePermissions" -> revokePermissions(call, result) @@ -568,6 +572,55 @@ class HealthPlugin(private var channel: MethodChannel? = null) : healthConnectRequestPermissionsLauncher!!.launch(setOf(PERMISSION_READ_HEALTH_DATA_HISTORY)) } + /** + * Checks if the health data in background feature is available on this device + */ + @OptIn(ExperimentalFeatureAvailabilityApi::class) + private fun isHealthDataInBackgroundAvailable(call: MethodCall, result: Result) { + scope.launch { + result.success( + healthConnectClient + .features + .getFeatureStatus(HealthConnectFeatures.FEATURE_READ_HEALTH_DATA_IN_BACKGROUND) == + HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) + } + } + + /** + * Checks if PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND has been granted + */ + private fun isHealthDataInBackgroundAuthorized(call: MethodCall, result: Result) { + scope.launch { + result.success( + healthConnectClient + .permissionController + .getGrantedPermissions() + .containsAll(listOf(PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND)), + ) + } + } + + /** + * Requests authorization for PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND + */ + private fun requestHealthDataInBackgroundAuthorization(call: MethodCall, result: Result) { + if (context == null) { + result.success(false) + return + } + + if (healthConnectRequestPermissionsLauncher == null) { + result.success(false) + Log.i("FLUTTER_HEALTH", "Permission launcher not found") + return + } + + // Store the result to be called in [onHealthConnectPermissionCallback] + mResult = result + isReplySubmitted = false + healthConnectRequestPermissionsLauncher!!.launch(setOf(PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND)) + } + private fun hasPermissions(call: MethodCall, result: Result) { val args = call.arguments as HashMap<*, *> val types = (args["types"] as? ArrayList<*>)?.filterIsInstance()!! diff --git a/packages/health/example/android/app/src/main/AndroidManifest.xml b/packages/health/example/android/app/src/main/AndroidManifest.xml index 1b559506e..70e81aa1e 100644 --- a/packages/health/example/android/app/src/main/AndroidManifest.xml +++ b/packages/health/example/android/app/src/main/AndroidManifest.xml @@ -57,6 +57,9 @@ + + + { // request access to read historic data await health.requestHealthDataHistoryAuthorization(); + // request access in background + await health.requestHealthDataInBackgroundAuthorization(); + } catch (error) { debugPrint("Exception in authorize: $error"); } diff --git a/packages/health/lib/src/health_plugin.dart b/packages/health/lib/src/health_plugin.dart index 0c7bae82b..536392458 100644 --- a/packages/health/lib/src/health_plugin.dart +++ b/packages/health/lib/src/health_plugin.dart @@ -264,6 +264,70 @@ class Health { } } + /// Checks if the Health Data in Background feature is available. + /// + /// See this for more info: https://developer.android.com/reference/androidx/health/connect/client/permission/HealthPermission#PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND() + /// + /// + /// Android only. Returns false on iOS or if an error occurs. + Future isHealthDataInBackgroundAvailable() async { + if (Platform.isIOS) return false; + + try { + final status = + await _channel.invokeMethod('isHealthDataInBackgroundAvailable'); + return status ?? false; + } catch (e) { + debugPrint( + '$runtimeType - Exception in isHealthDataInBackgroundAvailable(): $e'); + return false; + } + } + + /// Checks the current status of the Health Data in Background permission. + /// Make sure to check [isHealthConnectAvailable] before calling this method. + /// + /// See this for more info: https://developer.android.com/reference/androidx/health/connect/client/permission/HealthPermission#PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND() + /// + /// + /// Android only. Returns true on iOS or false if an error occurs. + Future isHealthDataInBackgroundAuthorized() async { + if (Platform.isIOS) return true; + + try { + final status = + await _channel.invokeMethod('isHealthDataInBackgroundAuthorized'); + return status ?? false; + } catch (e) { + debugPrint( + '$runtimeType - Exception in isHealthDataInBackgroundAuthorized(): $e'); + return false; + } + } + + /// Requests the Health Data in Background permission. + /// + /// Returns true if successful, false otherwise. + /// + /// See this for more info: https://developer.android.com/reference/androidx/health/connect/client/permission/HealthPermission#PERMISSION_READ_HEALTH_DATA_IN_BACKGROUND() + /// + /// + /// Android only. Returns true on iOS or false if an error occurs. + Future requestHealthDataInBackgroundAuthorization() async { + if (Platform.isIOS) return true; + + await _checkIfHealthConnectAvailableOnAndroid(); + try { + final bool? isAuthorized = + await _channel.invokeMethod('requestHealthDataInBackgroundAuthorization'); + return isAuthorized ?? false; + } catch (e) { + debugPrint( + '$runtimeType - Exception in requestHealthDataInBackgroundAuthorization(): $e'); + return false; + } + } + /// Requests permissions to access health data [types]. /// /// Returns true if successful, false otherwise. From bd44d3c34ac6ab30530fa66e844ec6824738bbf1 Mon Sep 17 00:00:00 2001 From: Alireza Hajebrahimi <6937697+iarata@users.noreply.github.com> Date: Tue, 22 Apr 2025 10:39:19 +0200 Subject: [PATCH 04/10] bumped to 12.2.0 --- packages/health/CHANGELOG.md | 4 ++++ packages/health/ios/health.podspec | 2 +- packages/health/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/health/CHANGELOG.md b/packages/health/CHANGELOG.md index fafe282ee..396b5c6aa 100644 --- a/packages/health/CHANGELOG.md +++ b/packages/health/CHANGELOG.md @@ -1,3 +1,7 @@ +## 12.2.0 + +* iOS: Add `deviceModel` in returned Health data to identify the device that generated the data of the receiver. (in iOS `source_name` represents the revision of the source responsible for saving the receiver.) + ## 12.1.0 * Add delete record by UUID method. See function `deleteByUUID(required String uuid, HealthDataType? type)` diff --git a/packages/health/ios/health.podspec b/packages/health/ios/health.podspec index aba1806e8..600f56161 100644 --- a/packages/health/ios/health.podspec +++ b/packages/health/ios/health.podspec @@ -3,7 +3,7 @@ # Pod::Spec.new do |s| s.name = 'health' - s.version = '12.1.0' + s.version = '12.2.0' s.summary = 'Wrapper for Apple\'s HealthKit on iOS and Google\'s Health Connect on Android.' s.description = <<-DESC Wrapper for Apple's HealthKit on iOS and Google's Health Connect on Android. diff --git a/packages/health/pubspec.yaml b/packages/health/pubspec.yaml index a92b82d90..2626c2118 100644 --- a/packages/health/pubspec.yaml +++ b/packages/health/pubspec.yaml @@ -1,6 +1,6 @@ name: health description: Wrapper for Apple's HealthKit on iOS and Google's Health Connect on Android. -version: 12.1.0 +version: 12.2.0 homepage: https://github.com/cph-cachet/flutter-plugins/tree/master/packages/health environment: From 0329a6fd2a3585eca23a81cc8df649b069493993 Mon Sep 17 00:00:00 2001 From: Alireza Hajebrahimi <6937697+iarata@users.noreply.github.com> Date: Tue, 22 Apr 2025 11:39:47 +0200 Subject: [PATCH 05/10] Updated CHANGELOG --- packages/health/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/health/CHANGELOG.md b/packages/health/CHANGELOG.md index 396b5c6aa..698c565cc 100644 --- a/packages/health/CHANGELOG.md +++ b/packages/health/CHANGELOG.md @@ -1,6 +1,7 @@ ## 12.2.0 * iOS: Add `deviceModel` in returned Health data to identify the device that generated the data of the receiver. (in iOS `source_name` represents the revision of the source responsible for saving the receiver.) +* Android: Add read health data in background - PR [#1184](https://github.com/cph-cachet/flutter-plugins/pull/1184) ## 12.1.0 From 4aefaaef93b6eef9d58b4c0d72c948d1fd4f65e4 Mon Sep 17 00:00:00 2001 From: Alireza Hajebrahimi <6937697+iarata@users.noreply.github.com> Date: Thu, 24 Apr 2025 10:21:15 +0200 Subject: [PATCH 06/10] Fix 12.1.0 mealType on NutritionHealthValue null #1169 --- packages/health/CHANGELOG.md | 1 + packages/health/example/lib/main.dart | 23 ++++++++++++++++++- packages/health/lib/health.g.dart | 4 ++-- .../health/lib/src/health_value_types.dart | 8 +++---- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/health/CHANGELOG.md b/packages/health/CHANGELOG.md index 698c565cc..0b9ddacc8 100644 --- a/packages/health/CHANGELOG.md +++ b/packages/health/CHANGELOG.md @@ -2,6 +2,7 @@ * iOS: Add `deviceModel` in returned Health data to identify the device that generated the data of the receiver. (in iOS `source_name` represents the revision of the source responsible for saving the receiver.) * Android: Add read health data in background - PR [#1184](https://github.com/cph-cachet/flutter-plugins/pull/1184) +* Fix of [#1169](https://github.com/cph-cachet/flutter-plugins/issues/1169) where `meal_type` property in `Nutrition` was null always ## 12.1.0 diff --git a/packages/health/example/lib/main.dart b/packages/health/example/lib/main.dart index 4bb48cfbb..b0d7c690b 100644 --- a/packages/health/example/lib/main.dart +++ b/packages/health/example/lib/main.dart @@ -197,6 +197,27 @@ class HealthAppState extends State { }); } + Future writeNutritionDataTest() async { + final now = DateTime.now(); + final earlier = now.subtract(const Duration(minutes: 20)); + + // Add nutrition data + bool success = await health.writeMeal( + mealType: MealType.DINNER, + startTime: earlier, + endTime: now, + caloriesConsumed: 1000, + carbohydrates: 50, + protein: 25, + fatTotal: 50, + name: "Banana", + ); + + setState(() { + _state = success ? AppState.DATA_ADDED : AppState.DATA_NOT_ADDED; + }); + } + /// Add some random health data. /// Note that you should ensure that you have permissions to add the /// following data types. @@ -740,7 +761,7 @@ class HealthAppState extends State { if (p.value is NutritionHealthValue) { return ListTile( title: Text( - "${p.typeString} ${(p.value as NutritionHealthValue).mealType}: ${(p.value as NutritionHealthValue).name}"), + "${p.typeString} ${(p.value as NutritionHealthValue).meal_type}: ${(p.value as NutritionHealthValue).name}"), trailing: Text('${(p.value as NutritionHealthValue).calories} kcal'), subtitle: Text('${p.dateFrom} - ${p.dateTo}\n${p.recordingMethod}'), diff --git a/packages/health/lib/health.g.dart b/packages/health/lib/health.g.dart index 701be9c5e..67eb66e1f 100644 --- a/packages/health/lib/health.g.dart +++ b/packages/health/lib/health.g.dart @@ -479,7 +479,7 @@ NutritionHealthValue _$NutritionHealthValueFromJson( Map json) => NutritionHealthValue( name: json['name'] as String?, - mealType: json['mealType'] as String?, + meal_type: json['meal_type'] as String?, calories: (json['calories'] as num?)?.toDouble(), protein: (json['protein'] as num?)?.toDouble(), fat: (json['fat'] as num?)?.toDouble(), @@ -529,7 +529,7 @@ Map _$NutritionHealthValueToJson( { if (instance.$type case final value?) '__type': value, if (instance.name case final value?) 'name': value, - if (instance.mealType case final value?) 'mealType': value, + if (instance.meal_type case final value?) 'meal_type': value, if (instance.calories case final value?) 'calories': value, if (instance.protein case final value?) 'protein': value, if (instance.fat case final value?) 'fat': value, diff --git a/packages/health/lib/src/health_value_types.dart b/packages/health/lib/src/health_value_types.dart index af13e1892..6558af1c2 100644 --- a/packages/health/lib/src/health_value_types.dart +++ b/packages/health/lib/src/health_value_types.dart @@ -426,7 +426,7 @@ class NutritionHealthValue extends HealthValue { String? name; /// The type of meal. - String? mealType; + String? meal_type; /// The amount of calories in kcal. double? calories; @@ -556,7 +556,7 @@ class NutritionHealthValue extends HealthValue { NutritionHealthValue({ this.name, - this.mealType, + this.meal_type, this.calories, this.protein, this.fat, @@ -625,7 +625,7 @@ class NutritionHealthValue extends HealthValue { name: ${name.toString()}, carbs: ${carbs.toString()}, caffeine: ${caffeine.toString()}, - mealType: $mealType, + mealType: $meal_type, vitaminA: ${vitaminA.toString()}, b1Thiamine: ${b1Thiamine.toString()}, b2Riboflavin: ${b2Riboflavin.toString()}, @@ -668,7 +668,7 @@ class NutritionHealthValue extends HealthValue { bool operator ==(Object other) => other is NutritionHealthValue && other.name == name && - other.mealType == mealType && + other.meal_type == meal_type && other.calories == calories && other.protein == protein && other.fat == fat && From 83969c3445689b6bc4be74f4c7b65db4472c7ad2 Mon Sep 17 00:00:00 2001 From: Alireza Hajebrahimi <6937697+iarata@users.noreply.github.com> Date: Thu, 24 Apr 2025 10:21:34 +0200 Subject: [PATCH 07/10] Update CHANGELOG --- packages/health/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/health/CHANGELOG.md b/packages/health/CHANGELOG.md index 0b9ddacc8..cb1d5a30b 100644 --- a/packages/health/CHANGELOG.md +++ b/packages/health/CHANGELOG.md @@ -2,7 +2,7 @@ * iOS: Add `deviceModel` in returned Health data to identify the device that generated the data of the receiver. (in iOS `source_name` represents the revision of the source responsible for saving the receiver.) * Android: Add read health data in background - PR [#1184](https://github.com/cph-cachet/flutter-plugins/pull/1184) -* Fix of [#1169](https://github.com/cph-cachet/flutter-plugins/issues/1169) where `meal_type` property in `Nutrition` was null always +* Fix [#1169](https://github.com/cph-cachet/flutter-plugins/issues/1169) where `meal_type` property in `Nutrition` was null always ## 12.1.0 From b3cd2b23a097cd161e42da7b28d7357effdbb22b Mon Sep 17 00:00:00 2001 From: Alireza Hajebrahimi <6937697+iarata@users.noreply.github.com> Date: Thu, 24 Apr 2025 10:32:24 +0200 Subject: [PATCH 08/10] Clean up --- packages/health/example/lib/main.dart | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/packages/health/example/lib/main.dart b/packages/health/example/lib/main.dart index b0d7c690b..1ef18e5b5 100644 --- a/packages/health/example/lib/main.dart +++ b/packages/health/example/lib/main.dart @@ -197,27 +197,6 @@ class HealthAppState extends State { }); } - Future writeNutritionDataTest() async { - final now = DateTime.now(); - final earlier = now.subtract(const Duration(minutes: 20)); - - // Add nutrition data - bool success = await health.writeMeal( - mealType: MealType.DINNER, - startTime: earlier, - endTime: now, - caloriesConsumed: 1000, - carbohydrates: 50, - protein: 25, - fatTotal: 50, - name: "Banana", - ); - - setState(() { - _state = success ? AppState.DATA_ADDED : AppState.DATA_NOT_ADDED; - }); - } - /// Add some random health data. /// Note that you should ensure that you have permissions to add the /// following data types. From 3c99c1d01e480746090af72eb4e0161008f18a19 Mon Sep 17 00:00:00 2001 From: Alireza Hajebrahimi <6937697+iarata@users.noreply.github.com> Date: Wed, 30 Apr 2025 17:27:52 +0200 Subject: [PATCH 09/10] Update CHANGELOG --- packages/health/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/health/CHANGELOG.md b/packages/health/CHANGELOG.md index cb1d5a30b..b1a333889 100644 --- a/packages/health/CHANGELOG.md +++ b/packages/health/CHANGELOG.md @@ -3,6 +3,7 @@ * iOS: Add `deviceModel` in returned Health data to identify the device that generated the data of the receiver. (in iOS `source_name` represents the revision of the source responsible for saving the receiver.) * Android: Add read health data in background - PR [#1184](https://github.com/cph-cachet/flutter-plugins/pull/1184) * Fix [#1169](https://github.com/cph-cachet/flutter-plugins/issues/1169) where `meal_type` property in `Nutrition` was null always +* iOS: Add `CARDIO_DANCE` HealthDataType - [#1146](https://github.com/cph-cachet/flutter-plugins/pull/1146) ## 12.1.0 From cb2e3b8dbfa72b5af8cddc5ebe0a8068aa65960a Mon Sep 17 00:00:00 2001 From: Alireza Hajebrahimi <6937697+iarata@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:27:15 +0200 Subject: [PATCH 10/10] Add docs for reading data in background --- packages/health/README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/health/README.md b/packages/health/README.md index 559ec09c4..65db40ed6 100644 --- a/packages/health/README.md +++ b/packages/health/README.md @@ -311,6 +311,17 @@ List points = ...; points = health.removeDuplicates(points); ``` +### Android: Reading Health Data in Background +Currently health connect allows apps to read health data in the background. In order to achieve this add the following permission to your `AndroidManifest.XML`: +```XML + + +``` +Furthermore, the plugin now exposes three new functions to help you check and request access to read data in the background: +1. `isHealthDataInBackgroundAvailable()`: Checks if the Health Data in Background feature is available +2. `isHealthDataInBackgroundAuthorized()`: Checks the current status of the Health Data in Background permission +3. `requestHealthDataInBackgroundAuthorization()`: Requests the Health Data in Background permission. + ## Data Types The plugin supports the following [`HealthDataType`](https://pub.dev/documentation/health/latest/health/HealthDataType.html).