sonarfit_flutter 1.0.0 copy "sonarfit_flutter: ^1.0.0" to clipboard
sonarfit_flutter: ^1.0.0 copied to clipboard

PlatformiOS

Flutter plugin for SonarFit SDK - AI-powered strength training with real-time rep detection

SonarFit Flutter Plugin #

Official Flutter plugin for the SonarFit SDK - AI-powered strength training with real-time rep detection using Apple Watch or AirPods Pro motion sensors.

pub package Platform

Features #

  • Real-time Rep Detection: AI-powered motion analysis counts reps automatically
  • Multiple Exercise Support: Squats, deadlifts, bench press, and more
  • Device Flexibility: Works with Apple Watch or AirPods Pro
  • Built-in UI: Beautiful, ready-to-use workout interface
  • Progress Tracking: Automatic set/rep tracking with rest timers
  • Permission Handling: Automatic motion permission requests

Platform Support #

Platform Support
iOS ✅ 17.0+
Android ❌ Not supported

Installation #

Add this to your pubspec.yaml:

dependencies:
  sonarfit_flutter: ^1.0.0

Then run:

flutter pub get

iOS Configuration #

  1. Update iOS deployment target in ios/Podfile:
platform :ios, '17.0'
  1. Add required permissions to ios/Runner/Info.plist:
<key>NSMotionUsageDescription</key>
<string>SonarFit needs motion sensor access to count your reps during workouts</string>

<key>NSHealthUpdateUsageDescription</key>
<string>SonarFit needs HealthKit access to save your workout data</string>

<key>NSHealthShareUsageDescription</key>
<string>SonarFit needs HealthKit access to read your workout history</string>
  1. Install CocoaPods dependencies:
cd ios && pod install && cd ..

Quick Start #

1. Initialize the SDK #

Get your API key from https://sonarfit.com/get-started

import 'package:sonarfit_flutter/sonarfit_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize SonarFit SDK
  await SonarFit.initialize('your-api-key-here');

  runApp(MyApp());
}

2. Present a Workout #

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

class WorkoutScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('SonarFit Workout')),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            try {
              final result = await SonarFit.presentWorkout(
                WorkoutConfig(
                  workoutType: WorkoutType.squat,
                  sets: 3,
                  reps: 10,
                  restTime: 60,
                ),
              );

              if (result.completed) {
                print('Workout completed!');
                print('Reps: ${result.totalRepsCompleted}/${result.totalTargetReps}');
                print('Completion: ${(result.completionPercentage * 100).toStringAsFixed(0)}%');
              } else if (result.cancelled) {
                print('Workout cancelled');
              }
            } on SonarFitException catch (e) {
              print('Error: ${e.message}');
            }
          },
          child: Text('Start Workout'),
        ),
      ),
    );
  }
}

API Reference #

SonarFit #

Main entry point for the SDK.

Methods

initialize(String apiKey)

Initialize the SDK with your API key. Must be called before using any other methods.

await SonarFit.initialize('your-api-key');

Throws: SonarFitException if initialization fails.


presentWorkout(WorkoutConfig config)

Present SonarFit's built-in workout UI.

final result = await SonarFit.presentWorkout(
  WorkoutConfig(
    workoutType: WorkoutType.squat,
    sets: 3,
    reps: 10,
    restTime: 60,
    countdownDuration: 3,
    autoReLift: true,
    deviceType: DeviceType.none, // Auto-detect
  ),
);

Returns: WorkoutResult when workout completes or user dismisses.

Throws: SonarFitException if workout fails to start.


WorkoutConfig #

Configuration for a workout session.

Properties

Property Type Required Default Description
workoutType WorkoutType Yes - Type of exercise
sets int Yes - Number of sets
reps int Yes - Target reps per set
restTime int No 60 Rest duration in seconds
countdownDuration int No 3 Countdown before each set
autoReLift bool No true Auto-detect reps
deviceType DeviceType No none Motion tracking device

Example

final config = WorkoutConfig(
  workoutType: WorkoutType.deadlift,
  sets: 5,
  reps: 5,
  restTime: 90,
  countdownDuration: 5,
  autoReLift: true,
  deviceType: DeviceType.watch,
);

WorkoutType #

Supported exercise types.

enum WorkoutType {
  squat,
  deadlift,
  benchpress,
}

DeviceType #

Motion tracking devices.

enum DeviceType {
  none,     // Auto-detect available device
  watch,    // Apple Watch
  airpods,  // AirPods Pro/Max with motion sensors
}

WorkoutResult #

Result of a completed workout.

Properties

Property Type Description
completed bool Was the workout completed?
cancelled bool Was the workout cancelled by user?
workoutType WorkoutType? Exercise type
deviceType DeviceType? Device used for tracking
startTime DateTime? Workout start time
endTime DateTime? Workout end time
totalDuration double? Total duration in seconds
completionPercentage double Completion percentage (0.0-1.0)
targetSets int? Target number of sets
targetRepsPerSet int? Target reps per set
totalRepsCompleted int Total reps completed
totalTargetReps int? Total target reps
sets List<WorkoutSet> Per-set details

Example

if (result.completed) {
  print('Completed ${result.totalRepsCompleted}/${result.totalTargetReps} reps');
  print('${(result.completionPercentage * 100).toStringAsFixed(0)}% complete');

  for (var set in result.sets) {
    print('Set ${set.setNumber}: ${set.repsCompleted} reps');
  }
}

