如何在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
相关产品推荐
相关产品推荐

