Skip to content

fix(@capacitor/haptics): prevent thread overload by reusing CHHapticEngine#2340

Open
GorkaMinus wants to merge 2 commits intoionic-team:7.xfrom
GorkaMinus:main
Open

fix(@capacitor/haptics): prevent thread overload by reusing CHHapticEngine#2340
GorkaMinus wants to merge 2 commits intoionic-team:7.xfrom
GorkaMinus:main

Conversation

@GorkaMinus
Copy link

Fix: Prevent iOS app freeze by reusing CHHapticEngine instance

This PR addresses an issue where calling Haptics.vibrate() rapidly (e.g., from a fast-scrolling picker in my case) causes the app to hang or crash on iOS. The problem stems from creating a new CHHapticEngine instance on each call, which leads to excessive thread creation and eventual system overload.

Solution

  • Reuses a single CHHapticEngine instance across multiple vibration calls.
  • Ensures the engine is only created and started when necessary.
  • Handles engine lifecycle and failure states gracefully.

This fix improves performance and stability, especially in high-frequency vibration scenarios.

Related Issue #1960

@OS-pedrogustavobilro OS-pedrogustavobilro changed the base branch from main to 7.x March 4, 2026 17:01
@OS-pedrogustavobilro
Copy link
Contributor

Hey @GorkaMinus, sorry for the delay, I changed the branch to 7.x, as since 8.x, the capacitor haptics plugin now lives in its own repository - https://github.com/ionic-team/capacitor-haptics.

If you can, open an equivalent PR to that repository in order to be able to merge it into the latest version.

If you have any questions feel free to ask, thank you!

// 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants