Skip to content

Commit b7d70a6

Browse files
Merge pull request #6 from SimformSolutionsPvtLtd/fix/UNT-T39093_ios_haptics_release_build_timing
fix(UNT-T39093): Resolve Core Haptics timing validation error in iOS Release builds
2 parents 23b2d0c + ab3e954 commit b7d70a6

File tree

1 file changed

+35
-4
lines changed

1 file changed

+35
-4
lines changed

ios/HapticEngine.swift

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)