見出し画像

【ミーア】flutterでAppleのHealthKit API からユーザーの行動ログを取得してサーバーに送信し、Gemini APIを元にアドバイス文を生成:実装編

はじめに

前回、こちらの記事で、flutterで「Appleヘルスケアとの連携」ボタンを設置し、AppleのHealthKit APIにデータアクセスの許可を実装するところまでを記載した。

今回は、Flutterアプリからサーバーにヘルスデータを送信し、Gemini APIを通じてアドバイスのテキスト(例:昨日はよく眠れたみたいですね。この調子!)を生成する部分を実装したい。

ヘルスデータの取得

Flutterアプリで、ユーザーからの許可を得た後、指定した期間(例えば、前日)のヘルスデータを取得する。前回で、既に**HealthFactory**を使用して許可を取得する部分を実装しているので、次にデータ取得のロジックを追加する。
特定の期間(この場合は前日の始まりから今日の始まりまで)にわたってユーザーの健康データを取得し、それをコンソールに出力するFlutterの非同期関数**fetchData**を追加する。

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

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

  @override
  _HealthCareAppIntegrationScreenState createState() =>
      _HealthCareAppIntegrationScreenState();
}

class _HealthCareAppIntegrationScreenState
    extends State<HealthCareAppIntegrationScreen> {
  // ここで連携したいデータタイプを定義
  static final types = [
    HealthDataType.STEPS,
    HealthDataType.WEIGHT,
    HealthDataType.WORKOUT,
    HealthDataType.EXERCISE_TIME,
    HealthDataType.MINDFULNESS,
    HealthDataType.SLEEP_IN_BED,
    HealthDataType.SLEEP_ASLEEP,
    HealthDataType.SLEEP_AWAKE,
    HealthDataType.SLEEP_DEEP,
    HealthDataType.SLEEP_REM,
  ];
  // READ only
  final permissions = types.map((e) => HealthDataAccess.READ).toList();

  // create a HealthFactory for use in the app
  HealthFactory health = HealthFactory(useHealthConnectIfAvailable: true);

  Future<void> requestPermissionsAndFetchData() async {
    final permissions = types.map((e) => HealthDataAccess.READ).toList();
    bool requestResult =
        await health.requestAuthorization(types, permissions: permissions);

    if (requestResult) {
      print("Authorization granted");
      fetchData();
    } else {
      print("Authorization denied");
    }
  }

  Future<void> fetchData() async {
    DateTime now = DateTime.now();
    DateTime startOfDay = DateTime(now.year, now.month, now.day - 1);
    DateTime endOfDay = DateTime(now.year, now.month, now.day);

    List<HealthDataPoint> healthDataPoints =
        await health.getHealthDataFromTypes(startOfDay, endOfDay, types);
    healthDataPoints = HealthFactory.removeDuplicates(healthDataPoints);

    for (var dataPoint in healthDataPoints) {
      print(
          "${dataPoint.typeString}: ${dataPoint.value} ${dataPoint.unitString}");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ヘルスケアアプリとの連携'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () => requestPermissionsAndFetchData(),
          child: const Text('連携する'),
        ),
      ),
    );
  }
}

ユーザーが「連携する」ボタンをクリックすると、**requestPermissionsAndFetchData**メソッドが呼び出される。
このメソッドはまずHealthKitまたはGoogle Fitからのデータアクセス許可をリクエストし、ユーザーが許可した場合にのみ**fetchData**メソッドを呼び出してデータをフェッチする。取得したデータポイントはコンソールに出力された。

flutter: >> isAuthorized: true
flutter: Authorization granted
flutter: STEPS: 142.0 COUNT
flutter: STEPS: 55.0 COUNT
flutter: STEPS: 10.0 COUNT
flutter: STEPS: 20.0 COUNT
flutter: STEPS: 84.0 COUNT
flutter: STEPS: 92.0 COUNT
flutter: STEPS: 39.0 COUNT
flutter: STEPS: 31.0 COUNT
flutter: STEPS: 19.0 COUNT
flutter: STEPS: 67.0 COUNT
flutter: STEPS: 13.0 COUNT
flutter: STEPS: 724.0 COUNT
flutter: STEPS: 624.0 COUNT
flutter: STEPS: 836.0 COUNT
flutter: STEPS: 775.0 COUNT
flutter: STEPS: 231.0 COUNT
flutter: STEPS: 297.0 COUNT
flutter: STEPS: 264.0 COUNT
flutter: STEPS: 351.0 COUNT
flutter: STEPS: 205.0 COUNT
flutter: STEPS: 94.0 COUNT
flutter: STEPS: 88.0 COUNT
flutter: STEPS: 642.0 COUNT
flutter: STEPS: 556.0 COUNT
flutter: STEPS: 833.0 COUNT
flutter: STEPS: 836.0 COUNT
flutter: STEPS: 271.0 COUNT
flutter: STEPS: 277.0 COUNT
flutter: STEPS: 553.0 COUNT
flutter: STEPS: 611.0 COUNT
flutter: STEPS: 52.0 COUNT
flutter: STEPS: 33.0 COUNT
flutter: STEPS: 109.0 COUNT
flutter: STEPS: 479.0 COUNT
flutter: STEPS: 400.0 COUNT
flutter: STEPS: 68.0 COUNT
flutter: STEPS: 80.0 COUNT
flutter: STEPS: 41.0 COUNT
flutter: STEPS: 72.0 COUNT
flutter: STEPS: 68.0 COUNT
flutter: STEPS: 26.0 COUNT
flutter: STEPS: 10.0 COUNT
flutter: STEPS: 179.0 COUNT
flutter: STEPS: 41.0 COUNT
flutter: STEPS: 11.0 COUNT
flutter: STEPS: 68.0 COUNT
flutter: STEPS: 12.0 COUNT
flutter: STEPS: 37.0 COUNT
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: EXERCISE_TIME: 1.0 MINUTE
flutter: SLEEP_IN_BED: 663.0 MINUTE

あれ、睡眠時間以外は、項目が多いなと。1日分のデータなので、歩数データは、1日の間に歩いた総歩数が出ると思ったのだが。調べてみると下記が理由みたい。

歩数データの多さ

歩数データが多く表示されている理由の一つは、HealthKitが1日の間に歩いた総歩数ではなく、特定の時間帯やアクティビティごとに歩数を記録しているため。
例えば、ユーザーが1日の中で複数回に分けて歩いた場合、それぞれのセッションが個別のデータポイントとして記録される。これにより、1日の総歩数を得るためには、取得した全ての歩数データを合計する必要がある。

運動時間データの複数回記録

運動時間(EXERCISE_TIME)が1分のデータポイントで複数回記録されているのは、短い運動セッションが複数回にわたって行われたことを示している。HealthKitは、

続きは、こちらで記載しています。


この記事が参加している募集

仕事について話そう

よろしければサポートお願いします!いただいたサポートはクリエイターとしての活動費に使わせていただきます!