// // HapticEnginePlayer.swift // Keging // // Core Haptics 정밀 패턴 재생 — 아이폰 전용·포그라운드 전용 (watchOS SDK엔 CoreHaptics 없음). // 시스템 바이브로는 불가능한 짧은 간격의 연타와 1초 이상의 연속 진동을 만든다. // 엔진이 백그라운드 등에서 죽어 있으면 1회 재생성 후 재시도, 그래도 실패면 false // (호출 측이 시스템 진동으로 폴백). // #if canImport(CoreHaptics) import CoreHaptics @MainActor final class HapticEnginePlayer { static let shared = HapticEnginePlayer() private var engine: CHHapticEngine? private init() {} @discardableResult func play(_ pattern: HapticPattern) -> Bool { guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return false } if attempt(pattern) { return true } engine = nil return attempt(pattern) } private func attempt(_ pattern: HapticPattern) -> Bool { do { let engine = try currentEngine() let events = pattern.hapticEvents.map { spec in CHHapticEvent( eventType: .hapticContinuous, parameters: [ CHHapticEventParameter(parameterID: .hapticIntensity, value: spec.intensity), CHHapticEventParameter(parameterID: .hapticSharpness, value: spec.sharpness), ], relativeTime: spec.time, duration: spec.duration ) } let player = try engine.makePlayer(with: try CHHapticPattern(events: events, parameters: [])) try engine.start() try player.start(atTime: CHHapticTimeImmediate) return true } catch { return false } } private func currentEngine() throws -> CHHapticEngine { if let engine { return engine } let newEngine = try CHHapticEngine() newEngine.isAutoShutdownEnabled = true engine = newEngine return newEngine } } #endif