You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter中对接Google Fit/Apple Health获取步数数据?

Flutter 接入health包读取步数极简实现(适配Google Fit/Apple Health)

不用找什么配套教学视频,核心逻辑没那么复杂,按下面步骤来就行,都是踩过坑整理的最小可用实现。

一、先搞定原生端配置,这步漏了后面代码全白写

安卓(Google Fit)配置

  • 打开android/app/build.gradle,把minSdkVersion改成21及以上,health包不支持21以下的版本
  • 打开android/app/src/main/AndroidManifest.xml,在根级<manifest>标签下加两个权限:
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
  • 安卓10及以上系统的活动识别动态权限,health包会自动触发申请,不用自己额外写逻辑

iOS(Apple Health)配置

  • 打开ios/Runner/Info.plist,在根级<dict>标签下加两个权限描述,内容要清晰说明用途,不然上架审核会被拒:
<key>NSHealthShareUsageDescription</key>
<string>需要读取步数数据用于应用内展示</string>
<key>NSHealthUpdateUsageDescription</key>
<string>需要同步步数数据到应用</string>
  • 用Xcode打开Runner项目,在Signing & Capabilities页添加HealthKit能力,这步不开的话,权限弹窗根本弹不出来

二、Dart端核心代码,只留读步数的必要逻辑

首先在pubspec.yaml的dependencies下加最新版的health依赖,跑flutter pub get拉取包即可。
下面是可以直接复制用的页面代码,没有多余封装,逻辑一目了然:

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

class StepPage extends StatefulWidget {
  const StepPage({super.key});

  @override
  State<StepPage> createState() => _StepPageState();
}

class _StepPageState extends State<StepPage> {
  // 入门阶段不用搞什么单例、全局封装,直接实例化用就行
  final HealthFactory _health = HealthFactory();
  int _todaySteps = 0;
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    // 进页面自动拉一次步数
    _loadTodaySteps();
  }

  Future<void> _loadTodaySteps() async {
    setState(() => _isLoading = true);
    // 只要步数数据,别的类型都不用加
    final dataTypes = [HealthDataType.STEPS];
    // 只读权限,不需要申请写入权限
    final permissions = [HealthDataAccess.READ];

    try {
      // 先申请权限,用户同意了才能读数据
      final isAuthed = await _health.requestAuthorization(dataTypes, permissions: permissions);
      if (!isAuthed) {
        setState(() => _isLoading = false);
        // 这里可以自行加提示,告诉用户没权限无法读取步数
        return;
      }

      // 时间范围设置为今日0点到当前时间
      final now = DateTime.now();
      final dayStart = DateTime(now.year, now.month, now.day);
      // 直接用官方提供的聚合方法拿总步数,别自己遍历健康数据点求和,慢还容易算错
      final steps = await _health.getTotalStepsInInterval(dayStart, now);

      setState(() {
        _todaySteps = steps ?? 0;
        _isLoading = false;
      });
    } catch (e) {
      debugPrint('拉取步数出错: $e');
      setState(() {
        _isLoading = false;
        _todaySteps = 0;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('今日步数')),
      body: Center(
        child: _isLoading
            ? const CircularProgressIndicator()
            : Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const Text('今日累计步数', style: TextStyle(fontSize: 20)),
                  const SizedBox(height: 12),
                  Text(
                    '$_todaySteps',
                    style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
                  ),
                  const SizedBox(height: 24),
                  ElevatedButton(
                    onPressed: _loadTodaySteps,
                    child: const Text('刷新步数'),
                  )
                ],
              ),
      ),
    );
  }
}

三、新手必避的坑

  • 安卓测试机必须装完整的Google Play服务和Google Fit,国内很多定制系统砍了Google服务框架,会直接拉取失败,这种情况要做兜底提示
  • iOS如果用户第一次点了拒绝权限,后面再调用申请接口不会再弹系统弹窗,需要引导用户手动去系统设置-健康里给应用开权限
  • 不要一次拉太长时间跨度的步数(比如几个月、一年),很容易触发系统接口限流,日常拉当日、近7天的数据都不会有问题
  • 系统健康数据不是实时更新的,一般有1-5分钟的延迟,不用做轮询实时刷新,进页面拉一次、加个手动刷新按钮就足够
  • 尽量用3.0以上版本的health包,老版本对Android13、iOS17的权限适配有很多bug,跑起来会出现各种莫名其妙的问题

内容的提问来源于stack exchange,提问作者Vectorr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 08:33:10