Я устал принимать платежи через WebView. Что мне делать?

Habrahabr 1

Я езжу в офис на электричке — нужно проехать одну станцию, и я буду почти на месте.

Каждое утро покупаю билеты на поезд в приложении и страдаю. Там дешевле, но разница в цене не окупает мою боль, когда я прохожу эти три минуты стресса. Даже не упоминая время загрузки каждого из пяти экранов приложения, нельзя не сказать про банковские WebView с сохранённой картой, ввод кода из смс на бегу и неожиданные сбои в работе.

Это когда ты бежишь на поезд, а тебе говорят «Что-то пошло не так» и списывают деньги, а билет не дают. Возврат приходит тут же, но поезд-то уже ушел. Такое происходит пару раз в месяц, вне зависимости от качества интернета. Ни о каких -пэях и говорить не приходится.

В этот момент задумываешься — а может, есть способ проще? Ну, чтобы вообще без вебвью, красиво и нативно. И да, такой способ есть. Подробности под катом. tl;dr Мы сделали интерфейс для приёма платежей через Apple Pay, Google Pay, мобильный банк Сбербанка и Яндекс.Деньги в iOS и Android. Нет, не придётся рисовать платёжные формы. Да, это еще и в open source.

Вообще, сценариев приёма платежей в мобильных приложениях примерно два.

Первый — через WebView с платёжной страницей. Так можно принимать платежи через кошелек, банковскую карту, мобильный или что угодно ещё. Проблема в том, что у WebView нет доступа к браузерным кукам, а значит, и авторизации для некоторых способов оплаты, поэтому заплатить не получится.

Во втором сценарии мерчант пропускает карточные данные через свой бэкенд — для этого нужно соответствовать PCI DSS, что дорого, долго и сложно.

Мобильный SDK

Мобильный SDK Яндекс.Кассы — это библиотека под iOS и Android, которую мы сделали, чтобы упростить жизнь мерчантам, разработчикам приложений и тем, кто заботится о своих пользователях. Фактически мобильный SDK — это инструмент для токенизации банковских карт и других платёжных инструментов. Токенизация — это обмен данных, которые нужны для проведения платежа, на уникальный идентификатор — токен.

Весной мы выкатили первую версию SDK — там была оплата картой и из кошелька в Яндекс.Деньгах. Сейчас всё стало ещё лучше — в июльском релизе добавили Google Pay, Apple Pay и платежи через Сбербанк с подтверждением по смс.

О пользе

Главная польза — покупатель платит чем угодно, но для мерчанта это выглядит как один токен, которым можно оперировать вместо платёжных данных.

Ещё не придётся проходить сертификацию на соответствие PCI DSS — карточные данные будут обрабатываться в нашем периметре. Мы каждый год проходим сертификацию, соблюдаем все правила регуляторов и избавляем от этого магазины, которые подключились к Кассе. Так можно.

С SDK платежи в Android и iOS выглядят привычно для пользователей, и им теперь не нужно покидать контекст приложения во время оплаты. Тем, кто платит из электронного кошелька, еще и не нужно авторизовываться — если пользователь залогинен в приложении Денег, понадобится только выбрать нужную учётку через Яндекс.Паспорт.

Как начать использовать у себя?

Если совсем обобщить, то нужно сделать две вещи:
  • Интегрировать платёжный API Яндекс.Кассы — для приёма платежей;
  • Подключить мобильный SDK — для токенизации и нативного интерфейса.
Чтобы добавить Apple Pay, достаточно подключить приём платежей по банковским картам и выпустить ключи в аккаунте разработчика Apple.

С Google Pay немного по-другому. Нужно:

  1. Подготовить тестовую сборку APK.
  2. Заполнить интеграционный чек-лист — подтвердить, что ваше приложение не собирается захватывать мир, и ещё несколько вещей.
  3. Залить сборку на проверку в Google Pay.
Google всё проверит и разрешит (или не разрешит) выкладывать приложение в Google Play.

Мобильный SDK встраивается в клиентское приложение, чтобы через него работали нативные платежи. Работает так: реквизиты карты уходят сразу в наш периметр PCI DSS, не попадая на бэкенд магазина. Мы всё проверяем, обрабатываем и возвращаем мерчанту платёжный токен со временем жизни в 30 минут — его можно использовать один раз.

Схема взаимодействия пользователя, мерчанта, мобильного SDK и API Я.Кассы<br/ >