SonarFitException #

Exception thrown by SDK operations.

Properties

Property Type Description
code String Error code
message String Human-readable error message
details dynamic Additional error details

Common Error Codes

Code Description
E_INIT_FAILED SDK initialization failed
E_PERMISSION Motion permission denied
E_INVALID_CONFIG Invalid workout configuration
E_NO_ROOT_VC Cannot find root view controller

Examples #

Complete Workout Flow #

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

class WorkoutExampleScreen extends StatefulWidget {
  @override
  _WorkoutExampleScreenState createState() => _WorkoutExampleScreenState();
}

class _WorkoutExampleScreenState extends State<WorkoutExampleScreen> {
  WorkoutResult? _lastResult;
  bool _isLoading = false;

  Future<void> _startWorkout() async {
    setState(() => _isLoading = true);

    try {
      final result = await SonarFit.presentWorkout(
        WorkoutConfig(
          workoutType: WorkoutType.squat,
          sets: 3,
          reps: 10,
          restTime: 60,
        ),
      );

      setState(() {
        _lastResult = result;
        _isLoading = false;
      });

      if (result.completed) {
        _showCompletionDialog(result);
      }
    } on SonarFitException catch (e) {
      setState(() => _isLoading = false);
      _showErrorDialog(e);
    }
  }

  void _showCompletionDialog(WorkoutResult result) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Workout Complete! 🎉'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Reps: ${result.totalRepsCompleted}/${result.totalTargetReps}'),
            Text('Completion: ${(result.completionPercentage * 100).toStringAsFixed(0)}%'),
            SizedBox(height: 16),
            Text('Sets:', style: TextStyle(fontWeight: FontWeight.bold)),
            ...result.sets.map((set) =>
              Text('Set ${set.setNumber}: ${set.repsCompleted} reps')),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text('OK'),
          ),
        ],
      ),
    );
  }

  void _showErrorDialog(SonarFitException error) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Error'),
        content: Text(error.message),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text('OK'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('SonarFit Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            if (_isLoading)
              CircularProgressIndicator()
            else
              ElevatedButton(
                onPressed: _startWorkout,
                child: Text('Start Workout'),
              ),
            if (_lastResult != null) ...[
              SizedBox(height: 32),
              Text(
                'Last Workout',
                style: Theme.of(context).textTheme.headlineSmall,
              ),
              SizedBox(height: 8),
              Text('${_lastResult!.totalRepsCompleted} reps completed'),
              Text('${(_lastResult!.completionPercentage * 100).toStringAsFixed(0)}% complete'),
            ],
          ],
        ),
      ),
    );
  }
}

Multiple Workout Types #

class WorkoutTypeSelector extends StatelessWidget {
  final List<WorkoutType> workouts = [
    WorkoutType.squat,
    WorkoutType.deadlift,
    WorkoutType.benchpress,
  ];

  Future<void> _startWorkout(BuildContext context, WorkoutType type) async {
    try {
      final result = await SonarFit.presentWorkout(
        WorkoutConfig(
          workoutType: type,
          sets: 3,
          reps: 10,
        ),
      );

      if (result.completed) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Workout completed! ${result.totalRepsCompleted} reps')),
        );
      }
    } on SonarFitException catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error: ${e.message}')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: workouts.length,
      itemBuilder: (context, index) {
        final workout = workouts[index];
        return ListTile(
          title: Text(_getWorkoutName(workout)),
          trailing: Icon(Icons.arrow_forward),
          onTap: () => _startWorkout(context, workout),
        );
      },
    );
  }

  String _getWorkoutName(WorkoutType type) {
    switch (type) {
      case WorkoutType.squat:
        return 'Squat';
      case WorkoutType.deadlift:
        return 'Deadlift';
      case WorkoutType.benchpress:
        return 'Bench Press';
    }
  }
}

Pricing #

SonarFit uses MAU-based pricing (Monthly Active Users). A user counts as active when they complete at least one workout in a calendar month.

Tier Price Included MAUs Overage
Developer Free 500 (hard cap) N/A
Startup £129/mo 2,000 £0.08/MAU
Growth £599/mo 10,000 £0.07/MAU
Enterprise Custom Negotiated Custom

Get started at https://sonarfit.com/pricing

Requirements #

  • Flutter: 3.3.0 or higher
  • Dart: 3.0.0 or higher
  • iOS: 17.0 or higher
  • Xcode: 16.0 or higher
  • CocoaPods: 1.11.0 or higher

Troubleshooting #

Build Errors #

Error: "Platform version is lower than 17.0"

Solution: Update ios/Podfile:

platform :ios, '17.0'

Error: "No such module 'SonarFitKit'"

Solution: Run:

cd ios && pod install && cd ..
flutter clean
flutter pub get

Runtime Errors #

Error: "Motion permission denied"

Solution: Add NSMotionUsageDescription to Info.plist and ensure user grants permission when prompted.


Error: "SDK not initialized"

Solution: Call SonarFit.initialize() before using any other methods.


Support #

License #

MIT License - see LICENSE file for details

About SonarFit #

SonarFit provides AI-powered workout execution intelligence for fitness apps. Our SDK handles real-time rep counting, form analysis, and workout progression so you can focus on building great user experiences.

Learn more at https://sonarfit.com

0
likes
150
points
96
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for SonarFit SDK - AI-powered strength training with real-time rep detection

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on sonarfit_flutter

Packages that implement sonarfit_flutter