flutter_smkit_ui 1.6.1
flutter_smkit_ui: ^1.6.1 copied to clipboard
Flutter plugin for Sency's SMKitUI SDK on iOS and Android, including assessments, workouts, guidance, summaries, and runtime configuration.
SMKitUI Flutter Plugin (v1.6.1) #
A Flutter plugin for integrating Sency's SMKitUI SDK, supporting both iOS and Android. Run fitness, body360, strength, cardio, and custom assessments and workouts with unified user data, summary options, skeleton visualization, and runtime modifications.
Requirements #
- Flutter: 3.44.0+
- Dart: 3.12.0+
- iOS: 16.0+, SMKitUI 2.5.9, SMKit 2.5.9
- Android: Android 7.0+ (API 24), compileSdk 36, SMKitUI 1.9.6, SMKit 1.9.6, Gradle 8.14, AGP 8.13.2, Kotlin 2.2.20, Java 17
Getting Started #
1. Configure #
final _smkitUiFlutterPlugin = SmkitUiFlutterPlugin();
await _smkitUiFlutterPlugin.configure(
key: apiPublicKey,
// customerCode: 'CUSTOMER_CODE', // when your customer assets require one
poseModelChoice: SmKitPoseModelChoice.adaptiveChoice,
configureLanguage: SMKitLanguage.english,
includesHighlights: false, // iOS only
);
Available Android pose choices:
adaptiveChoice, prime, pro, lite, ultraLite, basic.
On iOS this parameter is accepted for API parity and currently ignored.
configureLanguage defaults to English and controls configure-time voice feedback asset selection.
2. Apply SDK Config (Optional) #
Set includeAssessmentInsights before configure to download insights for
custom assessments. On Android, exerciseSummaryTimingMetrics also requires
another configure call after it changes. The iOS bridge reads
includeAssessmentInsights on each configure call.
await _smkitUiFlutterPlugin.setConfig(
config: SMKitConfig(
includeAssessmentInsights: true,
exerciseSummaryTimingMetrics: true,
guidanceModeSuggestion: true,
feedbackFrequency: SMKitFeedbackFrequency.normal,
voiceFeedbackVoice: SMKitVoice.male1,
mobilityFlowVoice: SMKitVoice.female1,
automaticallyPreloadModels: true, // iOS only
enableDiagnostics: true, // iOS only
enableIntelligenceRest: true,
startTimerOnFirstActivity: true,
workoutContinuationTimerDuration: 10,
colorTheme: SMKitColorTheme.green,
playPhoneCalibrationAudio: true,
allowAudioMixing: false,
instructionVideoConfig: InstructionVideoConfig(
displayMode: InstructionVideoDisplayMode.mediumCycle,
mediumSizeCycles: 2,
),
skeletonConfig: SkeletonConfig(preset: SkeletonPreset.neonGlow),
pauseTypes: [SMKitPauseType.resume, SMKitPauseType.quit],
),
);
The two voice choices take effect on the next configure call. On iOS,
quitWorkout() completes after native teardown and reports teardown errors.
For iOS model preparation and customer assets, use preloadModels(),
getCustomerAssetPath(identifier: ...), or
requestCustomerAssetPath(identifier: ...). Android customer asset calls return
the local path when available; Android does not expose manual model preloading.
The iOS diagnostics stream emits SMKitDiagnosticEvent values when enabled.
For a custom assessment, set exportInternalInsights: true on the
SMKitWorkout to include downloaded insights in the result. Exercises may
also set internalInsightsKey to select an insights asset. A static position
exercise can use SMKitPositionRepConfig(targetReps: 3, secondsPerRep: 5) via
positionRepConfig to perform repeated timed holds.
3. Set Preferences (Optional) #
_smkitUiFlutterPlugin.setSessionLanguage(language: SMKitLanguage.english);
_smkitUiFlutterPlugin.setCounterPreferences(counterPreferences: SMKitCounterPreferences.perfectOnly);
_smkitUiFlutterPlugin.setEndExercisePreferences(endExercisePrefernces: SMKitEndExercisePreferences.targetBased);
4. Start an Assessment #
_smkitUiFlutterPlugin.startAssessment(
type: AssessmentTypes.body360, // fitness, body360, strength, cardio, custom
userData: {
'gender': 'Male', // or 'Female', 'Idle'
'birthday': DateTime(1990, 1, 1).millisecondsSinceEpoch,
},
showSummary: true,
forceShowUserDataScreen: false,
modifications: {
'primaryColor': '#4CAF50',
'phoneCalibration': {'enabled': true},
},
onHandle: (status) {
if (status.operation == SMKitOperation.assessmentSummaryData) {
final summary = status.data as SMKitAssessmentSummaryData;
} else if (status.operation == SMKitOperation.error) {
final error = status.data as SMKitError;
}
},
);
5. Start a Customized Workout #
_smkitUiFlutterPlugin.startCustomizedWorkout(
workout: SMKitWorkout(
id: '1',
name: 'My Workout',
exercises: [
SMKitExercise(
detector: 'SquatRegular',
prettyName: 'Squat',
totalSeconds: 30,
uiElements: [SMKitUIElement.repsCounter, SMKitUIElement.timer],
shortIntro: true,
adaptiveRomFeedbackEnabled: true,
),
],
continuation: SMKitWorkoutContinuation(
interactionUnlockSoundKey: 'ContinueWorkoutPrompt',
exercises: [
SMKitExercise(detector: 'Rest', prettyName: 'Rest', totalSeconds: 10),
],
),
),
modifications: {'primaryColor': '#2196F3'},
onHandle: (status) { ... },
);
6. Start a Customized Assessment #
final targetReps = 5;
await _smkitUiFlutterPlugin.setEndExercisePreferences(
endExercisePrefernces: SMKitEndExercisePreferences.targetBased,
);
_smkitUiFlutterPlugin.startCustomizedAssessment(
assessment: SMKitWorkout(
id: 'assessment-1',
name: 'Target Reps Assessment',
exercises: [
SMKitExercise(
detector: 'SquatRegular',
prettyName: 'Squat',
totalSeconds: 30, // still required by the native model
uiElements: [SMKitUIElement.repsCounter, SMKitUIElement.gaugeOfMotion],
showTargetProgress: true,
scoringParams: ScoringParams.targetReps(
targetReps: targetReps,
scoreFactor: 0.5,
),
),
],
),
showSummary: true,
forceShowUserDataScreen: false,
modifications: {'primaryColor': '#FF9800'},
onHandle: (status) { ... },
);
For rep-scored dynamic assessments, targetReps stays available for scoring
and summary data. Add showTargetProgress: true when the exercise should render
completed/target reps and finish at the target without running the countdown
timer; omit it to keep the normal timer behavior.
7. Start a Workout Program #
_smkitUiFlutterPlugin.startWorkoutProgram(
config: WorkoutConfig(
programId: 'my-program-id',
week: 1,
bodyZone: BodyZone.fullBody,
difficultyLevel: DifficultyLevel.midDifficulty,
workoutDuration: WorkoutDuration.short,
language: SencySupportedLanguage.english,
shortIntro: true,
phonePosition: SMKitPhonePosition.floor, // iOS only
),
modifications: {'primaryColor': '#4CAF50'},
onHandle: (status) { ... },
);
SMKitConfig Reference #
| Field | Type | Description |
|---|---|---|
enableIntelligenceRest |
bool? |
Enable AI-based rest detection |
enableHeartRateRest |
bool? |
Enable Apple Watch heart-rate rest suggestions on iOS |
heartRateRestThreshold |
int? |
iOS heart-rate threshold for rest suggestions |
allowAudioMixing |
bool? |
Allow app audio to mix with SDK audio |
showExternalAudioControl |
bool? |
Show external audio control button |
playPhoneCalibrationAudio |
bool? |
Play phone calibration audio |
playBodyCalibrationAudio |
bool? |
Play body calibration audio |
enableButtonTutorial |
bool? |
Enable hover-button tutorial |
buttonTutorialCompletionAudioPath |
String? |
Local or URL audio for tutorial completion |
enableWatchCompanion |
bool? |
Enable Apple Watch companion |
accuratePoseEstimation |
bool? |
Enable high-accuracy pose estimation |
showRowingPhoneCalibration |
bool? |
Show rowing phone calibration screen |
enablePhoneMovementCountPrevention |
bool? |
Block counting while phone movement is detected |
enableVariationMismatchFeedback |
bool? |
Play mismatch feedback for static/dynamic variation errors |
startTimerOnFirstActivity |
bool? |
Start timer only after first rep or in-position frame |
workoutContinuationTimerDuration |
int? |
Continuation prompt timer in seconds |
colorTheme |
SMKitColorTheme? |
Direct SDK theme selection |
skeletonConfig |
SkeletonConfig? |
Skeleton visualization settings |
pauseTypes |
List<SMKitPauseType>? |
Pause overlay buttons |
instructionVideoConfig |
InstructionVideoConfig? |
Instruction video display mode |
useDefaultGuidanceMode |
bool? |
Android guidance default mode |
guidanceDebugLogging |
bool? |
Native guidance debug logging |
androidConfigString |
String? |
Android native flat config string |
showDebugBoundingBox |
bool? |
iOS debug bounding box |
Runtime Controls #
await _smkitUiFlutterPlugin.quitWorkout();
await _smkitUiFlutterPlugin.pauseSdk(); // iOS only
await _smkitUiFlutterPlugin.resumeSdk(); // iOS only
await _smkitUiFlutterPlugin.clearAdaptiveRomCache(); // Android only
await _smkitUiFlutterPlugin.setFeedbacksUiToExclude(
feedbacks: ['SquatHipCreaseDepth'],
);
await _smkitUiFlutterPlugin.setExcludedFeedbacks(
feedbacks: ['SquatHipCreaseDepth'], // iOS only
);
final movements = await _smkitUiFlutterPlugin.getSupportedMovements(); // iOS only
final type = await _smkitUiFlutterPlugin.getExerciseType(detector: 'SquatRegular'); // iOS only
SkeletonConfig #
Customize skeleton overlay: preset, connectionStyle, jointShape, dotsOpacity, connectionsOpacity, dotsInnerColor, dotsOuterColor, dotsGlow, connectionsGlow, lineWidthScale, outlineScale, softness, animationDuration, hidden.
Modifications Map #
| Key | Type | Description |
|---|---|---|
primaryColor |
String |
Hex color for UI theme (maps to green/blue/orange/purple/silver/gold/pink) |
phoneCalibration.enabled |
bool |
Show/hide phone calibration screen |
Platform Notes #
forceShowUserDataScreenis iOS-only.pauseSdk,resumeSdk,setExcludedFeedbacks,getSupportedMovements,getExerciseType,includesHighlights,WorkoutConfig.phonePosition, andshowDebugBoundingBoxare iOS-only.clearAdaptiveRomCache,useDefaultGuidanceMode,guidanceDebugLogging, andandroidConfigStringare Android-only.SMKitPauseType.restandswitchExerciseare Android-only.WorkoutConfigenums use PascalCase on the wire (FullBody,MidDifficulty,Short,English).- Native SDK 2.5.9/1.9.6 support English and Hebrew. Configure defaults to English.
Changelog #
See CHANGELOG.md for details.
Additional iOS bridge controls #
SMKitConfig now accepts enablePerExerciseBodyCalibration,
enableBodyCalibrationObjectDetection, bodyCalibrationRequiredObjectClasses,
enableObjectDetectionFeedbacks, showAllSkeletonKeypoints,
mobilityFlowHoldIndicatorStyle, hostManagedExternalAudioDucking, and
usePlayAndRecordForSDKSounds. Set these before configure when they affect
model loading or startup. configure also accepts
includesObjectDetectionFeedbacks and modelDownloadPolicy on iOS.
Android 1.9.6 rejects non-default values for these two configure options.
The iOS session methods skipCurrentExercise, handleExternalCallback,
loadInstructionVideo, and setVideo are exposed. Android 1.9.6 reports
unsupported for these methods. The native iOS external callback API is
deprecated and currently returns false. Set an exercise's
targetRepsTimerDisplayMode to repsProgress or timeProgress to control
its iOS target-reps timer.
Note: iOS 2.5.9 accepts enablePerExerciseBodyCalibration, but its native per-exercise flow is currently disabled by an internal release gate.
License #
MIT
Android 1.9.6 / iOS 2.5.9 release candidate #
Configure before restoring history, and restore only between workouts. Pass the saved exercise adaptive-ROM payload objects, not entire workout summaries. The native SDK accepts snake_case or camelCase snapshot fields, ignores incompatible detector revisions, and preserves higher local records. The returned integer is the count accepted by the native SDK. Keep these snapshots in your account history.
Mandarin uses zh; startup prompts support the native male_1 and female_1 voices.
Downloaded voice assets are still required for other prompts. This is not a
promise that every prompt or screen has a Mandarin translation.
await sdk.configure(key: apiKey, configureLanguage: SMKitLanguage.mandarin);
final accepted = await sdk.mergeAdaptiveRomPilotCache(savedSnapshots);
// Save exercise.adaptiveRom from the workout summary for next time.