Library / Foundations

Core Haptics engine setup

Boilerplate for custom haptic patterns: capability check, engine creation, and auto-restart handlers.

0ms 100ms 200ms 300ms 400ms
Feel
N/A — infrastructure required by every custom pattern in this library.
APIs
CHHapticEngineCHHapticEventCHHapticPattern
Minimum OS
iOS 13+
Raw .md
Core Haptics
import CoreHaptics

/// Owns a CHHapticEngine and keeps it alive across app lifecycle events.
final class HapticEngine {
    static let shared = HapticEngine()
    private var engine: CHHapticEngine?

    /// True on iPhone 8 and later. Always gate custom patterns on this.
    var supportsHaptics: Bool {
        CHHapticEngine.capabilitiesForHardware().supportsHaptics
    }

    private init() {
        guard supportsHaptics else { return }
        do {
            engine = try CHHapticEngine()
            // Restart automatically if the system stops the engine
            // (audio session interruption, backgrounding, etc.)
            engine?.resetHandler = { [weak self] in
                try? self?.engine?.start()
            }
            engine?.stoppedHandler = { reason in
                print("Haptic engine stopped: \(reason)")
            }
            try engine?.start()
        } catch {
            print("Haptic engine failed to start: \(error)")
        }
    }

    /// Plays an array of events as a one-shot pattern.
    func play(_ events: [CHHapticEvent]) {
        guard supportsHaptics, let engine else { return }
        do {
            let pattern = try CHHapticPattern(events: events, parameters: [])
            let player = try engine.makePlayer(with: pattern)
            try engine.start() // no-op if already running
            try player.start(atTime: CHHapticTimeImmediate)
        } catch {
            print("Failed to play pattern: \(error)")
        }
    }
}
Copied