Flutter健康监测插件healthy_ios的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

Flutter健康监测插件healthy_ios的使用

介绍

healthy_ios 是一个小型封装库,用于在 HealthKit 上进行样本和统计查询。它受到 CACHET 的 health 库的启发。

使用方法

  1. pubspec.yaml 中添加 healthy_ios
  2. plist.info 文件中添加以下条目:
<key>NSHealthShareUsageDescription</key>
<string>请说明你需要这个权限的原因。</string>
<key>NSHealthUpdateUsageDescription</key>
<string>请说明你需要这个权限的原因。</string>
  1. 在 Xcode 中打开你的项目,并将 “HealthKit” 添加为功能。

设置完成后的操作

现在你可以实例化一个 HealthStore 对象:

final store = HealthStore();

在查询数据之前,请确保通过调用以下方法请求用户的权限:

final stepType = HKQuantityType.StepCount.identifier();
final permissionsGranted = await store.requestTypes([stepType]);

现在你可以查询样本。如果你查询的是数量类型,需要提供类型和单位的元组。这里有一个扩展函数可以使用:

final now = DateTime.now();
final samples = await store.getHealthSamplesForQuantityType(
  start: now.subtract(Duration(days: 2)), // 查询过去两天的数据
  end: now,
  types: [ 
    // 手动构造元组
    HKQuantityTypeUnitTuple(HKQuantityType.StepCount, 'count'),
    // 使用扩展函数
    HKQuantityType.HeartRate.withUnit('count/min'),
  ]);

如果你查询的是类别类型,则不需要传递单位,因此结果值属性包含子类型的枚举值。

获取统计数据也很容易。你还需要传递一个间隔时间(用于累积统计数据)和一个锚定日期(用于确定间隔的起始点)。目前,StatisticsInterval 只能处理天、小时和分钟间隔。

final now = DateTime.now();
final start = DateTime(now.year, now.month, now.day, 0, 0);
final samples = await store.getHealthStatisticsForType(
  start: start,
  end: now,
  interval: StatisticsInterval(hour: 1), // 每小时间隔
  anchor: start,
  types: [
    HKQuantityType.StepCount.withUnit('count'),
  ]);

生成的统计数据对象有四个值字段(sum, avg, min, max)。如果 HKQuantityType 是累计类型,只有 sum 字段会有值。如果是离散类型,avg, min 和 max 字段都会有值。

额外信息

  • 关于有效单位,请参阅相关文档。

支持的数据类型

定量类型:

  • ActiveEnergyBurned
  • BasalEnergyBurned
  • BloodGlucose
  • OxygenSaturation
  • BloodPressureDiastolic
  • BloodPressureSystolic
  • BodyFatPercentage
  • BodyMassIndex
  • BodyTemperature
  • HeartRate
  • Height
  • RestingHeartRate
  • StepCount
  • WaistCircumference
  • WalkingHeartRateAverage
  • BodyMass
  • FlightsClimbed
  • DistanceWalkingRunning
  • DietaryWater
  • HeartRateVariabilitySDNN
  • EnvironmentalAudioExposure
  • HeadphoneAudioExposure

类别类型:

  • MindfulSession
  • SleepAnalysis

完整示例 Demo

