iOS
Native iOS SDK that integrates the Zing Fitness experience into your app. The SDK ships as an SPM package via GitHub.
Requirements
| Requirement | Value / Notes |
|---|---|
| Minimum iOS version | 16 |
| Xcode iOS SDK | 16+ |
| Swift Package Manager | 5.10 |
1. Setup
Add the dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/Muze-Fitness/zing-coach-sdk-ios.git", from: "1.1.1")
]Then add ZingCoachSDK to your target’s dependencies:
.target(
name: "YourTarget",
dependencies: ["ZingCoachSDK"]
)2. Initialization
The SDK instance owns internal state and resources. Releasing it deallocates internal state and interrupts background sync.
let result = await ZingSDK.initialize(
with: .init(
authentication: .externalToken(provider: self),
errorHandler: self
)
)
switch result {
case .success(let sdk):
zingSDK = sdk // Retain at app-level scope
case .failure(let error):
print("Initialization failed: \(error)")
}3. Authentication
External Token Authentication
Use this mode when your backend manages user authentication and issues JWT tokens.
Token Requirements:
- Valid JWT format
- Must contain
subclaim with the partner user ID - Recommended token lifetime: 15 minutes
let result = await ZingSDK.initialize(
with: .init(
authentication: .externalToken(provider: self),
errorHandler: self
)
)
switch result {
case .success(let sdk):
self.sdk = sdk
_ = await sdk.login()
case .failure(let error):
print("Initialization failed: \(error)")
}
// Example implementation of the AuthProvider protocol
extension YourAuthProvider: ZingSDK.AuthProvider {
func didRequestAuthToken() async -> Result<String, Error> {
// Fetch JWT token from your authentication server
// The token must contain a "sub" claim with the user ID
let token = try await yourAuthService.getToken()
return .success(token)
}
}
// Example implementation of the ErrorHandler protocol
extension YourErrorHandler: ZingSDK.ErrorHandler {
func didReceiveError(_ error: ZingSDK.Error) {
print("SDK error: \(error)")
}
}Error types:
extension ZingSDK {
enum Error: Swift.Error {
case authError(AuthError)
case loginError(LoginError)
}
enum AuthError: Swift.Error {
/// The partner user ID in the new token does not match the previously authenticated user.
case partnerIDMismatch
/// The token is invalid: either malformed JWT structure or missing required "sub" claim.
case badToken
/// The external authentication provider returned an error.
case externalError(Swift.Error)
}
enum LoginError: Swift.Error {
/// Login was attempted while a user is already authenticated.
case alreadyLoggedIn
/// Login was attempted while another login operation is in progress.
case loginAlreadyInProgress
/// Token retrieval failed during the login process.
/// The underlying cause may be a badToken, partnerIDMismatch, or externalError.
case failedToGetToken
/// Profile synchronization failed after successful token retrieval.
/// This typically indicates a network error when fetching user profile data.
case failedToGetProfile
}
enum LogoutError: Swift.Error {
/// Logout was attempted when no user is currently logged in.
case notLoggedIn
}
}API Key Authentication
Use this mode for testing or when backend integration is not available:
let result = await ZingSDK.initialize(
with: .init(
authentication: .apiKey(key: "your-api-key"),
errorHandler: errorHandler
)
)Login
After successful SDK initialization, call login() 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 on the first session, when loginState is .loggedOut. On subsequent sessions, init() automatically restores the previous session — you do not need to call login() again.
The SDK will request a token from your AuthProvider and establish the user session. Login errors are delivered through your ErrorHandler and returned from login().
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.isLoggedInLogout
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)
}This clears the user session and stops background sync. You can call login() again to start a new session.
4. Present SDK Modules
All SDK modules return UIViewController. Present them modally or embed in your navigation:
// Custom Workout Builder
let customWorkoutVC = sdk.makeCustomWorkoutModule()
present(customWorkoutVC, animated: true)
// Training Program
let programVC = sdk.makeProgramModule()
present(programVC, animated: true)
// Workout Preview/Player
// Use a ZingSDK.Workout instance obtained from CustomWorkoutDelegate
let previewVC = sdk.makeWorkoutPreview(for: workout)
present(previewVC, animated: true)
// AI Assistant Chat
let assistantVC = sdk.makeAssistantChat()
present(assistantVC, animated: true)
// Profile Settings (edit user profile settings)
let settingsVC = sdk.makeProfileSettings()
present(settingsVC, animated: true)
// Full Schedule
let scheduleVC = sdk.makeFullSchedule()
present(scheduleVC, animated: true)5. Handle Custom Workout Creation (Optional)
class WorkoutDelegate: ZingSDK.CustomWorkoutDelegate {
func didCreateWorkout(_ workout: ZingSDK.Workout) {
print("User created workout: \(workout.id)")
}
}
let delegate = WorkoutDelegate()
let customWorkoutVC = sdk.makeCustomWorkoutModule(delegate)