@@ -40,6 +40,12 @@ class HapticEngine: NSObject {
4040 @objc ( start: reject: )
4141 func start( resolve: @escaping RCTPromiseResolveBlock ,
4242 reject: @escaping RCTPromiseRejectBlock ) {
43+ // Check if device supports haptics first
44+ guard CHHapticEngine . capabilitiesForHardware ( ) . supportsHaptics else {
45+ reject ( " HAPTICS_NOT_SUPPORTED " , " Device does not support haptics " , nil )
46+ return
47+ }
48+
4349 var engine : CHHapticEngine
4450
4551 if let existingEngine = HapticEngine . shared. engines [ Key . defaultEngine] {
@@ -49,6 +55,16 @@ class HapticEngine: NSObject {
4955 else {
5056 do {
5157 let newEngine = try CHHapticEngine ( )
58+
59+ // Add reset and stopped handlers for better error handling
60+ newEngine. resetHandler = {
61+ print ( " Haptic engine reset " )
62+ }
63+
64+ newEngine. stoppedHandler = { reason in
65+ print ( " Haptic engine stopped: \( reason. rawValue) " )
66+ }
67+
5268 HapticEngine . shared. engines [ Key . defaultEngine] = newEngine
5369 engine = newEngine
5470 } catch let e {
@@ -117,14 +133,14 @@ class HapticEngine: NSObject {
117133 */
118134 @objc ( startPlayerAtTime: startTime: resolve: reject: )
119135 func startPlayerAtTime( pattern: HapticPattern ,
120- startTime: CGFloat ,
136+ startTime: NSNumber ,
121137 resolve: RCTPromiseResolveBlock ,
122138 reject: RCTPromiseRejectBlock ) {
123139 var engine : CHHapticEngine
124140
125141 if let hapticPatternPlayer {
126142 do {
127- try hapticPatternPlayer. stop ( atTime: . zero )
143+ try hapticPatternPlayer. stop ( atTime: CHHapticTimeImmediate )
128144 } catch let e {
129145 reject ( " Unable to stop the active player before starting the new haptic pattern " , e. localizedDescription, e)
130146 return
@@ -174,7 +190,11 @@ class HapticEngine: NSObject {
174190 }
175191
176192 do {
177- try hapticPatternPlayer? . start ( atTime: TimeInterval ( startTime) )
193+ // Use CHHapticTimeImmediate for immediate playback when startTime is 0 or negative
194+ // This fixes the timing validation error in Release builds
195+ let startTimeValue = startTime. doubleValue
196+ let playbackTime = startTimeValue <= 0 ? CHHapticTimeImmediate : TimeInterval ( startTimeValue)
197+ try hapticPatternPlayer? . start ( atTime: playbackTime)
178198
179199 resolve ( true )
180200 } catch let e {
@@ -189,8 +209,19 @@ class HapticEngine: NSObject {
189209 @objc ( stop: reject: )
190210 func stop( resolve: @escaping RCTPromiseResolveBlock ,
191211 reject: @escaping RCTPromiseRejectBlock ) {
212+ // First, stop any active player immediately
213+ if let activePlayer = hapticPatternPlayer {
214+ do {
215+ try activePlayer. stop ( atTime: CHHapticTimeImmediate)
216+ } catch {
217+ print ( " Warning: Could not stop active haptic player: \( error. localizedDescription) " )
218+ }
219+ hapticPatternPlayer = nil
220+ }
221+
192222 guard let existingEngine = HapticEngine . shared. engines [ Key . defaultEngine] else {
193- reject ( " Unable to find engine " , " Engine has not been created " , nil )
223+ // If no engine exists, consider it already stopped
224+ resolve ( true )
194225 return
195226 }
196227
0 commit comments