Skip to content

fix(ios): prevent thread overload by reusing CHHapticEngine#24

Open
GorkaMinus wants to merge 1 commit intoionic-team:mainfrom
GorkaMinus:fix/reuse-ios-haptics-engine
Open

fix(ios): prevent thread overload by reusing CHHapticEngine#24
GorkaMinus wants to merge 1 commit intoionic-team:mainfrom
GorkaMinus:fix/reuse-ios-haptics-engine

Conversation

@GorkaMinus
Copy link
Copy Markdown

Description

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:

  • Reuse a single CHHapticEngine instance across multiple vibration calls
  • Shut down the engine after duration + 5s of inactivity, so the idle countdown starts after the vibration finishes
  • Handle engine lifecycle with resetHandler (restarts engine after server recovery) and stoppedHandler (clears the reference on external stops like audio interruptions or app suspension)

Change Type

  • Fix

Rationale / Problems Fixed

Continuation of ionic-team/capacitor-plugins#2340, moved here per maintainer guidance since the haptics plugin now lives in its own repository.

Related: #7

Creating a new CHHapticEngine per vibrate() call spawns threads that accumulate faster than the system can reclaim them. Under rapid-fire usage (pickers, scroll-driven haptics), this leads to thread exhaustion, UI freezes, and eventual crashes.

Tests or Reproductions

  • Rapidly call Haptics.vibrate() from a picker/scroll, confirm no freeze or crash
  • Call vibrate(duration) with a long duration (e.g. 5s), confirm vibration completes fully before engine shuts down
  • Trigger an audio session interruption (e.g. phone call) mid-session, confirm haptics recover on next use
  • Verify fallback to AudioServicesPlayAlertSound on devices without haptic support

Platforms Affected

  • iOS

Notes / Comments

This also addresses review feedback from the original PR (ionic-team/capacitor-plugins#2340):

  • Removed redundant supportsHaptics check inside initializeEngine() since it's already guarded in the caller
  • Idle timer now accounts for vibration duration (duration + 5s) instead of a flat 5s countdown
  • Added resetHandler and stoppedHandler for proper engine lifecycle management following Apple's recommended patterns

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.

1 participant