Skip to Content

iOS

Native iOS SDK that integrates the Zing Fitness experience into your app. The SDK ships as an SPM package via GitHub.

Requirements

RequirementValue / Notes
Minimum iOS version16
Xcode iOS SDK16+
Swift Package Manager5.10

Setup

Add the dependency to your Package.swift:

dependencies: [ .package(url: "https://github.com/Muze-Fitness/zing-coach-sdk-ios.git", from: "1.4.2") ]

Then add ZingCoachSDK to your target’s dependencies:

.target( name: "YourTarget", dependencies: ["ZingCoachSDK"] )

Initialization

The SDK instance owns internal state and resources. Retain it at app-level scope for the application’s lifetime; releasing it deallocates internal state and interrupts background sync.

InitializationParameters

ParameterTypeDefaultNotes
authenticationAuthenticationTyperequired
themeTheme?nilSDK visual configuration
configurationConfigurationConfiguration()Coach availability, gender availability, HealthKit background delivery

Theming

Pass a Theme value to InitializationParameters to override the SDK’s built-in visual defaults.

let theme = Theme( colors: TokenProvider { token in switch token { case .brand(.primary): UIColor(red: 0x00/255, green: 0x40/255, blue: 0x70/255, alpha: 1) case .brand(.secondary): UIColor(red: 0x00/255, green: 0x4F/255, blue: 0x91/255, alpha: 1) default: nil // keep SDK default for all other color tokens } }, assets: TokenProvider { token in switch token { case .planBackground: UIImage(named: "MyPlanBackground") default: nil } } )

Theme accepts five optional providers:

PropertyToken typePlatform type
colorsColorTokenUIColor
spacingsSizeTokenCGFloat
cornersRoundingRadiusTokenRadiusAttribute
typographyTypographyTokenTypographyAttributes
assetsAssetTokenUIImage

Returning nil from a resolution closure keeps the SDK’s built-in default for that token. You do not need to handle every case — only override the tokens your brand requires.

Configuration

Coach availability

CaseBehaviour
.allCoachesAll coaches are available to every user (default)
.userGenderBasedCoaches are filtered based on the user’s gender

Gender availability

CaseBehaviour
.allAll gender options are available (default)
.binaryOnly male and female options are presented

HealthKit background delivery

Set ahBackgroundDeliveryEnabled to true to enable HealthKit background delivery so the SDK can sync Apple Health data while your app is suspended. Your app must include the HealthKit entitlement and request the appropriate read authorizations.

Handling InitializationResult

let result = await ZingSDK.initialize(with: ZingSDK.InitializationParameters( authentication: .externalToken(provider: self, errorHandler: self), theme: theme, configuration: ZingSDK.Configuration( coachesAvailability: .allCoaches, genderAvailability: .all, ahBackgroundDeliveryEnabled: false ) )) switch result { case .success(let sdk): self.sdk = sdk case .failure(let error): print("Initialization failed: \(error)") }

Authentication

External token authentication

Use external token authentication when your backend manages user accounts and issues JWT tokens.

Token requirements:

  • Valid JWT format
  • Must contain sub claim with the partner user ID
  • Recommended token lifetime: 15 minutes

Conform to ZingSDK.AuthProvider to supply tokens:

extension YourAuthProvider: ZingSDK.AuthProvider { func didRequestAuthToken() async -> Result<String, Error> { let token = try await yourAuthService.getToken() return .success(token) } }

Conform to ZingSDK.ErrorHandler to receive authentication errors:

extension YourErrorHandler: ZingSDK.ErrorHandler { func didReceiveError(_ error: AuthError) { switch error { case .partnerIDMismatch: break case .badToken: break case .externalError(let underlyingError): break } } }

API Key Authentication

Use this mode for testing or when backend integration is not available:

let result = await ZingSDK.initialize( with: ZingSDK.InitializationParameters( authentication: .apiKey(key: "your-api-key") ) )

Login

Call login() after initialization to authenticate the user and start a session:

let result = await sdk.login() switch result { case .success: // User logged in successfully case .failure(let error): // Handle LoginError }

Call login() only when loginState is .loggedOut — typically only on the first session. On subsequent launches, ZingSDK.initialize(with:) automatically restores the previous session and loginState will already be .loggedIn. Calling login() while already logged in returns .failure(.alreadyLoggedIn).

Logout

Call logout() when your user signs out of your app:

let result = await sdk.logout() switch result { case .success: // User logged out successfully case .failure(let error): // Handle LogoutError (e.g. .notLoggedIn) }

Logout clears the user’s token and removes all locally cached data. You can call login() again to start a new session.

Login state

// Current state let state: ZingSDK.LoginState = sdk.loginState // .loggedOut | .inProgress | .loggedIn(userID: String) // Reactive updates sdk.loginStatePublisher .sink { state in /* handle state changes */ } .store(in: &cancellables) // Quick check let isLoggedIn: Bool = sdk.isLoggedIn

Errors

enum LoginError: Error { /// Login was attempted while a user is already logged in. case alreadyLoggedIn /// Login was attempted while another login operation is in progress. case loginAlreadyInProgress /// Token retrieval failed during the login process. case failedToGetToken /// Profile synchronisation failed after successful token retrieval. case failedToGetProfile } enum LogoutError: Error { /// Logout was attempted when no user is currently logged in. case notLoggedIn } enum AuthError: Error { /// The partner user ID in the new token does not match the previously authenticated user. case partnerIDMismatch /// The token is invalid: malformed JWT or missing required sub claim. case badToken /// The external authentication provider returned an error. case externalError(Error) }

User profile

You can supply user profile data to personalise the SDK experience. Pass profile parameters before or after login.

ProfileParameters

All fields are optional. Omit any field to leave the existing value unchanged.

FieldTypeNotes
nameString?Display name
genderUserGender?.male, .female, .other, .preferNotToSay
heightDouble?In centimeters (cm). Values outside the valid range are ignored.
weightDouble?In kilograms (kg). Values outside the valid range are ignored.
ageInt?Age in full years
measurementSystemUnit?.metric or .imperial

Setting the profile

let params = ProfileParameters( name: "Username", gender: .female, height: 178, weight: 75, age: 30, measurementSystem: .metric ) sdk.setProfileParams(params)

SDK modules

Every SDK module returns a UIViewController.

If the user has not completed onboarding, the SDK automatically shows the onboarding flow before the requested module.

Workout program program

Present the user’s personalised workout program:

let programVC = sdk.makeProgramModule() present(programVC, animated: true)

AI assistant chat

Open the AI fitness assistant:

let assistantVC = sdk.makeAssistantChat() present(assistantVC, animated: true)

Profile settings

Allow users to edit their profile and settings:

let settingsVC = sdk.makeProfileSettings() present(settingsVC, animated: true)

Full schedule

Display the user’s full workout schedule:

let scheduleVC = sdk.makeFullSchedule() present(scheduleVC, animated: true)

Workout preview

Display a preview of a specific workout. Obtain a Workout value from CustomWorkoutDelegate.didCreateWorkout(_:):

let previewVC = sdk.makeWorkoutPreview(for: workout) present(previewVC, animated: true)

Custom workout builder

Let users build a custom workout. Provide an optional delegate to receive the created workout:

class WorkoutDelegate: CustomWorkoutDelegate { func didCreateWorkout(_ workout: Workout) { // workout.id is a stable string identifier for the created workout } } let delegate = WorkoutDelegate() let customWorkoutVC = sdk.makeCustomWorkoutModule(delegate) present(customWorkoutVC, animated: true)
Last updated on