Flutter健身工作流插件flutter_workoutkit的使用

Flutter健身工作流插件flutter_workoutkit的使用

pub points pub package platform License: Apache 2.0

注意此插件仅适用于iOS 17.0及以上设备,并且需要与iOS设备配对的Apple Watch。不支持Android设备。

一个利用Apple的WorkoutKit SDK来创建、预览和同步自定义运动的Flutter插件。该插件使Flutter应用与WatchOS的运动功能无缝集成,允许开发者通过编程方式定义和管理用户可以直接在Apple Watch上访问的运动计划。

🚨 积极开发中!

该插件目前处于积极开发阶段。可能会有破坏性更改,直到版本1.0.0发布。在生产环境中使用此插件时请自行承担风险。如有任何问题或功能请求,请在GitHub仓库中报告。

🔑 关键特性

  • 创建、预览和同步自定义运动。
  • 使用小部件定义自定义、单目标、配速或游泳骑行跑步的运动计划。
  • 设置每个运动步骤的目标,例如时间、距离或重复次数。
  • 设置各种警报,如心率区间、配速和功率区间。
  • 与Apple Watch上的运动应用完美配合。

🎥 预览

Demo 1

📸 截图

Screenshot 1 Screenshot 2

📝 示例运动

final CustomWorkout speedCyclingWorkout = CustomWorkout(
  activityType: WorkoutActivityType.cycling,
  location: WorkoutLocationType.outdoor,
  displayName: "Speed Cycling",
  warmup: WorkoutStep(
    alert: HeartRateZoneAlert(zone: 1),
    goal: const WorkoutGoal(
      type: WorkoutGoalType.time,
      targetDuration: Duration(minutes: 10),
      unit: WorkoutGoalUnit.minutes,
    ),
  ),
  blocks: [
    IntervalBlock(
      type: IntervalBlockType.work,
      iterations: 1,
      steps: [
        IntervalStep(
          alert: SpeedRangeAlert(
            lowerBound: 28,
            upperBound: 32,
            unitSpeed: UnitSpeed.kilometersPerHour,
            metric: WorkoutAlertMetric.average,
          ),
          purpose: IntervalStepPurpose.work,
          goal: const WorkoutGoal(
            type: WorkoutGoalType.distance,
            targetValue: 24,
            unit: WorkoutGoalUnit.kilometers,
          ),
        ),
      ],
    ),
  ],
  cooldown: WorkoutStep(
    alert: HeartRateZoneAlert(zone: 1),
    goal: const WorkoutGoal(
      type: WorkoutGoalType.time,
      targetDuration: Duration(minutes: 10),
      unit: WorkoutGoalUnit.minutes,
    ),
  ),
);

📥 安装

在您的Flutter项目中的pubspec.yaml文件内添加flutter_workoutkit作为依赖项:

dependencies:
  flutter_workoutkit: <latest_version>

此插件需要在项目中启用HealthKit。确保在Info.plist文件中有必要的权限:

<key>NSHealthShareUsageDescription</key>
<string>允许访问健康数据以跟踪运动。</string>
<key>NSHealthUpdateUsageDescription</key>
<string>允许更新健康数据以跟踪运动。</string>

同时,确保在Xcode项目中启用了必要的功能:

Xcode Capabilities

📚 使用

您可以使用四种运动类之一来定义运动:

  • CustomWorkout
  • PacerWorkout
  • SwimBikeRunWorkout
  • SingleGoalWorkout

您可以在插件包内的lib/sampleWorkouts文件夹或示例应用中查看每种运动的预览示例。

要预览并同步运动,可以使用WorkoutPreviewButton小部件:

WorkoutPreviewButton(workout: speedCyclingWorkout);

WorkoutPreviewButton小部件会自动调用原生的workoutPreview()方法来预览运动,并允许用户将运动保存到他们的Apple Watch。

在预览运动之前,必须请求健康权限:

import 'package:flutter_workoutkit/flutter_workoutkit.dart';

