Flutter健康数据同步插件withings_health的使用

Flutter健康数据同步插件withings_health的使用

本指南将帮助你了解如何在Flutter应用中使用withings_health插件来读取健康数据。该插件支持从Withings健康API获取活动和睡眠数据。

支持

此插件支持iOS和Android平台。

对于Android

确保已正确配置flutter_web_auth以在成功登录后重定向回应用。

数据类型

用户活动(User.Activity)

  • 步骤:步数。
  • 距离:行进距离(米)。
  • 楼层:爬楼层数。
  • :轻度活动持续时间(秒)。
  • 中等:中等强度活动持续时间(秒)。
  • 高强度:高强度活动持续时间(秒)。
  • 活跃:中等和高强度活动持续时间之和(秒)。
  • 卡路里:活跃消耗的卡路里(千卡)。通过混合精细粒度的卡路里估算、锻炼估计卡路里和用户手动设置的卡路里来计算。
  • 总卡路里:总消耗的卡路里(千卡)。通过将活跃卡路里与静息卡路里相加得到。
  • 平均心率:平均心率。
  • 最小心率:最低心率。
  • 最小心率:最高心率。
  • 心率区0:心率在轻度区间内的持续时间(秒)。
  • 心率区1:心率在中等区间内的持续时间(秒)。
  • 心率区2:心率在高强度区间内的持续时间(秒)。
  • 心率区3:心率在最大区间内的持续时间(秒)。

用户睡眠(User.Sleep)

  • REM阶段计数:REM睡眠阶段的数量。
  • 睡眠效率:总睡眠时间与在床上的时间比值。
  • 入睡潜伏期:入睡前在床上的时间。
  • 总睡眠时间:实际睡眠时间。包括浅睡、深睡和REM睡眠的总和。
  • 总床上时间:在床上的总时间。
  • 醒来潜伏期:醒来后在床上的时间。
  • 醒来后清醒时间:入睡后第一次醒来期间在床上清醒的时间。

睡眠呼吸障碍

  • 呼吸暂停低通气指数:医疗级AHI。仅适用于欧洲和澳大利亚购买且激活了睡眠呼吸障碍检测功能的设备。平均每小时发生的呼吸暂停和低通气事件次数。
  • 呼吸障碍强度:所有睡眠和睡眠分析设备可用的健康指标。呼吸障碍强度。

其他睡眠数据点和生命体征

  • 入睡时间:入睡所需时间(秒)。(已弃用)
  • 醒来时间:醒来所需时间(秒)。(已弃用)
  • 平均心率:平均心率。
  • 最大心率:最高心率。
  • 最小心率:最低心率。
  • 浅睡持续时间:浅睡状态下的持续时间(秒)。
  • 夜间事件:夜间发生的事件列表。
  • 离床次数:夜间离床次数。
  • REM睡眠持续时间:REM睡眠状态下的持续时间(秒)。
  • 平均呼吸频率:平均呼吸频率。
  • 最大呼吸频率:最高呼吸频率。
  • 最小呼吸频率:最低呼吸频率。
  • 睡眠评分:睡眠评分。
  • 打鼾:总打鼾时间。
  • 打鼾次数:至少一分钟的打鼾次数。
  • 醒来次数:在床上醒来的次数。不包括离床次数。
  • 清醒时间:清醒时间(秒)。

设置

步骤1:在developer.withings.com注册一个应用程序

注意:重定向URL很重要,因为它用于成功登录后导航回应用。 例如:“yourappname://withings/auth”

步骤2:获取clientId和secretKey

以下是使用插件的简化流程。

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:withings_health/constants/api_constants.dart';
import 'package:withings_health/models/withings_activity_model.dart';
import 'package:withings_health/models/withings_sleep_model.dart';
import 'package:withings_health/withings_health.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: WithingsHealthExample(),
    );
  }
}

class WithingsHealthExample extends StatefulWidget {
  const WithingsHealthExample({Key? key}) : super(key: key);

  [@override](/user/override)
  State<WithingsHealthExample> createState() => _WithingsHealthExampleState();
}

