diff --git a/packages/health/lib/src/health_factory.dart b/packages/health/lib/src/health_factory.dart index 9550bb397..ff3d51166 100644 --- a/packages/health/lib/src/health_factory.dart +++ b/packages/health/lib/src/health_factory.dart @@ -6,14 +6,33 @@ class HealthFactory { String? _deviceId; final _deviceInfo = DeviceInfoPlugin(); - static PlatformType _platformType = - Platform.isAndroid ? PlatformType.ANDROID : PlatformType.IOS; + static PlatformType _platformType = Platform.isAndroid ? PlatformType.ANDROID : PlatformType.IOS; /// Check if a given data type is available on the platform - bool isDataTypeAvailable(HealthDataType dataType) => - _platformType == PlatformType.ANDROID - ? _dataTypeKeysAndroid.contains(dataType) - : _dataTypeKeysIOS.contains(dataType); + bool isDataTypeAvailable(HealthDataType dataType) => _platformType == PlatformType.ANDROID + ? _dataTypeKeysAndroid.contains(dataType) + : _dataTypeKeysIOS.contains(dataType); + + /// iOS isn't completely supported by HealthKit, false means no, true means user has approved or declined permissions. + /// In case user has declined permissions read will just return empty list for declined data types. + static Future hasPermissions(List types) async { + return await _channel.invokeMethod('hasPermissions', { + "types": types.map((type) => _enumToString(type)).toList(), + }); + } + + /// If you're using more than one DataType it's advised to call requestPermissions with all the data types once, + /// otherwise iOS HealthKit will ask to approve every permission one by one in separate screens. + static Future requestPermissions(List types) async { + return await _channel.invokeMethod('requestPermissions', { + "types": types.map((type) => _enumToString(type)).toList(), + }); + } + + /// iOS isn't supported by HealthKit, method does nothing. + static Future revokePermissions() async { + return await _channel.invokeMethod('revokePermissions'); + } /// Request access to GoogleFit or Apple HealthKit Future requestAuthorization(List types) async { @@ -29,23 +48,19 @@ class HealthFactory { } List keys = types.map((e) => _enumToString(e)).toList(); - final bool isAuthorized = - await _channel.invokeMethod('requestAuthorization', {'types': keys}); + final bool isAuthorized = await _channel.invokeMethod('requestAuthorization', {'types': keys}); return isAuthorized; } /// Calculate the BMI using the last observed height and weight values. - Future> _computeAndroidBMI( - DateTime startDate, DateTime endDate) async { - List heights = - await _prepareQuery(startDate, endDate, HealthDataType.HEIGHT); + Future> _computeAndroidBMI(DateTime startDate, DateTime endDate) async { + List heights = await _prepareQuery(startDate, endDate, HealthDataType.HEIGHT); if (heights.isEmpty) { return []; } - List weights = - await _prepareQuery(startDate, endDate, HealthDataType.WEIGHT); + List weights = await _prepareQuery(startDate, endDate, HealthDataType.WEIGHT); double h = heights.last.value.toDouble(); @@ -55,8 +70,8 @@ class HealthFactory { final bmiHealthPoints = []; for (var i = 0; i < weights.length; i++) { final bmiValue = weights[i].value.toDouble() / (h * h); - final x = HealthDataPoint(bmiValue, dataType, unit, weights[i].dateFrom, - weights[i].dateTo, _platformType, _deviceId!, '', ''); + final x = HealthDataPoint( + bmiValue, dataType, unit, weights[i].dateFrom, weights[i].dateTo, _platformType, _deviceId!, '', ''); bmiHealthPoints.add(x); } @@ -76,8 +91,7 @@ class HealthFactory { } /// Prepares a query, i.e. checks if the types are available, etc. - Future> _prepareQuery( - DateTime startDate, DateTime endDate, HealthDataType dataType) async { + Future> _prepareQuery(DateTime startDate, DateTime endDate, HealthDataType dataType) async { // Ask for device ID only once _deviceId ??= _platformType == PlatformType.ANDROID ? (await _deviceInfo.androidInfo).androidId @@ -85,21 +99,18 @@ class HealthFactory { // If not implemented on platform, throw an exception if (!isDataTypeAvailable(dataType)) { - throw _HealthException( - dataType, 'Not available on platform $_platformType'); + throw _HealthException(dataType, 'Not available on platform $_platformType'); } // If BodyMassIndex is requested on Android, calculate this manually - if (dataType == HealthDataType.BODY_MASS_INDEX && - _platformType == PlatformType.ANDROID) { + if (dataType == HealthDataType.BODY_MASS_INDEX && _platformType == PlatformType.ANDROID) { return _computeAndroidBMI(startDate, endDate); } return await _dataQuery(startDate, endDate, dataType); } /// The main function for fetching health data - Future> _dataQuery( - DateTime startDate, DateTime endDate, HealthDataType dataType) async { + Future> _dataQuery(DateTime startDate, DateTime endDate, HealthDataType dataType) async { // Set parameters for method channel request final args = { 'dataTypeKey': _enumToString(dataType), @@ -113,8 +124,7 @@ class HealthFactory { if (fetchedDataPoints != null) { return fetchedDataPoints.map((e) { final num value = e['value']; - final DateTime from = - DateTime.fromMillisecondsSinceEpoch(e['date_from']); + final DateTime from = DateTime.fromMillisecondsSinceEpoch(e['date_from']); final DateTime to = DateTime.fromMillisecondsSinceEpoch(e['date_to']); final String sourceId = e["source_id"]; final String sourceName = e["source_name"];