Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 51 additions & 9 deletions haptics/ios/Sources/HapticsPlugin/Haptics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,45 @@ import CoreHaptics

var selectionFeedbackGenerator: UISelectionFeedbackGenerator?

// Haptic Engine Management
private var hapticEngine: CHHapticEngine?
private var idleTimer: Timer?
private let idleInterval: TimeInterval = 5.0 // Engine will shut down after 5 seconds of inactivity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This limits the duration to 5 seconds as it doesn't really tracks inactivity (when it stops) but from when it was last started.

Maybe you can add a duration param in resetIdleTimer to pass the vibration duration and add the 5 seconds after it stoped instead?


/**
* Initializes the haptic engine and starts it.
*/
private func initializeEngine() {
if CHHapticEngine.capabilitiesForHardware().supportsHaptics {
Copy link
Member

@jcesarmobile jcesarmobile Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initializeEngine is only called inside a supportsHaptics check inside vibrate, so no need to double check here, the supportsHaptics if can be removed.

do {
hapticEngine = try CHHapticEngine()
try hapticEngine?.start()
} catch {
print("Error initializing haptic engine: \(error)")
hapticEngine = nil
}
}
}

/**
* Reset the idle timer each time a haptic event is fired.
*/
private func resetIdleTimer() {
idleTimer?.invalidate()
idleTimer = Timer.scheduledTimer(withTimeInterval: idleInterval, repeats: false) { [weak self] _ in
self?.shutdownEngine()
}
}

/**
* Shuts down the haptic engine if it is not in use.
*/
private func shutdownEngine() {
hapticEngine?.stop(completionHandler: nil)
hapticEngine = nil
}


@objc public func impact(_ impactStyle: UIImpactFeedbackGenerator.FeedbackStyle) {
let generator = UIImpactFeedbackGenerator(style: impactStyle)
generator.impactOccurred()
Expand Down Expand Up @@ -38,16 +77,19 @@ import CoreHaptics

@objc public func vibrate(_ duration: Double) {
if CHHapticEngine.capabilitiesForHardware().supportsHaptics {
// Reuse the existing engine or initialize a new one if needed.
if hapticEngine == nil {
initializeEngine()
}
// Reset the idle timer so the engine remains alive.
resetIdleTimer()

guard let engine = hapticEngine else {
vibrate() // fallback if the engine couldn’t be created
return
}

do {
let engine = try CHHapticEngine()
try engine.start()
engine.resetHandler = { [] in
do {
try engine.start()
} catch {
self.vibrate()
}
}
let intensity = CHHapticEventParameter(parameterID: .hapticIntensity, value: 1.0)
let sharpness = CHHapticEventParameter(parameterID: .hapticSharpness, value: 1.0)

Expand Down
Loading