### Complete HTML Integration for TrainingKit Workout
Source: https://trainingkit.fizzup.com/web/quickstart.html
This example demonstrates a full HTML page setup to initialize TrainingKit and start a workout with various options and callbacks.
```html
```
--------------------------------
### Install JavaScript Dependencies
Source: https://trainingkit.fizzup.com/react-native/quickstart.html
Navigate to the `sample` directory and install the necessary JavaScript dependencies using Yarn.
```shell
cd sample
yarn install
```
--------------------------------
### Fetch and Install iOS Pods (if missing)
Source: https://trainingkit.fizzup.com/react-native/quickstart.html
If `pod install` fails due to a missing `TrainingKit.xcframework`, fetch it from the repository root and then reinstall the pods.
```shell
cd .. # back to the repository root
yarn fetch:ios-trainingkit
cd sample/ios
pod install
cd .. # back to sample/
```
--------------------------------
### trainingkit.start(options)
Source: https://trainingkit.fizzup.com/web/reference.html
Starts a workout session with specified options and listeners.
```APIDOC
## trainingkit.start(options)
### Description
Starts a workout session. This method accepts an options object that configures the workout experience and registers event listeners.
### Parameters
#### Request Body
- **options** (object) - Required - Configuration object for the workout session.
- **workoutId** (string) - Required - TrainingKit workout identifier to launch.
- **soundpack** (string) - Optional - Sound theme for the workout experience.
- **getAccessToken** (function) - Optional - Async callback returning a backend-issued access token.
- **onWorkoutQuit** (function) - Optional - Callback called when the user quits the workout.
- **onWorkoutSave** (function) - Optional - Callback called when workout data is saved.
- **onWorkoutEvent** (function) - Optional - Generic callback receiving event name and payload.
### Request Example
```json
{
"workoutId": "4RGZ7S46",
"soundpack": "none",
"getAccessToken": "async function() { return 'your-access-token' }",
"onWorkoutQuit": "function() {}",
"onWorkoutSave": "function(workoutData) {}",
"onWorkoutEvent": "function(action, payload) {}"
}
```
### Completion Listeners
Register workout listeners within the `trainingkit.start` call:
- **onWorkoutSave(workoutData)**: Triggered when the workout completes and produces session state. Payload: Workout result data.
- **onWorkoutQuit()**: Triggered when the user exits the workout without completing it. Payload: None.
- **onWorkoutEvent(action, payload)**: Triggered when TrainingKit emits a tracking event. Payload: Event name plus event properties.
```
--------------------------------
### Initialize GraphQL client and wrap app
Source: https://trainingkit.fizzup.com/flutter/usage.html
Initialize the GraphQL client with device identifier in headers and wrap your app with GraphQLProvider. This setup ensures that the client is configured correctly before the app starts.
```dart
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:trainingkit_flutter/trainingkit_flutter.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
final deviceId = await deviceIdentifier();
final locale = WidgetsBinding.instance.platformDispatcher.locale;
final link = HttpLink(
'https://your-graphql-endpoint/graphql',
defaultHeaders: {
'X-TrainingKit-Device': deviceId,
// Derived from the app locale — see "Language" below.
'Accept-Language': '${locale.languageCode}-${locale.countryCode}',
},
);
final client = ValueNotifier(GraphQLClient(link: link, cache: GraphQLCache()));
runApp(GraphQLProvider(client: client, child: const MyApp()));
}
```
--------------------------------
### Initialize and Start Workout - Vanilla JavaScript
Source: https://trainingkit.fizzup.com/web/usage.html
Use this pattern in a plain HTML or server-rendered page to initialize the SDK and start a workout. It logs workout quit, save, and event data to the console.
```javascript
trainingkit.init('https://cloud.YourCompany.fizzup.com')
trainingkit.start({
workoutId: '4RGZ7S46',
soundpack: 'none',
onWorkoutQuit: function () {
console.log('Event received: workout quit')
},
onWorkoutSave: function (workoutData) {
console.log('Event received: workout save', workoutData)
},
onWorkoutEvent: function (action, payload) {
console.log('Event received:', action, payload)
},
})
```
--------------------------------
### Install iOS Pods
Source: https://trainingkit.fizzup.com/react-native/quickstart.html
Navigate to the `ios` directory within `sample` and install the CocoaPods dependencies. This step requires macOS and Xcode.
```shell
cd ios
pod install
cd ..
```
--------------------------------
### Install Apollo Client for React
Source: https://trainingkit.fizzup.com/web/usage.html
Installs the necessary packages for using Apollo Client in a React application.
```bash
npm install @apollo/client graphql
```
--------------------------------
### Start Workout Session with Options
Source: https://trainingkit.fizzup.com/web/reference.html
Initiates a workout session using `trainingkit.start()`. Provide a `workoutId` and optionally configure `soundpack`, `getAccessToken`, and various event callbacks.
```javascript
trainingkit.start({
workoutId: '4RGZ7S46',
soundpack: 'none',
getAccessToken: async function () {
return 'your-access-token'
},
onWorkoutQuit: function () {},
onWorkoutSave: function (workoutData) {},
onWorkoutEvent: function (action, payload) {},
})
```
--------------------------------
### Clone the repository
Source: https://trainingkit.fizzup.com/flutter/quickstart.html
Clone the trainingkit-flutter repository and navigate to the example directory.
```sh
git clone https://github.com/getfizzup/trainingkit-flutter
cd trainingkit-flutter/example
```
--------------------------------
### Install Apollo Client for React Native
Source: https://trainingkit.fizzup.com/react-native/usage.html
Install the necessary Apollo Client packages. This is a prerequisite for using GraphQL with TrainingKit.
```sh
yarn add @apollo/client graphql
```
--------------------------------
### Install Flutter dependencies
Source: https://trainingkit.fizzup.com/flutter/quickstart.html
Install the necessary Flutter dependencies for the project.
```sh
flutter pub get
```
--------------------------------
### Android Setup: Provide GitHub Credentials
Source: https://trainingkit.fizzup.com/react-native/installation.html
Configure your GitHub username and token for accessing the Android SDK artifacts. This can be done either in 'android/local.properties' or by setting environment variables.
```properties
GithubUser=your-github-username
GithubToken=your-github-token
```
```sh
export GITHUB_USERNAME=your-github-username
export GITHUB_TOKEN=your-github-token
```
--------------------------------
### Get Access Token Function
Source: https://trainingkit.fizzup.com/web/authentication.html
Provide this function to `trainingkit.start()` when your integration requires authenticated requests. It fetches the token from your backend API.
```javascript
getAccessToken: async function () {
const response = await fetch('/api/trainingkit/token', {
method: 'POST',
credentials: 'include',
})
if (!response.ok) {
throw new Error('Unable to retrieve TrainingKit access token')
}
const data = await response.json()
return data.accessToken
}
```
--------------------------------
### Install React Native Package
Source: https://trainingkit.fizzup.com/react-native/installation.html
Use this command to add the training kit package to your React Native project. For local development, use a file path reference.
```sh
yarn add trainingkit-reactnative
```
```sh
yarn add file:../relative/path/to/trainingkit-reactnative
```
--------------------------------
### Install iOS Platform in Xcode
Source: https://trainingkit.fizzup.com/react-native/troubleshooting.html
If Xcode reports a missing iOS platform version, install it via Xcode's Settings. Then, rebuild the app.
```sh
yarn ios
```
--------------------------------
### Run Pods Through Bundler
Source: https://trainingkit.fizzup.com/react-native/troubleshooting.html
Execute `pod install` using Bundler after setting up the correct Ruby environment. This ensures consistent dependency management for iOS.
```sh
cd ios
bundle exec pod install
```
--------------------------------
### Flutter TrainingKit Integration Example
Source: https://trainingkit.fizzup.com/flutter
This snippet demonstrates the two main steps for integrating TrainingKit into a Flutter app: obtaining the device identifier for GraphQL requests and launching a workout using the session payload.
```dart
import 'package:trainingkit_flutter/trainingkit_flutter.dart';
// 1. Send the device id with your GraphQL requests
final headers = {'X-TrainingKit-Device': await deviceIdentifier()};
// 2. Launch the workout from the session payload (it carries trainingKitToken)
await launchWorkout(session);
```
--------------------------------
### Start Workout with Completion Listeners
Source: https://trainingkit.fizzup.com/web/reference.html
Register workout completion listeners like `onWorkoutSave`, `onWorkoutQuit`, and `onWorkoutEvent` within the `trainingkit.start()` call to handle workout lifecycle events.
```javascript
trainingkit.start({
workoutId: '4RGZ7S46',
onWorkoutSave: function (workoutData) {
// Persist the completed workout result.
},
onWorkoutQuit: function () {
// The user exited before completing the workout.
},
onWorkoutEvent: function (action, payload) {
// Forward TrainingKit analytics metadata if needed.
},
})
```
--------------------------------
### Add TrainingKit SDK Script
Source: https://trainingkit.fizzup.com/web/installation.html
Include this script tag in your HTML page before initializing or starting the TrainingKit SDK. Ensure it's placed before any calls to `trainingkit.init()` or `trainingkit.start()`.
```html
```
--------------------------------
### Build the App
Source: https://trainingkit.fizzup.com/react-native/installation.html
After installing native dependencies, rebuild your application using 'yarn ios' for iOS or 'yarn android' for Android. Metro reload is insufficient after adding native packages.
```sh
yarn ios
yarn android
```
--------------------------------
### Check Ruby and CocoaPods Versions
Source: https://trainingkit.fizzup.com/react-native/troubleshooting.html
Verify your active Ruby and Bundler versions if `pod install` hangs or fails. This helps diagnose version conflicts.
```sh
ruby --version
which ruby
bundle --version
which bundle
```
--------------------------------
### Initialize and Launch Workout with React Native SDK
Source: https://trainingkit.fizzup.com/react-native
Use `deviceIdentifier` to include the device ID in your GraphQL requests and `launchWorkout` to start a session from the backend response. Ensure your GraphQL client is set up and authenticated.
```typescript
import { deviceIdentifier, launchWorkout } from 'trainingkit-reactnative'
// 1. Send the device id with your GraphQL requests
const headers = { 'X-TrainingKit-Device': deviceIdentifier() }
// 2. Launch the workout from the session payload (it carries trainingKitToken)
launchWorkout(session)
```
--------------------------------
### Android Setup: Configure Gradle Repositories
Source: https://trainingkit.fizzup.com/react-native/installation.html
Add the FizzUp Maven repository to your project's Gradle configuration in 'android/build.gradle'. This allows Gradle to find the Android SDK artifacts. Ensure you provide GitHub credentials either via properties or environment variables.
```groovy
buildscript {
repositories {
google()
mavenCentral()
maven {
url "https://maven.pkg.github.com/getfizzup/trainingkit-android-sdk"
credentials {
username = properties.getProperty("GithubUser") ?: System.getenv("GITHUB_USERNAME")
password = properties.getProperty("GithubToken") ?: System.getenv("GITHUB_TOKEN")
}
}
}
}
allprojects {
repositories {
google()
mavenCentral()
maven {
url "https://maven.pkg.github.com/getfizzup/trainingkit-android-sdk"
credentials {
username = properties.getProperty("GithubUser") ?: System.getenv("GITHUB_USERNAME")
password = properties.getProperty("GithubToken") ?: System.getenv("GITHUB_TOKEN")
}
}
}
}
```
--------------------------------
### React Component for TrainingKit Player
Source: https://trainingkit.fizzup.com/web/usage.html
This React component loads the SDK script, initializes TrainingKit, and starts a workout on button click. It uses `accessTokenProvider` for external token retrieval, keeping authentication logic in the application layer.
```typescript
import { useEffect, useState } from 'react'
declare global {
interface Window {
trainingkit: {
init: (baseUrl: string) => void
start: (options: {
workoutId: string
soundpack?: string
getAccessToken?: () => Promise
onWorkoutQuit?: () => void
onWorkoutSave?: (workoutData: unknown) => void
onWorkoutEvent?: (action: string, payload: unknown) => void
}) => void
close: () => void
}
}
}
type TrainingKitPlayerProps = {
baseUrl: string
workoutId: string
soundpack?: 'none' | 'zen' | 'original' | 'new' | 'whistle'
accessTokenProvider?: () => Promise
onWorkoutQuit?: () => void
onWorkoutSave?: (workoutData: unknown) => void
onWorkoutEvent?: (action: string, payload: unknown) => void
}
const SDK_URL = 'https://cdn.fizzup.com/js/trainingkit-sdk/1.0.0/sdk.js'
export function TrainingKitPlayer({
baseUrl,
workoutId,
soundpack = 'original',
accessTokenProvider,
onWorkoutQuit,
onWorkoutSave,
onWorkoutEvent,
}: TrainingKitPlayerProps) {
const [isReady, setIsReady] = useState(false)
useEffect(() => {
const existingScript = document.querySelector(`script[src="${SDK_URL}"]`)
const initialize = () => {
window.trainingkit.init(baseUrl)
setIsReady(true)
}
if (existingScript) {
if (window.trainingkit) {
initialize()
} else {
existingScript.addEventListener('load', initialize, { once: true })
}
return
}
const script = document.createElement('script')
script.src = SDK_URL
script.async = true
script.onload = initialize
document.body.appendChild(script)
return () => {
script.onload = null
}
}, [baseUrl])
const startWorkout = () => {
window.trainingkit.start({
workoutId,
soundpack,
getAccessToken: accessTokenProvider,
onWorkoutQuit,
onWorkoutSave,
onWorkoutEvent,
})
}
return (
)
}
```
--------------------------------
### React Workout Preview Item Component
Source: https://trainingkit.fizzup.com/web/usage.html
A React component that displays a workout preview and integrates with the TrainingKit SDK to start a workout session. It handles SDK initialization, fetching session content, and launching the workout with user-specific access tokens and callbacks.
```typescript
import { useLazyQuery } from '@apollo/client/react'
import { useEffect, useState } from 'react'
import {
GET_SESSION_CONTENT,
type GetSessionContentData,
type GetSessionContentVariables,
type WorkoutPreview,
} from './queries'
import { WORKOUTKIT_BASE_URL } from './TrainingKitGraphQLProvider'
declare global {
interface Window {
trainingkit: {
init: (baseUrl: string) => void
start: (options: {
workoutId: string
soundpack?: string
getAccessToken?: () => Promise
onWorkoutQuit?: () => void
onWorkoutSave?: (workoutData: unknown) => void
onWorkoutEvent?: (action: string, payload: unknown) => void
}) => void
}
}
}
type WorkoutPreviewItemProps = {
workout: WorkoutPreview
}
const SDK_URL = 'https://cdn.fizzup.com/js/trainingkit-sdk/1.0.0/sdk.js'
async function accessTokenProvider() {
// Replace with your own end-user token retrieval when your integration needs it.
return 'yourEndUserAccessToken'
}
function formatDuration(seconds: number) {
const minutes = Math.round(seconds / 60)
return `${minutes} min`
}
export function WorkoutPreviewItem({ workout }: WorkoutPreviewItemProps) {
const [isReady, setIsReady] = useState(false)
const [hasClickedStart, setHasClickedStart] = useState(false)
const [loadWorkoutSession, { loading: isLoadingSession }] = useLazyQuery<
GetSessionContentData,
GetSessionContentVariables
>(GET_SESSION_CONTENT, {
fetchPolicy: 'network-only',
})
useEffect(() => {
const existingScript = document.querySelector(`script[src="${SDK_URL}"]`)
const initialize = () => {
window.trainingkit.init(WORKOUTKIT_BASE_URL)
setIsReady(true)
}
if (existingScript) {
if (window.trainingkit) {
initialize()
} else {
existingScript.addEventListener('load', initialize, { once: true })
}
return
}
const script = document.createElement('script')
script.src = SDK_URL
script.async = true
script.onload = initialize
document.body.appendChild(script)
return () => {
script.onload = null
}
}, [])
const startWorkout = async () => {
setHasClickedStart(true)
if (!window.trainingkit || !isReady) {
return
}
const response = await loadWorkoutSession({
variables: { id: workout.id },
})
if (!response.data?.publicWorkoutSession) {
throw new Error('TrainingKit session content is missing')
}
window.trainingkit.start({
workoutId: workout.id,
soundpack: 'none',
getAccessToken: accessTokenProvider,
onWorkoutQuit: () => {
console.log('Workout quit', workout.id)
},
onWorkoutSave: (workoutData) => {
console.log('Workout saved', workout.id, workoutData)
},
onWorkoutEvent: (action, payload) => {
console.log('Workout event', action, payload)
},
})
}
const isStarting = hasClickedStart && (!isReady || isLoadingSession)
return (
)
}
```
--------------------------------
### Get Device Identifier
Source: https://trainingkit.fizzup.com/react-native/reference.html
Returns the native TrainingKit device identifier as a string. This identifier is stable for a given device installation and should be used as the value of the `X-TrainingKit-Device` HTTP header.
```typescript
function deviceIdentifier(): string
```
--------------------------------
### Get Device Identifier
Source: https://trainingkit.fizzup.com/flutter/reference.html
Returns the native TrainingKit device identifier, which is stable for a given device installation. Use it as the value of the X-TrainingKit-Device HTTP header on every GraphQL request. Throws a TrainingKitException if the native module is unavailable.
```dart
Future deviceIdentifier()
```
--------------------------------
### Run the demo app on iOS
Source: https://trainingkit.fizzup.com/flutter/quickstart.html
Run the demo app on an iOS simulator. First, open a simulator, then execute the command. This requires a Mac with Xcode.
```sh
open -a Simulator
flutter run
```
--------------------------------
### Initialize TrainingKit SDK
Source: https://trainingkit.fizzup.com/web/reference.html
Call `trainingkit.init()` with your TrainingKit base URL to initialize the SDK. This must be done before calling other TrainingKit methods.
```javascript
trainingkit.init('https://cloud.YourCompany.fizzup.com')
```
--------------------------------
### trainingkit.init(baseUrl)
Source: https://trainingkit.fizzup.com/web/reference.html
Initializes the SDK with your TrainingKit base URL. This must be called before any other SDK methods.
```APIDOC
## trainingkit.init(baseUrl)
### Description
Initializes the SDK with your TrainingKit base URL.
### Parameters
#### Path Parameters
- **baseUrl** (string) - Required - The base URL for the TrainingKit service.
```
--------------------------------
### Build Workout Configuration
Source: https://trainingkit.fizzup.com/android/quickstart.html
Construct a JSON object to configure workout parameters, including audio coach availability and custom text for different workout states.
```kotlin
val workoutConfig = JSONObject().apply {
put("isHumanAudioCoachAvailable", false)
put(
"texts",
JSONObject(
mapOf(
"startWorkoutCTA" to "Let's go!",
"endedWorkoutTitle" to "Well done!",
"saveWorkoutCTA" to "Close"
)
)
)
}
```
--------------------------------
### Get one workout preview
Source: https://trainingkit.fizzup.com/api/queries.html
Retrieves a preview for a specific workout using its global ID.
```APIDOC
## Get one workout preview
### Description
Retrieves a preview for a specific workout using its global ID.
### Method
GET
### Endpoint
/graphql
### Query Parameters
- **id** (ID!) - Required - The global ID of the workout.
### Request Example
```graphql
query GetSession($id: ID!) {
publicWorkout(globalId: $id) {
...WorkoutPreviewItem
}
}
```
### Response
#### Success Response (200)
- **publicWorkout** (object) - Represents a single workout preview.
- **id** (ID) - The global ID of the workout.
- **type** (string) - The type of the workout.
- **duration** (integer) - The duration of the workout in seconds.
- **name** (string) - The name of the workout.
- **format** (string) - The format of the workout.
- **picture** (string) - URL to the workout's picture.
#### Response Example
```json
{
"data": {
"publicWorkout": {
"id": "workout-global-id-1",
"type": "STRENGTH",
"duration": 1800,
"name": "Full Body Strength",
"format": "VIDEO",
"picture": "https://example.com/image.jpg"
}
}
}
```
```
--------------------------------
### Instantiate WorkoutVideoFragment
Source: https://trainingkit.fizzup.com/android/reference/fragments.html
Use this constructor pattern for streaming video workouts with WorkoutVideoFragment. Provide workoutContent, workoutConfig, and jwtToken.
```kotlin
WorkoutVideoFragment.newInstance(workoutContent, workoutConfig, jwtToken)
```
--------------------------------
### Instantiate GoFragment
Source: https://trainingkit.fizzup.com/android/reference/fragments.html
Use this constructor pattern for classic workouts with GoFragment. Ensure workoutContent, workoutConfig, and jwtToken are provided.
```kotlin
GoFragment.newInstance(workoutContent, workoutConfig, jwtToken)
```
--------------------------------
### Get session payload for launch
Source: https://trainingkit.fizzup.com/api/queries.html
Fetches the session payload required for launching a workout, including specific details for block or video sessions.
```APIDOC
## Get session payload for launch
### Description
Fetches the session payload required for launching a workout, including specific details for block or video sessions. This query returns the session payload consumed by the SDK and may include a `TrainingKitToken`.
### Method
GET
### Endpoint
/graphql
### Query Parameters
- **globalId** (ID!) - Required - The global ID of the workout session.
- **configuration.difficulty** (string) - Optional - Configure the difficulty level (e.g., EASY).
### Request Example
```graphql
query GetSessionContent($id: ID!) {
publicWorkoutSession(globalId: $id, configuration: { difficulty: EASY }) {
... on WorkoutBlockSession {
...WorkoutBlockSessionItem
}
... on WorkoutVideoSession {
...WorkoutVideoSessionItem
}
}
}
```
### Response
#### Success Response (200)
- **publicWorkoutSession** (object) - The session payload for the workout.
- This can be a `WorkoutBlockSession` or `WorkoutVideoSession` object, containing specific fields relevant to the session type (e.g., `WorkoutBlockSessionItem`, `WorkoutVideoSessionItem`).
- May include a `TrainingKitToken` (string) valid for 1 day.
#### Response Example
```json
{
"data": {
"publicWorkoutSession": {
"__typename": "WorkoutVideoSession",
"id": "session-global-id-1",
"trainingKitToken": "your-1-day-valid-token",
"video": {
"url": "https://example.com/video.mp4"
}
}
}
}
```
```
--------------------------------
### Configure Workout Launch Options
Source: https://trainingkit.fizzup.com/ios/guides/customization.html
Use a configuration dictionary to customize CTA labels and completion text for workouts. Additional keys for voice prompts and behavior flags are available in the upstream DocC archive.
```swift
let configuration: [String: Any] = [
"startWorkoutCTA": "Start now",
"endedWorkoutTitle": "Great job!",
"saveWorkoutCTA": "Continue"
]
```
--------------------------------
### Fetch and Reinstall iOS TrainingKit Framework
Source: https://trainingkit.fizzup.com/react-native/troubleshooting.html
If `TrainingKit.xcframework` is not found, manually fetch it and reinstall pods. This ensures the necessary framework is present for the iOS build.
```sh
yarn fetch:ios-trainingkit
cd ios
pod install
```
--------------------------------
### Core Functions
Source: https://trainingkit.fizzup.com/react-native
Two primary functions are exported by the package: `deviceIdentifier` to get the device ID for GraphQL requests and `launchWorkout` to initiate a workout session.
```APIDOC
## Core Functions
### Description
Provides essential functions for integrating TrainingKit into your React Native application.
### Functions
#### `deviceIdentifier()`
- **Description**: Returns the native TrainingKit device identifier. This identifier is required as an HTTP header on GraphQL requests to authenticate the device.
- **Usage**: Call this function to retrieve the device identifier and include it in your GraphQL request headers.
```javascript
import { deviceIdentifier } from 'trainingkit-reactnative';
const headers = { 'X-TrainingKit-Device': deviceIdentifier() };
```
#### `launchWorkout(session)`
- **Description**: Launches the native workout experience. It automatically dispatches to either the classic or video native controller based on the provided session payload.
- **Parameters**:
- **session** (object) - Required - The GraphQL session payload containing workout details and the `trainingKitToken`.
- **Usage**: Call this function with the session object obtained from your backend to start a workout.
```javascript
import { launchWorkout } from 'trainingkit-reactnative';
launchWorkout(session);
```
```
--------------------------------
### Configure TrainingKit Android with JSON
Source: https://trainingkit.fizzup.com/android/reference/configuration-options.html
Use this to set up text customizations and enable/disable features like the human audio coach.
```kotlin
val workoutConfig = JSONObject().apply {
put("isHumanAudioCoachAvailable", true)
put(
"texts",
JSONObject(
mapOf(
"startWorkoutCTA" to "Let's go!",
"endedWorkoutTitle" to "Great job!",
"saveWorkoutCTA" to "Close"
)
)
)
}
```
--------------------------------
### Create Classic Workout Fragment
Source: https://trainingkit.fizzup.com/android/quickstart.html
Instantiate the `GoFragment` for classic workout sessions, passing the workout content, configuration, and JWT token.
```kotlin
val goFragment = GoFragment.newInstance(
workoutContent,
workoutConfig,
jwtToken
)
```
--------------------------------
### Get Single Workout Preview by ID
Source: https://trainingkit.fizzup.com/api/queries.html
Retrieve a preview of a single workout using its global ID. This query is suitable for displaying workout details before launch.
```graphql
query GetSession($id: ID!) {
publicWorkout(globalId: $id) {
...WorkoutPreviewItem
}
}
```
--------------------------------
### Create Video Workout Fragment
Source: https://trainingkit.fizzup.com/android/quickstart.html
Instantiate the `WorkoutVideoFragment` for video workout sessions, passing the workout content, configuration, and JWT token.
```kotlin
val videoFragment = WorkoutVideoFragment.newInstance(
workoutContent,
workoutConfig,
jwtToken
)
```
--------------------------------
### Clone the Repository
Source: https://trainingkit.fizzup.com/react-native/quickstart.html
Clone the `trainingkit-reactnative` repository to your local machine.
```shell
git clone https://github.com/getfizzup/trainingkit-reactnative
cd trainingkit-reactnative
```
--------------------------------
### deviceIdentifier()
Source: https://trainingkit.fizzup.com/react-native/reference.html
Returns the native TrainingKit device identifier as a string. This identifier is stable for a given device installation and should be used as the value of the X-TrainingKit-Device HTTP header on every GraphQL request.
```APIDOC
## deviceIdentifier()
### Description
Returns the native TrainingKit device identifier as a string. This identifier is stable for a given device installation.
Use it as the value of the `X-TrainingKit-Device` HTTP header on every GraphQL request.
### Method
`deviceIdentifier(): string`
### Parameters
None
### Response
- Returns a `string` representing the device identifier.
```
--------------------------------
### Run the demo app on Android
Source: https://trainingkit.fizzup.com/flutter/quickstart.html
Run the demo app on an Android emulator or device. Ensure you have an emulator running or a device connected.
```sh
flutter run -d android
```
--------------------------------
### Customize Session Save Behavior
Source: https://trainingkit.fizzup.com/ios/guides/classic-workouts.html
Subclasses `ClassicWorkoutController` to customize the session saving mechanism. This example uses a `Future` to simulate an asynchronous save operation, ensuring TrainingKit waits for completion.
```swift
final class SampleClassicWorkoutController: ClassicWorkoutController {
private var subscriptions = Set()
private var savePublisher: AnyPublisher?
override func saveSession(state: SaveWorkoutState) {
super.saveSession(state: state)
savePublisher = Future { promise in
// Replace with your backend persistence.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
promise(.success(()))
}
}.eraseToAnyPublisher()
}
override func displayPostWorkout() -> AnyPublisher {
guard let savePublisher else { return super.displayPostWorkout() }
return savePublisher
}
}
```
--------------------------------
### Update Local File Dependency
Source: https://trainingkit.fizzup.com/react-native/troubleshooting.html
When using a local file dependency in `package.json`, changes are not reflected until you re-run `yarn install` and rebuild the native app. This ensures the latest local changes are incorporated.
```json
"trainingkit-reactnative": "file:../relative/path/to/trainingkit-reactnative"
```
```sh
yarn install
cd ios
pod install
cd ..
yarn ios
```
--------------------------------
### Handle Workout Completion
Source: https://trainingkit.fizzup.com/android/guides/video-workouts.html
Implement the WorkoutVideoKitInterface to manage workout completion, navigation, and event tracking.
```kotlin
override fun saveWorkout(saveState: SaveWorkoutState): Promise<*, *, *> {
// The workout completed. Persist saveState before resolving if needed.
return DeferredObject()
.resolve(saveState)
}
override fun goToNextScreen() {
// Continue or dismiss your host flow after the workout screen is done.
finish()
}
override fun trackEvent(data: TrackingData) {
// Optional: forward TrainingKit analytics metadata.
}
```
--------------------------------
### Switch to Ruby 3.x with rbenv
Source: https://trainingkit.fizzup.com/react-native/troubleshooting.html
Install and configure `rbenv` to use a specific Ruby version (e.g., 3.3.6) for React Native iOS development if Ruby 4 is active. This ensures compatibility with CocoaPods.
```sh
brew install rbenv ruby-build
rbenv install 3.3.6
rbenv local 3.3.6
eval "$(rbenv init -)"
gem install bundler
bundle install
```
--------------------------------
### Fetch Schema and Generate Models
Source: https://trainingkit.fizzup.com/ios/quickstart.html
Run these commands from the repository root to fetch the GraphQL schema and generate Swift models using the Apollo CLI.
```bash
./apollo-ios-cli fetch-schema --path SampleApp/apollo-codegen-config.json
./apollo-ios-cli generate --path SampleApp/apollo-codegen-config.json
```
--------------------------------
### Configure Android credentials
Source: https://trainingkit.fizzup.com/flutter/quickstart.html
Create the local.properties file in the android directory and add your GitHub credentials.
```properties
GithubUser=your-github-username
GithubToken=your-github-token
```
--------------------------------
### Create GoFragment Instance
Source: https://trainingkit.fizzup.com/android/guides/classic-workouts.html
Instantiate the GoFragment with the necessary GraphQL payload, workout configuration, and JWT token. This fragment is used to render classic workouts.
```kotlin
val goFragment = GoFragment.newInstance(
workoutContent, // GraphQL payload
workoutConfig, // JSON configuration
jwtToken // JWT token
)
```
--------------------------------
### Instantiate Workout Fragment with SDK Token
Source: https://trainingkit.fizzup.com/android/authentication.html
Pass the TrainingKitToken and deviceId when creating workout fragments. Ensure the token is fetched shortly before launch as it's valid for one day and bound to the current app lifecycle.
```kotlin
val fragment = GoFragment.newInstance(workoutContent, config, trainingKitToken, deviceId)
// or WorkoutVideoFragment.newInstance(workoutContent, config, trainingKitToken, true)
```
--------------------------------
### deviceIdentifier()
Source: https://trainingkit.fizzup.com/flutter/reference.html
Returns the native TrainingKit device identifier. This identifier is stable for a given device installation and should be used as the value of the `X-TrainingKit-Device` HTTP header on every GraphQL request. Throws a `TrainingKitException` if the native module is unavailable.
```APIDOC
## deviceIdentifier()
### Description
Returns the native TrainingKit device identifier. This identifier is stable for a given device installation and should be used as the value of the `X-TrainingKit-Device` HTTP header on every GraphQL request.
### Throws
- `TrainingKitException`: If the native module is unavailable (e.g., if the app was not rebuilt after adding the package).
### Returns
- `Future`: The stable device identifier.
```
--------------------------------
### GraphQL Fragment for Workout Video Session
Source: https://trainingkit.fizzup.com/web/usage.html
Defines a GraphQL fragment to retrieve specific details about a workout video session, including cover image, start and end times, text color, and video URL.
```graphql
fragment WorkoutVideoSessionVideoItem on WorkoutVideoSessionVideo {
cover
end
start
textPrimaryColor
url
}
```
--------------------------------
### Example JWT Payload
Source: https://trainingkit.fizzup.com/api/authentication-server-requests.html
This JSON object demonstrates a typical payload for a JWT used in TrainingKit API authentication. It includes the 'sub' claim for user identification, 'exp' for expiration time, and 'nbf' for not-before time.
```json
{
"sub": "550e8400-e29b-41d4-a716-446655440000",
"exp": 1760000000,
"nbf": 1759996400
}
```
--------------------------------
### Instantiate Workout Controller
Source: https://trainingkit.fizzup.com/ios/quickstart.html
Instantiate either `SampleClassicWorkoutController` or `SampleStreamingWorkoutController` based on the workout session type. This code is used within the sample app to present the appropriate workout controller.
```swift
let controller: UIViewController
if response.data?.publicWorkoutSession.asWorkoutBlockSession != nil {
controller = try await SampleClassicWorkoutController(data: data, token: token)
} else {
controller = try await SampleStreamingWorkoutController(data: data, token: token)
}
controller.modalPresentationStyle = .fullScreen
present(controller, animated: true)
```
--------------------------------
### workoutEvents()
Source: https://trainingkit.fizzup.com/flutter/reference.html
Returns a broadcast stream of workout lifecycle events emitted by the native SDKs. It is recommended to start listening before calling `launchWorkout(session)` to avoid missing events. Cancel the subscription when the host screen no longer needs workout events.
```APIDOC
## workoutEvents()
### Description
Returns a broadcast stream of workout lifecycle events emitted by the native SDKs. Start listening before calling `launchWorkout(session)` so save, quit, and tracking events cannot be missed. Cancel the subscription when the host screen no longer needs workout events.
### Returns
- `Stream`: A stream of workout lifecycle events.
```
--------------------------------
### Listen to Workout Events
Source: https://trainingkit.fizzup.com/flutter/reference.html
Returns a broadcast stream of workout lifecycle events emitted by the native SDKs. Start listening before calling launchWorkout(session) so save, quit, and tracking events cannot be missed. Cancel the subscription when the host screen no longer needs workout events.
```dart
Stream workoutEvents()
```
```dart
final subscription = workoutEvents().listen((event) {
switch (event.type) {
case TrainingKitEventType.save:
// Persist completed workout state from event.data.
break;
case TrainingKitEventType.quit:
// The user exited before completing the workout.
break;
case TrainingKitEventType.event:
// Forward analytics metadata if needed.
break;
}
});
await subscription.cancel();
```
--------------------------------
### Get Session Content for Launch
Source: https://trainingkit.fizzup.com/api/queries.html
Fetch the session payload required for launching a workout. This query handles different session types (WorkoutBlockSession, WorkoutVideoSession) and is crucial for SDK integration. It's recommended to fetch this query close to workout launch and use the payload immediately.
```graphql
query GetSessionContent($id: ID!) {
publicWorkoutSession(globalId: $id, configuration: { difficulty: EASY }) {
... on WorkoutBlockSession {
...WorkoutBlockSessionItem
}
... on WorkoutVideoSession {
...WorkoutVideoSessionItem
}
}
}
```
--------------------------------
### Configure GraphQL Authentication
Source: https://trainingkit.fizzup.com/android/quickstart.html
Add your server URL and authentication key to the `local.properties` file. This file should not be committed to version control.
```properties
GraphQLServerUrl=https://server.com/graphql
GraphQLAuthKey=your_auth_key_here
```
--------------------------------
### Create WorkoutVideoFragment
Source: https://trainingkit.fizzup.com/android/guides/video-workouts.html
Instantiate the WorkoutVideoFragment with the necessary GraphQL payload, JSON configuration, and JWT token.
```kotlin
val videoFragment = WorkoutVideoFragment.newInstance(
workoutContent, // GraphQL payload
workoutConfig, // JSON configuration
jwtToken // JWT token
)
```
--------------------------------
### Run the Demo App
Source: https://trainingkit.fizzup.com/react-native/quickstart.html
Run the demo app on either iOS or Android using Yarn commands. The app connects to the FizzUp demo GraphQL endpoint.
```shell
yarn ios
# or
yarn android
```
--------------------------------
### Coordinate Persistence and Post-Workout Completion
Source: https://trainingkit.fizzup.com/ios/guides/workout-data.html
Return your async save publisher to ensure the SDK waits for your data pipeline before finishing the workout. This is crucial for coordinating persistence and post-workout completion.
```swift
override func displayPostWorkout() -> AnyPublisher {
guard let savePublisher else { return super.displayPostWorkout() }
return savePublisher
}
```
--------------------------------
### Reinstall Native Dependencies and Rebuild
Source: https://trainingkit.fizzup.com/react-native/troubleshooting.html
Use this command sequence when a native module is not found after adding a new native package. A simple Metro reload is insufficient.
```sh
yarn install
cd ios
pod install
cd ..
yarn ios
```
--------------------------------
### TrainingKitInterface
Source: https://trainingkit.fizzup.com/ios/reference/delegates.html
`TrainingKitInterface` is the core host lifecycle protocol implemented by TrainingKit controllers. It defines methods for saving workout states, displaying post-workout flows, and handling workout quitting.
```APIDOC
## `TrainingKitInterface`
`TrainingKitInterface` is the core host lifecycle protocol implemented by TrainingKit controllers.
### Methods
- `saveSession(state: SaveWorkoutState)`: Persist session results in host backend/app logic. Call `super` in controller overrides.
- `displayPostWorkout() -> AnyPublisher`: Return publisher that completes when post-workout flow is done.
- `quitWorkout()`: Handle quit-without-save flow. Call `super` and ensure handling of non-UI-thread invocations.
*Note: `ClassicWorkoutController` and `StreamingWorkoutController` both provide default implementations for this protocol.*
```
--------------------------------
### Download GraphQL Schema via Gradle
Source: https://trainingkit.fizzup.com/android/quickstart.html
Use the Gradle command to download the GraphQL schema if the Apollo GraphQL plugin flow fails.
```bash
./gradlew downloadServiceApolloSchemaFromIntrospection
```
--------------------------------
### Create and Present Classic Workout Controller
Source: https://trainingkit.fizzup.com/ios/guides/classic-workouts.html
Instantiates and presents the `ClassicWorkoutController` once the session payload is validated. The controller is presented in full-screen mode.
```swift
if response.data?.publicWorkoutSession.asWorkoutBlockSession != nil {
let controller = try await SampleClassicWorkoutController(data: data, token: token)
controller.modalPresentationStyle = .fullScreen
present(controller, animated: true)
}
```
--------------------------------
### Add GitHub Credentials to local.properties
Source: https://trainingkit.fizzup.com/android/installation.html
Configure your GitHub username and token in the local.properties file. Ensure these credentials are not committed to version control.
```properties
GithubUser=$YOUR_GITHUB_USERNAME
GithubToken=$YOUR_GITHUB_TOKEN
```
--------------------------------
### Launch Workout with SDK Authentication
Source: https://trainingkit.fizzup.com/react-native/authentication.html
Pass the full session object to `launchWorkout`. The function reads the `trainingKitToken` from the session and forwards it to the native SDK. This is required for SDK Authentication and the function throws if the token is missing.
```typescript
import { launchWorkout } from 'trainingkit-reactnative'
launchWorkout(session) // throws if trainingKitToken is missing
```