Flutter健康数据访问插件health_ios12的使用

Flutter健康数据访问插件health_ios12的使用

Health 插件简介

Health 插件允许从 Apple Health、Google Fit 和 Health Connect 读取和写入健康数据。

注意:Google Fitness API 正在被弃用,该插件将逐步过渡到 Health Connect API。

插件支持的功能:

  • 权限管理:通过 hasPermissionsrequestAuthorizationrevokePermissions 方法处理权限。
  • 读取健康数据:使用 getHealthDataFromTypes 方法读取健康数据。
  • 写入健康数据:使用 writeHealthData 方法写入健康数据。
  • 写入运动数据:使用 writeWorkout 方法写入运动数据。
  • 写入音频图:在 iOS 上使用 writeAudiogram 方法写入音频图。
  • 写入血压数据:使用 writeBloodPressure 方法写入血压数据。
  • 获取总步数:使用 getTotalStepsInInterval 方法获取步数。
  • 清理重复数据点:使用 removeDuplicates 方法清理重复数据。
  • 删除指定类型的数据:使用 delete 方法删除指定时间段内的数据。
  • 支持未来的 Android API Health Connect

注意:对于 Android 用户,目标设备需要安装 Google Fit 或 Health Connect(目前处于测试阶段),并且需要互联网连接,否则该插件无法正常工作。


数据类型

以下为支持的数据类型及其单位:

数据类型 单位 iOS Android (Google Fit) Android (Health Connect) 备注
ACTIVE_ENERGY_BURNED CALORIES
BASAL_ENERGY_BURNED CALORIES
BLOOD_GLUCOSE MILLIGRAM_PER_DECILITER
BLOOD_OXYGEN PERCENTAGE
BLOOD_PRESSURE_DIASTOLIC MILLIMETER_OF_MERCURY
BLOOD_PRESSURE_SYSTOLIC MILLIMETER_OF_MERCURY
BODY_FAT_PERCENTAGE PERCENTAGE
BODY_MASS_INDEX NO_UNIT
BODY_TEMPERATURE DEGREE_CELSIUS


安装与配置

Apple Health (iOS)

第一步:修改 Info.plist

添加以下两个条目以描述健康数据用途:

<key>NSHealthShareUsageDescription</key>
<string>我们需要同步您的数据到 Apple Health 应用以提供更好的洞察。</string>
<key>NSHealthUpdateUsageDescription</key>
<string>我们需要同步您的数据到 Apple Health 应用以提供更好的洞察。</string>

第二步:启用 HealthKit

在 Xcode 中打开项目,并在 Runner 的设置中启用 HealthKit 能力。


Google Fit (Android 选项 1)

按照以下步骤生成 OAuth2 客户端 ID 并添加 SHA1 指纹:

  1. 在终端进入密钥库目录:

    cd ~/.android/
    
  2. 获取密钥库的 SHA1 指纹:

    keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
    
  3. 将 SHA1 指纹添加到 OAuth2 凭据中,并生成客户端 ID,例如:

    YOUR_CLIENT_ID.apps.googleusercontent.com
    

Health Connect (Android 选项 2)

AndroidManifest.xml 中添加以下内容:

<queries>
    <package android:name="com.google.android.apps.healthdata" />
</queries>

Android 权限

从 Android 9.0 开始,访问某些健身数据(如步数)需要特殊权限。在 AndroidManifest.xml 中添加以下行:

<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>

对于 Health Connect,还需添加以下权限:

<uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
<uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>

此外,如果请求运动距离,则需要位置权限:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

使用 permission_handler 插件提示用户授予这些权限:

await Permission.activityRecognition.request();
await Permission.location.request();

使用示例

以下是一个完整的示例代码,展示如何使用 health_ios12 插件访问健康数据。

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:health_ios12/health.dart';
import 'package:health_example/util.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(HealthApp());

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

enum AppState {
  DATA_NOT_FETCHED,
  FETCHING_DATA,
  DATA_READY,
  NO_DATA,
  AUTHORIZED,
  AUTH_NOT_GRANTED,
  DATA_ADDED,
  DATA_DELETED,
  DATA_NOT_ADDED,
  DATA_NOT_DELETED,
  STEPS_READY,
}

class _HealthAppState extends State<HealthApp> {
  List<HealthDataPoint> _healthDataList = [];
  AppState _state = AppState.DATA_NOT_FETCHED;
  int _nofSteps = 0;

  // 定义要获取的数据类型
  static final types = dataTypesAndroid;
  final permissions = types.map((e) => HealthDataAccess.READ_WRITE).toList();

  HealthFactory health = HealthFactory(useHealthConnectIfAvailable: true);

  Future authorize() async {
    await Permission.activityRecognition.request();
    await Permission.location.request();

    bool authorized = false;
    try {
      authorized = await health.requestAuthorization(types, permissions: permissions);
    } catch (error) {
      print("授权异常: $error");
    }
    setState(() => _state = authorized ? AppState.AUTHORIZED : AppState.AUTH_NOT_GRANTED);
  }

