Разработка экрана оформления заказа (Checkout) в мобильном приложении
Checkout — экран, на котором пользователи уходят чаще всего. Длинная форма с полями адреса, выбором доставки и вводом карты на мобильном экране превращается в испытание, если её не проектировать специально под touch interaction. Технически это самый сложный экран в e-commerce приложении: платёжная интеграция, валидация в реальном времени, работа с клавиатурой, управление несколькими scroll-зонами.
Платёжные интеграции
Это самая трудоёмкая часть. Каждый провайдер — отдельный SDK со своими требованиями.
Stripe — stripe-react-native или нативный Stripe iOS/Android SDK. CardField компонент берёт на себя ввод карты с автоформатированием и валидацией. PaymentSheet — готовый bottom sheet от Stripe, минимум кастомизации но максимум надёжности. Для кастомного UI — useStripe().confirmPayment() с PaymentIntent client secret с бэкенда.
Apple Pay / Google Pay. На iOS — PKPaymentAuthorizationViewController, в React Native через @stripe/stripe-react-native с useApplePay(). На Android — PaymentsClient из Google Pay API + IsReadyToPayRequest. Обе кнопки показываем только если платёжный метод доступен на устройстве — stripe.isApplePaySupported() / paymentsClient.isReadyToPay().
Важно: PCI DSS запрещает передавать raw данные карты через собственный бэкенд. Только tokenization на стороне SDK провайдера. За это Apple App Review отклоняет приложения с self-hosted card forms.
Управление формой
Форма checkout обычно содержит 10–15 полей. Без правильной навигации между полями (returnKeyType="next" + ref.focus() на следующем инпуте) это невыносимо. В React Native Hook Form — Controller + useRef массив для полей + автоматический setFocus при ошибке после submit.
Клавиатура — главная боль. KeyboardAwareScrollView из react-native-keyboard-aware-scroll-view работает лучше стандартного KeyboardAvoidingView: автоматически скроллит к активному полю и корректно обрабатывает изменение высоты при смене ориентации.
На iOS числовые поля (индекс, CVV) должны открывать UIKeyboardType.numberPad. decimalPad — для суммы. emailAddress — для email. Неправильный keyboardType — мелочь, которую замечают все пользователи и не говорят о ней вслух.
Валидация и UX
Валидация в реальном времени — только для полей с детерминированным форматом: телефон, email, индекс, номер карты. Для текстовых полей (имя, адрес) — только после потери фокуса (onBlur), иначе ошибка «неправильное имя» появляется на третьей букве.
Автозаполнение адреса через Google Places Autocomplete API или Dadata API (для РФ) — обязательный элемент. Ручной ввод улицы, дома, квартиры отдельными полями увеличивает время заполнения в 3–4 раза и ошибки доставки.
Из практики: приложение доставки, React Native + Stripe. При оплате Apple Pay на физическом iPhone XR приложение падало с NSException сразу после авторизации. Причина — PKPaymentAuthorizationController вызывался из background thread. Перенос в DispatchQueue.main в нативном модуле решил проблему. React Native bridge не гарантирует main thread для callback'ов.
Многошаговый checkout
Для длинного checkout используем stepper (шаги: адрес → доставка → оплата → подтверждение). Каждый шаг — отдельный компонент с собственной валидацией. Состояние храним в одном store, не передаём через пропсы между экранами. ProgressBar сверху показывает текущий шаг.
Кнопка «Назад» должна сохранять уже введённые данные — не сбрасывать форму при возврате к предыдущему шагу.
Что входит в работу
- Форма с полями адреса (с автодополнением через Places API)
- Выбор способа доставки с расчётом стоимости и сроков
- Список сохранённых адресов пользователя
- Интеграция платёжного провайдера (Stripe, CloudPayments, ЮKassa и другие)
- Apple Pay / Google Pay с проверкой доступности
- Валидация в реальном времени + обработка ошибок API
- Экран подтверждения заказа с номером и деталями
- Хранение последнего использованного адреса и карты
Сроки
3–5 рабочих дней — зависит от количества платёжных провайдеров, сложности логики скидок и требований к валидации адреса. Интеграция одного провайдера с Apple Pay/Google Pay — 2–3 дня. Стоимость рассчитывается индивидуально.