await Workoutkit.hasHealthPermissions();
await Workoutkit.requestHealthPermissions();

🎨 自定义预览按钮

WorkoutKit框架当前只提供了触发运动预览模态窗口的原生按钮。没有API可以实现无用户交互地预览运动。

为了适应这一限制,该插件提供了一个WorkoutPreviewButton小部件,用于渲染原生iOS按钮。因此,目前对按钮的定制是有限的。请检查WorkoutPreviewButton小部件以获取可用的定制选项。

🚧 路线图

  • ✅ 添加支持WorkoutPreviewButton来预览运动
  • ✅ 添加基本定制选项给WorkoutPreviewButton小部件
  • ❌ 添加更多高级定制选项给WorkoutPreviewButton小部件
  • ❌ 添加支持WorkoutScheduler来安排和管理运动
  • ❌ 添加支持ScheduledWorkoutPlan来安排运动计划
  • ❌ 添加支持poolSwimDistanceWithTime来设置运动目标
  • ❌ 改进示例和示例应用
  • ❌ 改进文档
  • ❌ 添加测试
  • ❌ (长期)探索支持Android的选项

📝 许可证

该项目由Apache License 2.0许可。详情请参阅LICENSE文件。

📧 联系

如有问题或反馈,请联系我:a@adamkramer.dev

💰 请我喝杯咖啡

如果您觉得这个插件有用,请考虑买杯咖啡支持我:


示例代码

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

import 'package:flutter/services.dart';
import 'package:flutter_workoutkit/flutter_workoutkit.dart';

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

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  bool _hasHealthPermissions = false;

  [@override](/user/override)
  void initState() {
    super.initState();
    initPlatformState();
  }

  // 平台消息异步,因此我们初始化在一个异步方法中。
  Future<void> initPlatformState() async {
    String platformVersion;
    try {
      platformVersion =
          await Workoutkit.getPlatformVersion() ?? '未知平台版本';
    } on PlatformException {
      platformVersion = '无法获取平台版本。';
    }
    if (!mounted) return;
    setState(() {
      _platformVersion = platformVersion;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter WorkoutKit 示例'),
        ),
        body: CustomScrollView(
          slivers: [
            SliverToBoxAdapter(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: ElevatedButton(
                      onPressed: () => Workoutkit.requestHealthPermissions(),
                      child: const Text('请求健康权限'),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: ElevatedButton(
                      onPressed: () =>
                          Workoutkit.hasHealthPermissions().then((value) {
                        setState(() {
                          _hasHealthPermissions = value;
                        });
                      }),
                      child: const Text('检查健康权限'),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: Text('是否有健康权限: $_hasHealthPermissions'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: Center(
                      child: Text('运行于: $_platformVersion\n'),
                    ),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sampleSwimBikeRunWorkout,
                        buttonTitle: '[SwimBikeRun] 三项全能训练'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: samplePacerHoursWorkout,
                        buttonTitle: '[Pacer] 2 小时骑行'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: samplePacerMinutesWorkout,
                        buttonTitle: '[Pacer] 30 分钟跑步'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sampleSpeedCyclingWorkout,
                        buttonTitle: '[Custom] 速度骑行'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sampleCustomWorkout,
                        buttonTitle: '[Custom] 定时运动'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sample10kTrainingRun,
                        buttonTitle: '[Custom] 10公里训练跑'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sample21kmTrainingRun,
                        buttonTitle: '[Custom] 21公里分段跑'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sampleSingleGoalTimedWorkout,
                        buttonTitle: '[Single] 定时运动'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sampleSingleGoalEnergyWorkout,
                        buttonTitle: '[Single] 能量运动'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sampleSingleOpenWorkout,
                        buttonTitle: '[Single] 开放式运动'),
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                    child: WorkoutPreviewButton(
                        workout: sampleSingleGoalSwimmingWorkout,
                        buttonTitle: '[Single] 游泳运动'),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter健身工作流插件flutter_workoutkit的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter健身工作流插件flutter_workoutkit的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter健身工作流插件 flutter_workoutkit 的示例代码。这个插件通常用于管理和跟踪健身锻炼,包括创建锻炼计划、记录锻炼进度等功能。

首先,确保你已经在你的 pubspec.yaml 文件中添加了 flutter_workoutkit 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_workoutkit: ^最新版本号  # 请替换为最新的版本号

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

以下是一个简单的示例代码,展示如何使用 flutter_workoutkit 来创建一个锻炼计划并启动锻炼:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter WorkoutKit Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: WorkoutScreen(),
    );
  }
}

class WorkoutScreen extends StatefulWidget {
  @override
  _WorkoutScreenState createState() => _WorkoutScreenState();
}

class _WorkoutScreenState extends State<WorkoutScreen> {
  late WorkoutManager _workoutManager;

  @override
  void initState() {
    super.initState();
    // 初始化WorkoutManager
    _workoutManager = WorkoutManager();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter WorkoutKit Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                // 创建一个锻炼计划
                _createWorkoutPlan();
              },
              child: Text('Create Workout Plan'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // 启动锻炼
                _startWorkout();
              },
              child: Text('Start Workout'),
            ),
          ],
        ),
      ),
    );
  }

  void _createWorkoutPlan() {
    // 创建一个锻炼集合
    List<Exercise> exercises = [
      Exercise(
        name: 'Push-Ups',
        sets: 3,
        reps: 12,
        restTime: Duration(seconds: 30),
      ),
      Exercise(
        name: 'Squats',
        sets: 3,
        reps: 15,
        restTime: Duration(seconds: 30),
      ),
      // 添加更多锻炼...
    ];

    // 创建锻炼计划
    WorkoutPlan plan = WorkoutPlan(
      name: 'Daily Workout',
      exercises: exercises,
    );

    // 将计划添加到WorkoutManager中(假设插件支持这种操作,具体根据文档实现)
    // 注意:实际插件API可能不同,这里仅为示例
    _workoutManager.addPlan(plan);
    // 显示一个SnackBar通知用户计划已创建
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Workout plan created successfully!'),
      ),
    );
  }

  void _startWorkout() {
    // 假设我们已有一个计划要启动
    // WorkoutPlan plan = _workoutManager.getPlanByName('Daily Workout');
    // 注意:实际插件API可能不同,这里仅为示例

    // 启动锻炼(具体实现依赖于插件提供的API)
    // _workoutManager.startWorkout(plan);

    // 由于我们不知道插件的确切API,这里仅显示一个SnackBar作为示例
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('Workout started!'),
      ),
    );
  }
}