import 'package:flutter/material.dart';
import 'package:healthy_ios/healthy_ios.dart';

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

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  var isLoading = false;
  var _result = '';
  final store = HealthStore();

  [@override](/user/override)
  void initState() {
    super.initState();
  }

  // 获取分类样本
  void _fetchCategoricalSamples() async {
    final types = [HKCategoryType.SleepAnalysis, HKCategoryType.MindfulSession];
    final granted = await store.requestTypes(types.map((e) => e.identifier));

    setState(() {
      isLoading = true;
    });

    try {
      if (granted) {
        final now = DateTime.now();
        final samples = await store.getHealthSamplesForCategroyType(
            start: now.subtract(Duration(days: 5)), end: now, types: types);
        setState(() {
          _result = samples.map((e) => e.toString()).join('\n');
        });
      }
    } on HealthyException catch (e) {
      setState(() {
        _result = e.code;
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  // 获取数量样本
  void _fetchQuantitySamples() async {
    final types = [HKQuantityType.StepCount, HKQuantityType.ActiveEnergyBurned]
        .map((e) => e.identifier);
    final granted = await store.requestTypes(types);

    setState(() {
      isLoading = true;
    });

    try {
      if (granted) {
        final now = DateTime.now();
        final samples = await store.getHealthSamplesForQuantityType(
            start: now.subtract(Duration(days: 2)),
            end: now,
            types: [
              HKQuantityTypeUnitTuple(HKQuantityType.StepCount, 'count'),
            ]);

        setState(() {
          _result = samples.map((e) => e.toString()).join('\n');
        });
      }
    } on HealthyException catch (e) {
      setState(() {
        _result = e.code;
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  // 获取统计数据
  void _fetchStatisticalData() async {
    final types = [HKQuantityType.StepCount, HKQuantityType.HeartRate]
        .map((e) => e.identifier);
    final granted = await store.requestTypes(types);

    setState(() {
      isLoading = true;
    });

    try {
      if (granted) {
        final now = DateTime.now();
        final start = DateTime(now.year, now.month, now.day, 0, 0);
        final samples = await store.getHealthStatisticsForType(
          start: start,
          end: now,
          interval: StatisticsInterval(hour: 1),
          anchor: start,
          types: [
            HKQuantityType.StepCount.withUnit('count'),
            HKQuantityType.HeartRate.withUnit('count/min'),
          ],
        );

        setState(() {
          _result = samples.map((e) => e.toString()).join('\n');
        });
      }
    } on HealthyException catch (e) {
      setState(() {
        _result = e.code;
      });
    } finally {
      setState(() {
        isLoading = false;
      });
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('插件示例应用'),
        ),
        body: isLoading
            ? const CircularProgressIndicator()
            : Center(
                child: SingleChildScrollView(
                    child: Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: [
                        ElevatedButton(
                            onPressed: _fetchQuantitySamples,
                            child: Text('样本')),
                        ElevatedButton(
                            onPressed: _fetchCategoricalSamples,
                            child: Text('分类')),
                        ElevatedButton(
                            onPressed: _fetchStatisticalData,
                            child: Text('统计')),
                      ],
                    ),
                    Text(_result),
                  ],
                )),
              ),
      ),
    );
  }
}

更多关于Flutter健康监测插件healthy_ios的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter健康监测插件healthy_ios的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中集成并使用healthy_ios插件来进行健康监测的一个基本示例。请注意,healthy_ios是一个特定于iOS的插件,因此在Android上不可用。此外,由于我无法实时验证插件的API或安装过程,以下代码基于插件的一般使用方法和假设的API设计。

首先,确保你已经在pubspec.yaml文件中添加了healthy_ios依赖:

dependencies:
  flutter:
    sdk: flutter
  healthy_ios: ^最新版本号  # 请替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,在你的Flutter项目的iOS部分(通常是通过Xcode打开的Runner项目),你需要确保你的应用有权限访问健康数据。这需要在Info.plist文件中添加相应的权限请求。例如:

<key>NSHealthShareUsageDescription</key>
<string>我们需要访问您的健康数据来提供更好的健康监测服务。</string>
<key>NSHealthUpdateUsageDescription</key>
<string>我们需要更新您的健康数据以提供最新的健康监测结果。</string>

现在,让我们编写一些Flutter代码来使用healthy_ios插件。由于healthy_ios可能是一个假设的插件名,我将提供一个基于类似插件可能提供的API的示例代码。请根据你实际使用的插件文档进行调整。

import 'package:flutter/material.dart';
import 'package:healthy_ios/healthy_ios.dart'; // 假设这是插件的导入路径

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

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

class _MyAppState extends State<MyApp> {
  String healthData = "No Data Yet";

  @override
  void initState() {
    super.initState();
    _requestHealthData();
  }

  Future<void> _requestHealthData() async {
    // 检查平台是否为iOS,因为healthy_ios是iOS特定的
    if (Platform.isIOS) {
      HealthyIos healthyIos = HealthyIos();

      try {
        // 假设插件有一个方法来请求步数数据
        var stepsData = await healthyIos.requestSteps();
        setState(() {
          healthData = "Steps: ${stepsData.stepsCount}";
        });
      } catch (e) {
        print("Error requesting health data: $e");
        setState(() {
          healthData = "Error fetching health data";
        });
      }
    } else {
      setState(() {
        healthData = "This feature is only available on iOS.";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Healthy iOS Plugin Demo'),
        ),
        body: Center(
          child: Text(healthData),
        ),
      ),
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,它尝试在iOS上请求健康数据(如步数)。请注意,HealthyIos类和requestSteps方法都是假设的,你需要根据你实际使用的插件的API进行调整。

由于healthy_ios可能不是一个真实存在的Flutter插件,我强烈建议你查阅官方文档或GitHub仓库以获取准确的API信息和集成指南。如果你发现healthy_ios确实存在但API与上述示例不同,请相应地调整代码。

回到顶部