--- name: sleeptrack-ios description: This skill helps iOS developers integrate the Asleep SDK for sleep tracking functionality. Use this skill when building native iOS apps with Swift/SwiftUI that need sleep tracking capabilities, implementing delegate patterns, configuring iOS permissions (microphone, notifications, background modes), managing tracking lifecycle, integrating Siri Shortcuts, or working with Combine framework for reactive state management. --- # Sleeptrack iOS ## Overview This skill provides comprehensive guidance for integrating the Asleep SDK into native iOS applications using Swift and SwiftUI. It covers SDK setup, iOS-specific permissions, delegate-based architecture, tracking lifecycle management, Combine framework integration, and Siri Shortcuts support. Use this skill when: - Building native iOS sleep tracking applications - Implementing SwiftUI-based tracking interfaces - Managing iOS permissions and background modes - Working with delegate patterns for SDK callbacks - Integrating Siri Shortcuts for voice-activated tracking - Using Combine framework for reactive state management **Prerequisites**: Developers should first review the `sleeptrack-foundation` skill to understand core Asleep concepts, authentication, data structures, and error handling before implementing iOS-specific integration. ## Quick Start ### 1. Installation Add AsleepSDK to your Xcode project using Swift Package Manager: ```swift // In Xcode: File → Add Packages // Enter package URL: https://github.com/asleep-ai/asleep-sdk-ios ``` Or add to `Package.swift`: ```swift dependencies: [ .package(url: "https://github.com/asleep-ai/asleep-sdk-ios", from: "2.0.0") ] ``` ### 2. Configure iOS Permissions Add required permissions to `Info.plist`: ```xml NSMicrophoneUsageDescription This app uses your microphone to track sleep stages and detect snoring during sleep. UIBackgroundModes audio NSUserNotificationsUsageDescription Get reminders to start and stop sleep tracking. ``` ### 3. Basic Setup ```swift import SwiftUI import AsleepSDK @main struct SleepTrackerApp: App { var body: some Scene { WindowGroup { MainView() } } } ``` ## SDK Architecture The Asleep iOS SDK follows a delegate-based architecture with three main components: ### 1. AsleepConfig - Configuration and User Management **Purpose**: Initialize SDK with API credentials and manage user lifecycle. **Key Delegate**: `AsleepConfigDelegate` ```swift protocol AsleepConfigDelegate { func userDidJoin(userId: String, config: Asleep.Config) func didFailUserJoin(error: Asleep.AsleepError) func userDidDelete(userId: String) } ``` ### 2. SleepTrackingManager - Tracking Lifecycle **Purpose**: Control sleep tracking start, stop, and monitor session state. **Key Delegate**: `AsleepSleepTrackingManagerDelegate` ```swift protocol AsleepSleepTrackingManagerDelegate { func didCreate() // Session created func didUpload(sequence: Int) // Data uploaded func didClose(sessionId: String) // Tracking stopped func didFail(error: Asleep.AsleepError) // Error occurred func didInterrupt() // Interrupted (e.g., phone call) func didResume() // Resumed after interruption func micPermissionWasDenied() // Mic permission denied func analysing(session: Asleep.Model.Session) // Real-time data (optional) } ``` ### 3. Reports - Retrieving Sleep Data **Purpose**: Fetch sleep reports and session lists after tracking completes. ```swift // Reports API is async/await based, not delegate-driven let reports = Asleep.createReports(config: config) // Get single report let report = try await reports.report(sessionId: "session_id") // Get report list let reportList = try await reports.reports( fromDate: "2024-01-01", toDate: "2024-01-31" ) ``` ## Implementation Overview ### Minimal ViewModel Example ```swift import Foundation import Combine import AsleepSDK final class SleepTrackingViewModel: ObservableObject { private(set) var trackingManager: Asleep.SleepTrackingManager? private(set) var reports: Asleep.Reports? @Published var isTracking = false @Published var error: String? @Published private(set) var config: Asleep.Config? func initAsleepConfig(apiKey: String, userId: String) { Asleep.initAsleepConfig( apiKey: apiKey, userId: userId, delegate: self ) } func startTracking() { trackingManager?.startTracking() } func stopTracking() { trackingManager?.stopTracking() } } // Implement delegates extension SleepTrackingViewModel: AsleepConfigDelegate { func userDidJoin(userId: String, config: Asleep.Config) { Task { @MainActor in self.config = config self.trackingManager = Asleep.createSleepTrackingManager( config: config, delegate: self ) } } func didFailUserJoin(error: Asleep.AsleepError) { Task { @MainActor in self.error = error.localizedDescription } } func userDidDelete(userId: String) { // Handle user deletion } } extension SleepTrackingViewModel: AsleepSleepTrackingManagerDelegate { func didCreate() { Task { @MainActor in self.isTracking = true } } func didClose(sessionId: String) { Task { @MainActor in self.isTracking = false // Initialize reports to fetch session data self.reports = Asleep.createReports(config: config!) } } func didFail(error: Asleep.AsleepError) { Task { @MainActor in self.error = error.localizedDescription } } // Implement other delegate methods as needed } ``` For complete ViewModel implementation with all delegate methods, see [references/complete_viewmodel_implementation.md](references/complete_viewmodel_implementation.md) ## iOS-Specific Features ### 1. Siri Shortcuts Enable voice-activated tracking with App Intents (iOS 16+). Users can say "Hey Siri, start sleep" or "Hey Siri, stop sleep". For complete Siri Shortcuts implementation, see [references/ios_specific_features.md](references/ios_specific_features.md#siri-shortcuts-integration) ### 2. Background Audio Mode Configure background audio to maintain tracking during sleep. Simply add `audio` to `UIBackgroundModes` in Info.plist - iOS handles the rest automatically. For details, see [references/ios_specific_features.md](references/ios_specific_features.md#background-audio-mode) ### 3. Microphone Permission Request microphone permission before starting tracking: ```swift import AVFoundation func requestMicrophonePermission() async -> Bool { switch AVAudioSession.sharedInstance().recordPermission { case .granted: return true case .denied: return false case .undetermined: return await AVAudioSession.sharedInstance().requestRecordPermission() @unknown default: return false } } ``` For complete permission handling, see [references/ios_specific_features.md](references/ios_specific_features.md#microphone-permission-handling) ### 4. App Lifecycle Management Handle app state transitions using SwiftUI's `scenePhase`: ```swift struct SleepTrackingView: View { @Environment(\.scenePhase) private var scenePhase var body: some View { // ... view content ... .onChange(of: scenePhase) { newPhase in switch newPhase { case .active: print("App is active") case .inactive: print("App is inactive") case .background: print("App in background - tracking continues") @unknown default: break } } } } ``` For advanced lifecycle patterns, see [references/ios_specific_features.md](references/ios_specific_features.md#app-lifecycle-management) ### 5. Persistent Storage Store configuration using AppStorage: ```swift struct SleepTrackingView: View { @AppStorage("sleepapp+apikey") private var apiKey = "" @AppStorage("sleepapp+userid") private var userId = "" // Values automatically persist across app launches } ``` ## Error Handling ### Common Error Patterns ```swift func handleError(_ error: Asleep.AsleepError) { switch error { case .micPermission: // Guide user to Settings showMicPermissionAlert() case .audioSessionError: // Another app is using microphone showAudioUnavailableAlert() case let .httpStatus(code, _, message): switch code { case 403: // Session already active on another device case 404: // Session not found default: break } default: showGenericError(error.localizedDescription) } } ``` ### Retry with Exponential Backoff ```swift func startTrackingWithRetry() { trackingManager?.startTracking() } func didFail(error: Asleep.AsleepError) { if isTransientError(error) && retryCount < maxRetries { retryCount += 1 DispatchQueue.main.asyncAfter(deadline: .now() + pow(2.0, Double(retryCount))) { self.startTrackingWithRetry() } } else { handleError(error) } } ``` For comprehensive error handling patterns, see [references/advanced_patterns.md](references/advanced_patterns.md#error-recovery-patterns) ## Best Practices ### 1. State Management Use `@Published` properties for reactive UI updates: ```swift final class SleepTrackingViewModel: ObservableObject { @Published var isTracking = false @Published var error: String? // UI automatically updates when values change } ``` ### 2. Main Thread Safety Always update UI on main thread: ```swift func didCreate() { Task { @MainActor in // Ensures main thread self.isTracking = true } } ``` ### 3. Resource Cleanup ```swift final class SleepTrackingViewModel: ObservableObject { deinit { trackingManager = nil reports = nil } } ``` ### 4. User Experience Provide clear visual feedback with loading states, progress indicators, and error messages. Disable controls appropriately during tracking. ### 5. Testing Considerations Use dependency injection for testable code: ```swift protocol SleepTrackingManagerProtocol { func startTracking() func stopTracking() } // Production and mock implementations ``` For complete testing patterns, see [references/advanced_patterns.md](references/advanced_patterns.md#testing-patterns) ## Common Integration Patterns ### Pattern 1: Simple Single-View App Best for basic sleep tracking with minimal features. Single view with tracking controls. ### Pattern 2: Multi-View App with Navigation Best for apps with reports, settings, and history. Uses TabView for navigation between Track, History, and Settings. ### Pattern 3: Centralized SDK Manager Best for complex apps sharing SDK instance across views. Single source of truth with `AsleepSDKManager.shared`. For complete implementation of all patterns, see [references/advanced_patterns.md](references/advanced_patterns.md) ## Real-time Data Access Access preliminary sleep data during tracking (available after sequence 10): ```swift func analysing(session: Asleep.Model.Session) { Task { @MainActor in if let sleepStages = session.sleepStages { updateRealtimeChart(stages: sleepStages) } } } func didUpload(sequence: Int) { // Real-time data available every 10 sequences after sequence 10 if sequence >= 10 && sequence % 10 == 0 { // SDK automatically calls analysing() delegate } } ``` ## Fetching Reports Retrieve sleep session data after tracking: ```swift func fetchReport(sessionId: String) async { do { let report = try await reports?.report(sessionId: sessionId) // Process report data } catch { // Handle error } } // Fetch multiple sessions func fetchReportList() async { let reportList = try await reports?.reports( fromDate: "2024-01-01", toDate: "2024-01-31" ) } ``` ## Troubleshooting ### Tracking Doesn't Start **Causes**: Missing microphone permission, empty API key/user ID, another app using microphone **Solution**: Validate configuration and check microphone permission before starting ### Background Tracking Stops **Causes**: Background audio mode not configured, memory pressure, force-closed app **Solution**: Ensure `UIBackgroundModes` includes `audio` in Info.plist ### Reports Not Available **Causes**: Session processing incomplete (takes time), minimum duration not met (5 minutes), network issues **Solution**: Implement retry logic with exponential backoff when fetching reports For detailed troubleshooting, see the complete implementation examples in references/ ## Sample Code Reference This skill is based on the official Asleep iOS sample app: - **MainViewModel.swift**: Complete ViewModel with all delegates - **MainView.swift**: SwiftUI view with tracking controls - **StartSleepIntent.swift / StopSleepIntent.swift**: Siri Shortcuts - **ReportView.swift**: Sleep report display - **Info.plist**: Required iOS permissions Sample app: [Asleep iOS Sample App](https://github.com/asleep-ai/asleep-sdk-ios-sampleapp-public) ## Resources ### Official Documentation - **iOS Get Started**: https://docs-en.asleep.ai/docs/ios-get-started.md - **iOS Error Codes**: https://docs-en.asleep.ai/docs/ios-error-codes.md - **AsleepConfig Reference**: https://docs-en.asleep.ai/docs/ios-asleep-config.md - **SleepTrackingManager Reference**: https://docs-en.asleep.ai/docs/ios-sleep-tracking-manager.md - **Sample App Guide**: https://docs-en.asleep.ai/docs/sample-app.md ### Apple Documentation - **SwiftUI**: https://developer.apple.com/documentation/swiftui - **Combine**: https://developer.apple.com/documentation/combine - **AVAudioSession**: https://developer.apple.com/documentation/avfaudio/avaudiosession - **App Intents**: https://developer.apple.com/documentation/appintents - **Background Modes**: https://developer.apple.com/documentation/xcode/configuring-background-execution-modes ### Related Skills - **sleeptrack-foundation**: Core Asleep concepts, authentication, and data structures - **sleeptrack-android**: Android-specific implementation guide - **sleeptrack-be**: Backend API integration ## Next Steps After integrating the iOS SDK: 1. Test thoroughly across different iOS devices and versions 2. Implement proper error handling for all edge cases 3. Add user-friendly error messages and recovery flows 4. Consider HealthKit integration for data export 5. Implement notification reminders for tracking 6. Add data visualization for sleep trends 7. Consider Apple Watch companion app 8. Submit to App Store with proper privacy declarations