// 假设的Exercise类定义(根据插件实际要求调整)
class Exercise {
  String name;
  int sets;
  int reps;
  Duration restTime;

  Exercise({required this.name, required this.sets, required this.reps, required this.restTime});
}

// 假设的WorkoutPlan类定义(根据插件实际要求调整)
class WorkoutPlan {
  String name;
  List<Exercise> exercises;

  WorkoutPlan({required this.name, required this.exercises});
}

// 注意:上述Exercise和WorkoutPlan类仅为示例,实际使用时需要根据flutter_workoutkit插件的文档进行调整。
// 同时,WorkoutManager及其方法(如addPlan和startWorkout)也是假设的,实际API可能不同。

重要提示

  1. 由于 flutter_workoutkit 插件的具体API和实现细节可能与我提供的示例代码不同,因此你需要查阅该插件的官方文档来了解如何正确初始化、添加锻炼计划和启动锻炼。
  2. 上述代码中的 ExerciseWorkoutPlan 类是假设的,仅用于演示目的。你需要根据插件的实际数据结构进行调整。
  3. 插件的 WorkoutManager 类及其方法(如 addPlanstartWorkout)也是假设的,实际使用时请参考插件的API文档。

希望这个示例代码能帮助你入门如何使用 flutter_workoutkit 插件。如果你有更多具体问题或需要进一步的帮助,请查阅插件的官方文档或提出更详细的问题。

回到顶部