С участием SDK платёж состоит из трех этапов:

  1. Инициация оплаты и получение токена. Приложение инициирует платёж через SDK, а на выходе получает платёжный токен.
  2. Создание платежа. Токен уходит на сервер, который инициирует оплату через API.
  3. Запрос статуса платежа. Это нужно для того, чтобы отрисовать правильное окно с успехом или ошибками.

Почему так — хорошо?

  1. Архитектура однородна в разных платёжных сценариях.
  2. Не нужно работать с банковской картой на бэкенде магазина.

Про разработку и тестирование

В iOS-версии мы используем VIPER и микросервисы.

В основе мобильного SDK лежит модуль токенизации — он управляет процессом так, чтобы мерчант на выходе видел только токен для API Яндекс.Кассы вне зависимости от того, чем платил пользователь. Еще модуль токенизации решает, какое окно сейчас показывать пользователю, и делает POST-запросы на сервер. Мы написали свою обёртку для API для работы с HTTP/HTTPS-запросами к YandexMoneyCoreApi — это сделало жизнь проще.

Сервисы — это хранилища и объекты, которые работают с клиентским API Яндекс.Кассы. Их код получился чистым и лаконичным, без большого количества ветвлений и ранних выходов, потому что отделу разработки удалось продумать всю архитектуру заранее. В сервисах SDK концентрированное количество функционального программирования — здесь мы раскрыли его возможности полностью. Там, где приходилось работать с Functor, Monad, Applicative Functor, нам помогли обычные Promise.

let method = PaymentOptions.Method(oauthToken: clientApplicationKey,
                                           passportAuthorization: passportToken,
                                           gatewayId: gatewayId,
                                           amount: amount,
                                           currency: currency)

        let paymentOptions = session.perform(apiMethod: method).responseApi()

        let allItems = getItems <^> paymentOptions
        let items = paymentMethodHandler.filterPaymentMethods <^> allItems
        let itemsWithEmptyError = items
            .recover(on: .global(), mapError)
            .then(makeErrors)
        return itemsWithEmptyError
Единственная сложность возникла с VIPER — мы начали добавлять новые виды оплаты и поняли, что центральный модуль сильно разрастается. Когда в нём оказалось около 1000 строк, мы решили, что надо что-то с этим делать и пересматривать архитектуру.

Идея с центральным модулем на процесс нам нравилась, и её мы решили оставить. В других проектах мы используем детерминированный конечный автомат для описания процесса, но здесь это не решило бы проблем, так как реализация многих вещей осталась бы в том же модуле. Так что мы решили применить паттерн «стратегия» для изоляции процессов каждого платёжного средства. После того, как пользователь выбрал способ платежа, мы создаём стратегию для способа оплаты, которая управляет картой переходов и решает, какой процесс за каким идет.

Демонстрационное приложение

Мы его сделали.

Всё началось с того, что отделу тестирования понадобилось что-то, на чём можно было тестировать мобильный SDK. Без тестового приложения ребята не могли проверить, как работает SDK, а разработчиков под обе платформы среди тестировщиков не нашлось.

В процессе выяснилось, что, кроме задач тестирования, демо-приложение — хороший способ показать нашим партнёрам, что такое мобильный SDK. Любой человек, который не умеет программировать на Swift или Kotlin (читай: любой человек), может посмотреть, как работает SDK. Поэтому мы залили демо-приложение в Google Play и iOS-версию на сайт Яндекс.Кассы.

Получилась штука, в которой можно посмотреть, как работают разные способы оплаты, поиграть с настройками или показать её тому, кто у вас отвечает за выбор платёжного агрегатора. Не стесняйтесь.

Открытый исходный код

Несколько месяцев после запуска мы распространяли библиотеку очень неудобно — делились ссылкой на сайт или отправляли файлы по почте. Хорошие ребята так не делают — они выкладывают всё на GitHub под лицензией MIT. Вот мы ровно так и сделали.

Кроме магии токенизации мерчанты могут настраивать цвета, менять логотипы или вносить любые другие изменения в библиотеку. А чтобы было совсем удобно, мы опубликовали мобильный SDK в CocoaPods для iOS-разработчиков и в Maven для Android-ребят.

Если вы уже принимаете платежи через Кассу, но теперь хотите делать это ещё лучше и продуктивнее — подключайте мобильный SDK. Если только открываете магазин — подключайте Кассу. У нас всё хорошо.

Полезные ссылки

Библиотека для мобильных приложенийДокументация по SDKSDK для iOS и Android на GitHub. → Maven

На этом всё. Задавайте вопросы в комментариях!