@@ -21,12 +21,21 @@ protocol HapticAnimationState {
2121 var hapticCurves : [ CHHapticParameterCurve ] { get }
2222}
2323
24+ /// Stores the configuration for a continuous player so it can be recreated after engine reinitialization
25+ struct ContinuousPlayerConfig {
26+ let playerId : String
27+ let initialIntensity : Float
28+ let initialSharpness : Float
29+ }
30+
2431class HapticFeedback {
2532 static let shared = HapticFeedback ( )
2633
2734 private var engine : CHHapticEngine ?
2835 private var hapticPlayers : [ String : CHHapticAdvancedPatternPlayer ] = [ : ]
2936 private var continuousPlayers : [ String : CHHapticAdvancedPatternPlayer ] = [ : ]
37+ /// Stores configurations for continuous players so they can be recreated after engine reinitialization
38+ private var continuousPlayerConfigs : [ String : ContinuousPlayerConfig ] = [ : ]
3039 private let lock = NSLock ( )
3140
3241 public var supportsHaptics : Bool {
@@ -40,7 +49,6 @@ class HapticFeedback {
4049 }
4150
4251 lock. lock ( )
43- defer { lock. unlock ( ) }
4452
4553 // Clean up existing engine first
4654 if engine != nil {
@@ -53,6 +61,7 @@ class HapticFeedback {
5361 engine = try CHHapticEngine ( )
5462 } catch let error {
5563 print ( " Engine Creation Error: \( error) " )
64+ lock. unlock ( )
5665 return
5766 }
5867
@@ -98,6 +107,19 @@ class HapticFeedback {
98107 } catch {
99108 print ( " Failed to start the engine: \( error) " )
100109 }
110+
111+ // Copy configs while holding the lock, then release before recreating players
112+ let configsCopy = Array ( continuousPlayerConfigs. values)
113+ lock. unlock ( )
114+
115+ // Recreate any continuous players that were registered before engine was destroyed
116+ for config in configsCopy {
117+ createContinuousPlayerInternal (
118+ playerId: config. playerId,
119+ initialIntensity: config. initialIntensity,
120+ initialSharpness: config. initialSharpness
121+ )
122+ }
101123 }
102124
103125 public func createHapticPlayers< State: HapticAnimationState > ( for states: [ State ] ) {
@@ -194,7 +216,28 @@ class HapticFeedback {
194216 /// Creates a continuous haptic player with the given ID.
195217 /// - If a player with this ID already exists, it will be stopped and replaced.
196218 /// - If the engine is not initialized or device doesn't support haptics, this is a no-op.
219+ /// - The player configuration is stored so it can be recreated after engine reinitialization.
197220 public func createContinuousPlayer( playerId: String , initialIntensity: Float , initialSharpness: Float ) {
221+ // Store the configuration so we can recreate the player after engine reinitialization
222+ let config = ContinuousPlayerConfig (
223+ playerId: playerId,
224+ initialIntensity: initialIntensity,
225+ initialSharpness: initialSharpness
226+ )
227+
228+ lock. lock ( )
229+ continuousPlayerConfigs [ playerId] = config
230+ lock. unlock ( )
231+
232+ createContinuousPlayerInternal (
233+ playerId: playerId,
234+ initialIntensity: initialIntensity,
235+ initialSharpness: initialSharpness
236+ )
237+ }
238+
239+ /// Internal method to create a continuous player without storing config (used during recreation)
240+ private func createContinuousPlayerInternal( playerId: String , initialIntensity: Float , initialSharpness: Float ) {
198241 lock. lock ( )
199242 defer { lock. unlock ( ) }
200243
@@ -311,10 +354,14 @@ class HapticFeedback {
311354 /// Destroys the continuous haptic player and releases resources.
312355 /// - If the player doesn't exist (not created or already destroyed), this is a safe no-op.
313356 /// - The player will be stopped if it's currently playing.
357+ /// - The player configuration is also removed, so it won't be recreated after engine reinitialization.
314358 public func destroyContinuousPlayer( playerId: String ) {
315359 lock. lock ( )
316360 defer { lock. unlock ( ) }
317361
362+ // Remove the stored config so this player won't be recreated after engine reinitialization
363+ continuousPlayerConfigs. removeValue ( forKey: playerId)
364+
318365 guard let player = continuousPlayers [ playerId] else {
319366 // Player doesn't exist - safe no-op
320367 // This can happen if destroy is called before create, or called multiple times
0 commit comments