class _WithingsHealthExampleState extends State<WithingsHealthExample> {
  static const String withingClientID =
      'cf9b703fa359f61343d6bd5ca3fc8f14325064514a6200bdcca898e1866c6843';

  // Withings Client Secret
  static const String withingClientSecret =
      'fec79c88c882d4b947f62e975688a7eb03a09a228959963f41f058ce7bf6d026';

  /// Auth Uri, you can replace "withingsnokia with your app name"
  static const String withingRedirectUri = 'withingsnokia://withings/auth';

  /// Callback scheme
  static const String withingCallbackScheme = 'withingsnokia';
  WithingsHealth healthFactory = WithingsHealth();
  late WithingsDataModel _withingActivityData;
  late WithingsSleepData _withingSleepData;
  late String? userId;
  late String? accessToken;
  late String? refreshToken;
  // Variables used to show data
  double calories = 0, distance = 0;
  int duration = 0, sleep = 0, caloriesLeft = 0;
  int goalSleep = 0, stepCount = 0, totalCalories = 0;
  int floors = 0;

  var now = new DateTime.now();
  var formatter = new DateFormat('yyyy-MM-dd');
  late String formattedDate;

  // Method to set Activity Data state
  setActivityData(WithingsDataModel _activityData) {
    _activityData.body!.activities!.forEach((element) {
      calories = calories + element.calories!.toDouble();

      // Distance in Meters
      distance = distance + element.distance!.toDouble();

      // Distance in Miles if needed
      // distance = distance / 1000 * 0.62137;
      totalCalories = totalCalories + element.totalcalories!.toInt();

      stepCount = stepCount + element.steps!.toInt();
      floors = floors + element.elevation!.toInt();
      duration = duration + element.active!.toInt();
    });
    setState(() {
      calories;
      distance;
      totalCalories;
      stepCount;
      floors;
      duration;
    });
  }

  // Method to set Sleep Data state
  setSleepData(WithingsSleepData _sleepData) {
    _sleepData.body!.series!.forEach((element) {
      sleep = sleep + element.data!.asleepduration!.toInt();
      goalSleep = goalSleep + element.data!.durationtosleep!.toInt();
      setState(() {
        sleep;
        goalSleep;
      });
    });
  }

  GetAuthData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    userId = prefs.getString('userWithing');
    accessToken = prefs.getString('accessTokenWithing');
    refreshToken = prefs.getString('refreshTokenWithing');
  }

  [@override](/user/override)
  void initState() {
    super.initState();
    formattedDate = formatter.format(now);
    print(formattedDate);
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Withings Health Mate")),
      body: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            ElevatedButton(
                onPressed: () async {
                  userId = await healthFactory.withingsLogin(
                      withingsClientID: withingClientID,
                      withingClientSecret: withingClientSecret,
                      withingRedirectUri: withingRedirectUri,
                      scopes: Strings.scopes,
                      withingCallbackScheme: withingCallbackScheme);
                },
                child: Text("Connect Withings Health Mate")),
            Divider(),
            ElevatedButton(
                onPressed: () async {
                  _withingActivityData =
                      await healthFactory.getWithingsActivityData(
                          startDate: formattedDate, endDate: formattedDate);
                  setActivityData(_withingActivityData);
                },
                child: Text("Get Activity Data")),
            Text("Calories: $calories"),
            Text("Distance: $distance"),
            Text("StepCount: $stepCount"),
            Text("Duration: $duration"),
            Divider(),
            ElevatedButton(
                onPressed: () async {
                  _withingSleepData = await healthFactory.getWithingsSleepData(
                      startDate: formattedDate, endDate: formattedDate);
                  setSleepData(_withingSleepData);
                },
                child: Text("Get Sleep Data")),
            Text("Sleep Time: $sleep"),
            Text("Goal Sleep Time: $goalSleep"),
            Divider(),
            ElevatedButton(
                onPressed: () {
                  GetAuthData();
                },
                child: Text("Get Auth Data")),
          ],
        ),
      ),
    );
  }
}

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

1 回复

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


withings_health 是一个 Flutter 插件,用于与 Withings 健康设备同步数据。通过这个插件,你可以从 Withings 设备中获取诸如步数、心率、睡眠数据等健康信息,并在你的 Flutter 应用中使用这些数据。

