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:
// In Xcode: File → Add Packages
// Enter package URL: https://github.com/asleep-ai/asleep-sdk-ios
Or add to Package.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 version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Microphone access for audio-based sleep tracking -->
<key>NSMicrophoneUsageDescription</key>
<string>This app uses your microphone to track sleep stages and detect snoring during sleep.</string>
<!-- Background audio mode for continuous tracking -->
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<!-- Optional: For notification reminders -->
<key>NSUserNotificationsUsageDescription</key>
<string>Get reminders to start and stop sleep tracking.</string>
</dict>
</plist>
3. Basic Setup
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
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
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.
// 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
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
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
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
3. Microphone Permission
Request microphone permission before starting tracking:
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
4. App Lifecycle Management
Handle app state transitions using SwiftUI's scenePhase:
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
5. Persistent Storage
Store configuration using AppStorage:
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
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
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
Best Practices
1. State Management
Use @Published properties for reactive UI updates:
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:
func didCreate() {
Task { @MainActor in // Ensures main thread
self.isTracking = true
}
}
3. Resource Cleanup
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:
protocol SleepTrackingManagerProtocol {
func startTracking()
func stopTracking()
}
// Production and mock implementations
For complete testing patterns, see references/advanced_patterns.md
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
Real-time Data Access
Access preliminary sleep data during tracking (available after sequence 10):
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:
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
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:
- Test thoroughly across different iOS devices and versions
- Implement proper error handling for all edge cases
- Add user-friendly error messages and recovery flows
- Consider HealthKit integration for data export
- Implement notification reminders for tracking
- Add data visualization for sleep trends
- Consider Apple Watch companion app
- Submit to App Store with proper privacy declarations
Scan to join WeChat group