### 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 Intégration FizzUp TrainingKit

Chargement de votre entrainement

``` -------------------------------- ### 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 ```