  Future fetchData() async {
    setState(() => _state = AppState.FETCHING_DATA);

    final now = DateTime.now();
    final yesterday = now.subtract(Duration(hours: 24));

    _healthDataList.clear();
    try {
      List<HealthDataPoint> healthData = await health.getHealthDataFromTypes(yesterday, now, types);
      _healthDataList.addAll(HealthFactory.removeDuplicates(healthData));
    } catch (error) {
      print("获取数据异常: $error");
    }

    setState(() {
      _state = _healthDataList.isEmpty ? AppState.NO_DATA : AppState.DATA_READY;
    });
  }

  Future addData() async {
    bool success = true;
    final now = DateTime.now();
    final earlier = now.subtract(Duration(minutes: 20));

    success &= await health.writeHealthData(10, HealthDataType.BODY_FAT_PERCENTAGE, earlier, now);
    success &= await health.writeHealthData(1.925, HealthDataType.HEIGHT, earlier, now);
    success &= await health.writeHealthData(90, HealthDataType.WEIGHT, earlier, now);
    success &= await health.writeHealthData(90, HealthDataType.HEART_RATE, earlier, now);
    success &= await health.writeHealthData(90, HealthDataType.STEPS, earlier, now);
    success &= await health.writeHealthData(200, HealthDataType.ACTIVE_ENERGY_BURNED, earlier, now);
    success &= await health.writeHealthData(70, HealthDataType.HEART_RATE, earlier, now);
    success &= await health.writeHealthData(37, HealthDataType.BODY_TEMPERATURE, earlier, now);
    success &= await health.writeBloodOxygen(98, earlier, now, flowRate: 1.0);
    success &= await health.writeHealthData(105, HealthDataType.BLOOD_GLUCOSE, earlier, now);
    success &= await health.writeHealthData(1.8, HealthDataType.WATER, earlier, now);
    success &= await health.writeWorkoutData(
        HealthWorkoutActivityType.AMERICAN_FOOTBALL, earlier, now,
        totalDistance: 2430, totalEnergyBurned: 400);
    success &= await health.writeBloodPressure(90, 80, earlier, now);

    setState(() {
      _state = success ? AppState.DATA_ADDED : AppState.DATA_NOT_ADDED;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Health Example')),
        body: Column(
          children: [
            ElevatedButton(onPressed: authorize, child: Text('授权')),
            ElevatedButton(onPressed: fetchData, child: Text('获取数据')),
            ElevatedButton(onPressed: addData, child: Text('添加数据')),
            Text('当前状态: $_state'),
          ],
        ),
      ),
    );
  }
}

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

1 回复

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


health_ios12 是一个用于在 Flutter 应用中访问 iOS 设备上健康数据的插件。它主要用于读取和写入与健康相关的数据,如步数、心率、睡眠等。以下是如何使用 health_ios12 插件的基本步骤:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 health_ios12 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  health_ios12: ^2.0.0  # 请使用最新版本

然后运行 flutter pub get 以获取依赖。

2. 配置 iOS 项目

在 iOS 项目中,你需要在 Info.plist 文件中添加健康数据访问的权限描述:

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

3. 初始化插件

在你的 Dart 代码中,首先导入 health_ios12 插件:

import 'package:health_ios12/health_ios12.dart';

然后创建一个 HealthFactory 实例:

HealthFactory health = HealthFactory();

4. 请求权限

在访问健康数据之前,你需要请求用户的权限。你可以使用 requestAuthorization 方法请求访问特定类型的健康数据:

List<HealthDataType> types = [
  HealthDataType.STEPS,
  HealthDataType.HEART_RATE,
  HealthDataType.SLEEP_IN_BED,
];

bool requested = await health.requestAuthorization(types);

if (requested) {
  print("权限请求成功");
} else {
  print("权限请求失败");
}

5. 读取健康数据

你可以使用 getHealthDataFromTypes 方法读取特定时间范围内的健康数据:

DateTime now = DateTime.now();
DateTime startDate = DateTime(now.year, now.month, now.day - 7); // 一周前
DateTime endDate = now;

List<HealthDataPoint> healthData = await health.getHealthDataFromTypes(startDate, endDate, types);

for (var dataPoint in healthData) {
  print("类型: ${dataPoint.type}, 值: ${dataPoint.value}, 时间: ${dataPoint.dateFrom}");
}

6. 写入健康数据

你也可以使用 writeHealthData 方法写入健康数据:

bool success = await health.writeHealthData(HealthDataType.STEPS, 1000, DateTime.now());

if (success) {
  print("数据写入成功");
} else {
  print("数据写入失败");
}

7. 处理错误

在实际应用中,你应该处理可能出现的错误,例如用户拒绝权限或设备不支持健康数据访问:

try {
  List<HealthDataPoint> healthData = await health.getHealthDataFromTypes(startDate, endDate, types);
  for (var dataPoint in healthData) {
    print("类型: ${dataPoint.type}, 值: ${dataPoint.value}, 时间: ${dataPoint.dateFrom}");
  }
} catch (e) {
  print("获取健康数据时出错: $e");
}
回到顶部