Реализация вибрационной обратной связи (Haptic Feedback) для мобильного приложения
Кнопка нажалась, но пользователь не почувствовал этого — и нажал ещё раз. Двойная отправка формы, двойной заказ, двойной платёж. Haptic feedback — не украшение интерфейса, а механизм подтверждения действия на физическом уровне.
Чем iOS и Android отличаются в haptics
На iOS всё строится вокруг UIFeedbackGenerator и его трёх подклассов: UIImpactFeedbackGenerator для тактильных ударов разной интенсивности (.light, .medium, .heavy, .rigid, .soft), UISelectionFeedbackGenerator для прокрутки picker'ов и UINotificationFeedbackGenerator для системных событий (.success, .warning, .error). Генераторы требуют явного вызова prepare() перед использованием — без него вибрация задержится на 150–200 мс, потому что Taptic Engine нужно время на инициализацию. Пропустить prepare() — самая частая ошибка.
С iOS 17 появился UICanvasFeedbackGenerator для рисования и CHHapticEngine из Core Haptics для полностью кастомных паттернов: можно задать кривую интенсивности и частоты во времени через CHHapticEvent и CHHapticParameterCurve. Это позволяет сделать, например, нарастающую вибрацию при долгом нажатии или пульсирующий паттерн для уведомлений.
На Android до API 31 был только Vibrator с примитивными паттернами через VibrationEffect.createWaveform(). Начиная с Android 12 (API 31) появился VibrationEffect.Composition с предопределёнными примитивами: PRIMITIVE_CLICK, PRIMITIVE_TICK, PRIMITIVE_THUD, PRIMITIVE_SPIN и другими. Проблема — фрагментация: поддержка конкретных примитивов зависит от производителя и модели устройства. Метод Vibrator.areAllPrimitivesSupported() обязателен перед использованием. На устройствах без поддержки нужен graceful fallback на VibrationEffect.createOneShot().
В Flutter — HapticFeedback из flutter/services.dart с методами lightImpact(), mediumImpact(), heavyImpact(), selectionClick(). Для более тонкого контроля на iOS можно через MethodChannel вызвать CHHapticEngine напрямую. На Android Flutter использует Vibrator под капотом, что ограничивает возможности на старых API.
В React Native — react-native-haptic-feedback или встроенный Vibration API. Первая библиотека даёт доступ к нативным типам на обеих платформах, но требует проверки платформы и версии API в рантайме.
Типичные ошибки реализации
Haptic без проверки поддержки. UIFeedbackGenerator молча игнорирует вызовы на симуляторе, но на устройстве без Taptic Engine (iPad mini 4, старые iPod touch) prepare() и impactOccurred() тоже не вызывают краша — просто ничего не происходит. Это ожидаемое поведение Apple. На Android — иначе: Vibrator.hasVibrator() и hasAmplitudeControl() нужно проверять явно.
Злоупотребление haptics в анимациях. Вибрация при каждом кадре scroll-анимации убивает батарею и раздражает пользователя. UISelectionFeedbackGenerator.selectionChanged() должен вызываться только при изменении выбранного элемента, не при каждом offset-изменении.
Игнорирование системной настройки. iOS с iOS 13 транслирует изменение «Системная тактильность» через CHHapticEngine, но UIFeedbackGenerator автоматически уважает эту настройку. Кастомные паттерны через CHHapticEngine требуют проверки CHHapticEngine.capabilitiesForHardware().supportsHaptics и настройки engine.playsHapticsOnly.
Что входит в работу
Анализируем интерактивные элементы приложения: кнопки, свайпы, слайдеры, picker'ы, pull-to-refresh, drag-and-drop, уведомления об ошибках. Для каждого типа подбираем интенсивность и паттерн, соответствующий системным гайдлайнам Apple HIG и Material Design 3. Реализуем нативные вызовы под каждую платформу с fallback-логикой. Тестируем на реальных устройствах — симулятор iOS не воспроизводит тактильный отклик корректно.
Если нужны кастомные паттерны (игровые эффекты, специфичные UI-события), проектируем CHHapticPattern с кривыми интенсивности и доставляем через CHHapticPatternPlayer.
Срок: от 1 дня для базовой интеграции стандартных генераторов. Кастомные Core Haptics паттерны и кросс-платформенная библиотека — 2–3 дня.