安装插件

首先,你需要在 pubspec.yaml 文件中添加 withings_health 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  withings_health: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来安装插件。

配置 Withings API

在使用 withings_health 插件之前,你需要在 Withings 开发者平台上注册你的应用,并获取 clientIdclientSecret

  1. 访问 Withings Developer Portal 并创建一个应用。
  2. 获取 clientIdclientSecret

使用插件

1. 初始化插件

在你的 Flutter 应用中,首先需要初始化 withings_health 插件:

import 'package:withings_health/withings_health.dart';

final withingsHealth = WithingsHealth();

2. 授权用户

用户需要通过 Withings 进行授权,以便你的应用可以访问他们的健康数据。你需要调用 authorize 方法:

Future<void> authorize() async {
  try {
    await withingsHealth.authorize(
      clientId: 'YOUR_CLIENT_ID',
      clientSecret: 'YOUR_CLIENT_SECRET',
      redirectUri: 'YOUR_REDIRECT_URI',
      state: 'YOUR_STATE',  // 可选
    );
  } catch (e) {
    print('Authorization failed: $e');
  }
}

3. 获取健康数据

一旦用户授权,你就可以获取他们的健康数据。以下是一些示例代码,展示如何获取步数、心率和睡眠数据:

Future<void> getHealthData() async {
  try {
    // 获取步数
    final steps = await withingsHealth.getSteps(
      startDate: DateTime.now().subtract(Duration(days: 7)),
      endDate: DateTime.now(),
    );
    print('Steps: $steps');

    // 获取心率
    final heartRate = await withingsHealth.getHeartRate(
      startDate: DateTime.now().subtract(Duration(days: 7)),
      endDate: DateTime.now(),
    );
    print('Heart Rate: $heartRate');

    // 获取睡眠数据
    final sleepSummary = await withingsHealth.getSleepSummary(
      startDate: DateTime.now().subtract(Duration(days: 7)),
      endDate: DateTime.now(),
    );
    print('Sleep Summary: $sleepSummary');
  } catch (e) {
    print('Failed to get health data: $e');
  }
}

4. 处理回调

在授权过程中,Withings 会重定向用户到你的应用。你需要在 AndroidManifest.xmlInfo.plist 中配置回调 URL。

Android:

AndroidManifest.xml 中添加以下内容:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="YOUR_REDIRECT_URI_SCHEME" />
</intent-filter>

iOS:

Info.plist 中添加以下内容:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>YOUR_REDIRECT_URI_SCHEME</string>
        </array>
    </dict>
</array>

5. 注销用户

如果你需要注销用户,可以调用 logout 方法:

Future<void> logout() async {
  await withingsHealth.logout();
}

注意事项

  1. 权限:确保你已经在 AndroidManifest.xmlInfo.plist 中配置了必要的权限。
  2. 数据隐私:处理用户健康数据时,请确保遵守相关的隐私政策和法律法规。
  3. API 限制:Withings API 可能有调用频率限制,请确保在你的应用中处理这些限制。

示例代码

以下是一个完整的示例代码,展示如何使用 withings_health 插件:

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HealthDataScreen(),
    );
  }
}

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

class _HealthDataScreenState extends State<HealthDataScreen> {
  final withingsHealth = WithingsHealth();
  String healthData = 'No data yet';

  Future<void> authorizeAndGetData() async {
    try {
      await withingsHealth.authorize(
        clientId: 'YOUR_CLIENT_ID',
        clientSecret: 'YOUR_CLIENT_SECRET',
        redirectUri: 'YOUR_REDIRECT_URI',
        state: 'YOUR_STATE',
      );

      final steps = await withingsHealth.getSteps(
        startDate: DateTime.now().subtract(Duration(days: 7)),
        endDate: DateTime.now(),
      );

      setState(() {
        healthData = 'Steps: $steps';
      });
    } catch (e) {
      setState(() {
        healthData = 'Error: $e';
      });
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Withings Health Data'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(healthData),
            ElevatedButton(
              onPressed: authorizeAndGetData,
              child: Text('Get Health Data'),
            ),
          ],
        ),
      ),
    );
  }
}
回到顶部