Skip to content

Commit 702b213

Browse files
author
Agil Setiawan
committed
Add getHealthDataByUUID for iOS
- Add getHealthDataByUUID example - Add getHealthDataByUUID documentation on README
1 parent ecd2ba5 commit 702b213

4 files changed

Lines changed: 452 additions & 10 deletions

File tree

packages/health/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,43 @@ Furthermore, the plugin now exposes three new functions to help you check and re
322322
2. `isHealthDataInBackgroundAuthorized()`: Checks the current status of the Health Data in Background permission
323323
3. `requestHealthDataInBackgroundAuthorization()`: Requests the Health Data in Background permission.
324324

325+
### Fetch single health data by UUID
326+
327+
In order to retrieve a single record, it is required to provide `String uuid` and `HealthDataType type`.
328+
329+
Please see example below:
330+
```dart
331+
HealthDataPoint? healthPoint = await health.getHealthDataByUUID(
332+
uuid: 'E9F2EEAD-8FC5-4CE5-9FF5-7C4E535FB8B8',
333+
type: HealthDataType.WORKOUT,
334+
);
335+
```
336+
```
337+
data by UUID: HealthDataPoint -
338+
uuid: E9F2EEAD-8FC5-4CE5-9FF5-7C4E535FB8B8,
339+
value: WorkoutHealthValue - workoutActivityType: RUNNING,
340+
totalEnergyBurned: null,
341+
totalEnergyBurnedUnit: KILOCALORIE,
342+
totalDistance: 2400,
343+
totalDistanceUnit: METER
344+
totalSteps: null,
345+
totalStepsUnit: null,
346+
unit: NO_UNIT,
347+
dateFrom: 2025-05-02 07:31:00.000,
348+
dateTo: 2025-05-02 08:25:00.000,
349+
dataType: WORKOUT,
350+
platform: HealthPlatformType.appleHealth,
351+
deviceId: unknown,
352+
sourceId: com.apple.Health,
353+
sourceName: Health
354+
recordingMethod: RecordingMethod.manual
355+
workoutSummary: WorkoutSummary - workoutType: runningtotalDistance: 2400, totalEnergyBurned: 0, totalSteps: 0
356+
metadata: null
357+
deviceModel: null
358+
```
359+
> Assuming that the `uuid` and `type` are coming from your database.
360+
361+
325362
## Data Types
326363

327364
The plugin supports the following [`HealthDataType`](https://pub.dev/documentation/health/latest/health/HealthDataType.html).

packages/health/example/lib/main.dart

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import 'package:carp_serializable/carp_serializable.dart';
1010
// Global Health instance
1111
final health = Health();
1212

13-
void main() => runApp(HealthApp());
13+
void main() => runApp(
14+
const MaterialApp(
15+
home: HealthApp(),
16+
),
17+
);
1418

1519
class HealthApp extends StatefulWidget {
1620
const HealthApp({super.key});
@@ -122,13 +126,12 @@ class HealthAppState extends State<HealthApp> {
122126
try {
123127
authorized =
124128
await health.requestAuthorization(types, permissions: permissions);
125-
129+
126130
// request access to read historic data
127131
await health.requestHealthDataHistoryAuthorization();
128132

129133
// request access in background
130134
await health.requestHealthDataInBackgroundAuthorization();
131-
132135
} catch (error) {
133136
debugPrint("Exception in authorize: $error");
134137
}
@@ -197,6 +200,26 @@ class HealthAppState extends State<HealthApp> {
197200
});
198201
}
199202

203+
/// Fetch single data point by UUID and type.
204+
Future<void> fetchDataByUUID({
205+
required String uuid,
206+
required HealthDataType type,
207+
}) async {
208+
try {
209+
// fetch health data
210+
HealthDataPoint? healthPoint = await health.getHealthDataByUUID(
211+
uuid: uuid,
212+
type: type,
213+
);
214+
215+
if (healthPoint != null) {
216+
openDetailBottomSheet(healthPoint);
217+
}
218+
} catch (error) {
219+
debugPrint("Exception in getHealthDataByUUID: $error");
220+
}
221+
}
222+
200223
/// Add some random health data.
201224
/// Note that you should ensure that you have permissions to add the
202225
/// following data types.
@@ -514,6 +537,22 @@ class HealthAppState extends State<HealthApp> {
514537
});
515538
}
516539

540+
/// Display bottom sheet dialog of selected HealthDataPoint
541+
void openDetailBottomSheet(HealthDataPoint? healthPoint) {
542+
if (!context.mounted) return;
543+
544+
showModalBottomSheet(
545+
context: context,
546+
isScrollControlled: true,
547+
shape: const RoundedRectangleBorder(
548+
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
549+
),
550+
builder: (BuildContext context) => _detailedBottomSheet(
551+
healthPoint: healthPoint,
552+
),
553+
);
554+
}
555+
517556
// UI building below
518557

519558
@override
@@ -735,6 +774,12 @@ class HealthAppState extends State<HealthApp> {
735774
trailing:
736775
Text((p.value as WorkoutHealthValue).workoutActivityType.name),
737776
subtitle: Text('${p.dateFrom} - ${p.dateTo}\n${p.recordingMethod}'),
777+
onTap: () {
778+
fetchDataByUUID(
779+
uuid: p.uuid,
780+
type: p.type,
781+
);
782+
},
738783
);
739784
}
740785
if (p.value is NutritionHealthValue) {
@@ -750,6 +795,12 @@ class HealthAppState extends State<HealthApp> {
750795
title: Text("${p.typeString}: ${p.value}"),
751796
trailing: Text(p.unitString),
752797
subtitle: Text('${p.dateFrom} - ${p.dateTo}\n${p.recordingMethod}'),
798+
onTap: () {
799+
fetchDataByUUID(
800+
uuid: p.uuid,
801+
type: p.type,
802+
);
803+
},
753804
);
754805
});
755806

@@ -806,4 +857,49 @@ class HealthAppState extends State<HealthApp> {
806857
AppState.PERMISSIONS_REVOKED => _permissionsRevoked,
807858
AppState.PERMISSIONS_NOT_REVOKED => _permissionsNotRevoked,
808859
};
860+
861+
Widget _detailedBottomSheet({HealthDataPoint? healthPoint}) {
862+
return DraggableScrollableSheet(
863+
expand: false,
864+
initialChildSize: 0.5,
865+
minChildSize: 0.3,
866+
maxChildSize: 0.9,
867+
builder: (BuildContext listContext, scrollController) {
868+
return Container(
869+
padding: const EdgeInsets.all(16),
870+
child: Column(
871+
children: [
872+
const Text(
873+
"Health Data Details",
874+
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
875+
),
876+
const SizedBox(height: 10),
877+
healthPoint == null
878+
? const Text('UUID Not Found!')
879+
: Expanded(
880+
child: ListView.builder(
881+
controller: scrollController,
882+
itemCount: healthPoint.toJson().entries.length,
883+
itemBuilder: (context, index) {
884+
String key =
885+
healthPoint.toJson().keys.elementAt(index);
886+
var value = healthPoint.toJson()[key];
887+
888+
return ListTile(
889+
title: Text(
890+
key.replaceAll('_', ' ').toUpperCase(),
891+
style:
892+
const TextStyle(fontWeight: FontWeight.bold),
893+
),
894+
subtitle: Text(value.toString()),
895+
);
896+
},
897+
),
898+
),
899+
],
900+
),
901+
);
902+
},
903+
);
904+
}
809905
}

0 commit comments

Comments
 (0)