Core Haptics engine setup
Boilerplate for custom haptic patterns: capability check, engine creation, and auto-restart handlers.
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)")
}
}
}