Easily transform your platform with our SDK: white-labeled workouts with precise motion tracking and real-time feedback tailored for accuracy and engagement
0b36f063-376b-4c30-a543-9112c4dc7e92.mp4
Welcome to the documentation for the KinesteX SDK for Kotlin. This SDK allows you to integrate AI-powered fitness and physio workouts into your app with ease. The KinesteX SDK offers a variety of integration options, detailed user feedback, and customizable features to create an immersive fitness experience.
Integration Option | Description | Features | Details |
---|---|---|---|
Complete User Experience | Leave it to us to recommend the best workout routines for your customers, handle motion tracking, and overall user interface. High level of customization based on your brand book for a seamless experience. | - Long-term lifestyle workout plans - Specific body parts and full-body workouts - Individual exercise challenges (e.g., 20 squat challenge) |
View Integration Options |
Custom User Experience | Integrate the camera component with motion tracking. Real-time feedback on all customer movements. Control the position, size, and placement of the camera component. | - Real-time feedback on customer movements - Communication of every repeat and mistake - Customizable camera component position, size, and placement |
View Details |
Add the following permissions to your AndroidManifest.xml
:
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
Add the JitPack repository to your project’s settings.gradle
or build.gradle
(if settings.gradle
is not your primary dependency resolution file):
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Add the KinesteX SDK dependency in your app’s build.gradle
:
implementation("com.github.KinesteX:KinesteXSDKKotlin:1.1.7")
-
Prerequisites: Ensure you’ve added the necessary permissions in
AndroidManifest.xml
. -
Project setup: When a user starts a workout, we need to present camera permission dialog. We are requesting camera permission on the app level and need to handle the result in the app level as well.
2.1 Make sure your activity or fragment implements the
PermissionHandler
interface:class MainActivity : AppCompatActivity(), PermissionHandler
2.2 Create necessary variables and override therequestCameraPermission
method inPermissionHandler
interface:private var kinesteXWebView: GenericWebView? = null private val requestPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted: Boolean -> kinestexWebView?.handlePermissionResult(isGranted) } override fun requestCameraPermission() { requestPermissionLauncher.launch(Manifest.permission.CAMERA) }
-
To launch Complete UX call
createMainView
in KinesteXSDK:@SuppressLint("SetJavaScriptEnabled", "MissingInflatedId") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // OPTIONAL: Custom Parameters val data = mutableMapOf<String, Any>() data["isHideHeaderMain"] = false // should display header in main screen kinesteXWebView = KinesteXSDK.createMainView( this, apiKey, company, userId, getPlanCategory(subOption), null, customParams = data, // example of using custom parameters. CAN BE NULL viewModel.isLoading, ::handleWebViewMessage, permissionHandler = this ) as GenericWebView? }
-
Handling the data: Use a ViewModel to handle changes:
class ContentViewModel : ViewModel() { val showWebView: MutableStateFlow<WebViewState> = MutableStateFlow(WebViewState.LOADING) // state of the webview: LOADING, ERROR, SUCCESS var selectedOptionPosition: MutableStateFlow<Int> = MutableStateFlow(0) // for the selected integration option (not necessary unless combining our solutions) val isLoading: MutableStateFlow<Boolean> = MutableStateFlow(false)// loading state of the webview // CAMERA COMPONENT SPECIFIC val reps: MutableStateFlow<Int> = MutableStateFlow(0) // for reps IF using our camera component val mistake: MutableStateFlow<String> = MutableStateFlow("") // for mistakes IF using our camera component }
The KinesteX SDK provides multiple methods to create different views:
-
Main View (Complete User Experience):
kinesteXWebView = KinesteXSDK.createMainView( this, apiKey, company, userId, PlanCategory.Cardio, // selected to plan category null, // user details customParams = data, // example of using custom parameters viewModel.isLoading, ::handleWebViewMessage, // callback function to handle responses permissionHandler = this // permission handler ) as GenericWebView?
-
Plan View (Stand-alone workout plan page):
kinesteXWebView = KinesteXSDK.createPlanView( this, apiKey, company, userId, "Circuit Training", // name of the workout plan null, null, // custom parameters is null viewModel.isLoading, ::handleWebViewMessage, permissionHandler = this ) as GenericWebView?
-
Workout View (Individual workout page):
kinesteXWebView = KinesteXSDK.createWorkoutView( this, apiKey, company, userId, "Fitness Lite", // name of the workout null, isLoading = viewModel.isLoading, onMessageReceived = ::handleWebViewMessage, permissionHandler = this ) as GenericWebView?
-
Challenge View:
kinesteXWebView = KinesteXSDK.createChallengeView( this, apiKey, company, userId, "Squats", // name of the exercise 100, // countdown of the challenge null, customParams = null, viewModel.isLoading, ::handleWebViewMessage, permissionHandler = this ) as GenericWebView?
-
Experiences View:
kinesteXWebView = KinesteXSDK.createExperiencesView( apiKey, company, userId, "box", // name of the experience 100, // duration of the experience null, customParams = null, viewModel.isLoading, ::handleWebViewMessage, permissionHandler = this ) as GenericWebView?
-
Camera Component (Just camera + our motion analysis and feedback):
kinesteXWebView = KinesteXSDK.createCameraComponent( context = context, apiKey = apiKey, companyName = company, userId = userId, currentExercise = "Squats", // current exercise name exercises = listOf("Squats","Jumping Jack"), // exercises that user is expected to do user = null, isLoading = viewModel.isLoading, onMessageReceived = ::handleWebViewMessage, permissionHandler = this ) as GenericWebView?
The SDK sends various messages through the WebView. Implement a callback to handle these messages:
private fun handleWebViewMessage(message: WebViewMessage) {
when (message) {
is WebViewMessage.ExitKinestex -> lifecycleScope.launch {
viewModel.showWebView.emit(
WebViewState.ERROR
)
}
// FOR CAMERA SPECIFIC INTEGRATION GET NUMBER OF REPS IN REAL-TIME AND MISTAKES
is WebViewMessage.Reps -> {
(message.data["value"] as? Int)?.let { viewModel.setReps(it) }
}
is WebViewMessage.Mistake -> {
(message.data["value"] as? String)?.let {
viewModel.setMistake(
it
)
}
}
else -> {
// handle all other messages
Log.d("Message received", message.toString())
}
}
}
Use the following method to update the current exercise in the camera component:
KinesteXSDK.updateCurrentExercise("Jumping Jack") // this exercise has to be from the list of exercises we are tracking
The KinesteX SDK provides various data points that are returned through the message callback. Here are the available data types:
Type | Data | Description |
---|---|---|
kinestex_launched |
dd mm yyyy hours:minutes:seconds |
When a user has launched KinesteX |
exit_kinestex |
date: dd mm yyyy hours:minutes:seconds , time_spent: number |
Logs when a user clicks the exit button and the total time spent |
plan_unlocked |
title: String, date: date and time |
Logs when a workout plan is unlocked by a user |
workout_opened |
title: String, date: date and time |
Logs when a workout is opened by a user |
workout_started |
title: String, date: date and time |
Logs when a workout is started by a user |
exercise_completed |
time_spent: number , repeats: number , calories: number , exercise: string , mistakes: [string: number] |
Logs each time a user finishes an exercise |
total_active_seconds |
number |
Logs every 5 seconds, counting the active seconds a user has spent working out |
left_camera_frame |
number |
Indicates that a user has left the camera frame |
returned_camera_frame |
number |
Indicates that a user has returned to the camera frame |
workout_overview |
workout: string , total_time_spent: number , total_repeats: number , total_calories: number , percentage_completed: number , total_mistakes: number |
Logs a complete summary of the workout |
exercise_overview |
[exercise_completed] |
Returns a log of all exercises and their data |
workout_completed |
workout: string , date: dd mm yyyy hours:minutes:seconds |
Logs when a user finishes the workout and exits the workout overview |
active_days (Coming soon) |
number |
Represents the number of days a user has been opening KinesteX |
total_workouts (Coming soon) |
number |
Represents the number of workouts a user has done since starting to use KinesteX |
workout_efficiency (Coming soon) |
number |
Represents the level of intensity with which a person has completed the workout |
For any questions, contact us at support@kinestex.com.
The KinesteX SDK is licensed under the Apache License, Version 2.0. See the LICENSE file for more details.