Интеграция SDK
1. Отобразить экран оформления заказа
Помимо информации о заказе, этот экран должен предоставить пользователю возможность выбрать карту для оплаты.
- iOS
- Android
- Flutter
2. Вызвать метод своего бэкенда
Перед показом экрана оформления заказа вызовите метод своего бэкенда, созданный по инструкции в Подготовка бэкенда. Затем сохраните customer_access_token
и order_access_token
в переменных.
- iOS
- Android
- Flutter
// В контроллере экрана оформления заказа
override func viewDidLoad() {
// ...
api.startPayment(for: order) { result in
switch result {
case .success(let response):
self.orderAccessToken = response.orderAccessToken
self.customerAccessToken = response.customerAccessToken
// ...
}
}
Пример получения токенов с использованием Kotlin Coroutines:
fun getTokens() {
...
scope.launch(Dispatchers.IO) {
val order = myRepository.checkout()
this.customerAccessToken = order.customerAccessToken
this.orderAccessToken = order.orderAccessToken
}
...
}
RaisedButton(
onPressed: () async {
final tokens = await MyBackend.createOrder();
// Здесь [tokens] это объект с токенами, но это может быть и, например, Map
final customerAccessToken = tokens.customerAccessToken;
final orderAccessToken = tokens.orderAccessToken;
// Заранее создаём заказ и передаём токены в экран оформления
await showCheckoutView(
context: context,
customerAccessToken: customerAccessToken,
orderAccessToken: orderAccessToken,
);
},
child: Text('Оформить заказ')
),
3. Получить сохраненные карты пользователя
Вызовите метод получения сохраненных карт пользователя, чтобы отобразить их и сохранить для дальнейшей работы.
- iOS
- Android
- Flutter
Вызовите метод Ioka.shared.getSavedCards()
, передав в него customer_access_token
:
override func viewDidLoad() {
// ...
api.startPayment(for: order) { result in
switch result {
case .success(let response):
self.orderAccessToken = response.orderAccessToken
self.customerAccessToken = response.customerAccessToken
Ioka.shared.getSavedCards(customerAccessToken: customerAccessToken) { result in
switch result {
case .success(let savedCards):
self.savedCards = savedCards
self.updateInterface()
// ...
}
// ...
}
}
Вызовите suspend метод Ioka.getCards()
, передав в него customer_access_token
:
fun fetchCards() {
...
scope.launch(Dispatchers.IO) {
this.customerCards = Ioka.getCards(customerAccessToken)
}
...
}
Вызовите метод Ioka.instance.getSavedCards()
, передав в него customer_access_token
:
// Список сохраненных карт
List<SavedCard>? savedCards;
void initState() {
super.initState();
// Загружаем сохраненные карты при создании страницы
_loadCards();
}
Future<void> _loadCards() {
// Получаем список сохраненных карт и сохраняем в переменной.
// customerAccessToken был получен в шаге (2).
savedCards = await Ioka.instance.getSavedCards(
customerAccessToken: widget.customerAccessToken,
);
// Обновляем интерфейс
setState(() {});
}
4. Отобразить сохраненные карты в своем интерфейсе
- iOS
- Android
- Flutter
Для получения иконки типа карты (Mastercard, Visa) и иконки банка-эмитента используйте свойства paymentSystemIcon
и emitterIcon
в объекте SavedCard
:
// Отображаемая карта
let savedCard = ...
paymentSystemImageView.image = savedCard.paymentSystemIcon
emitterImageView.image = savedCard.emitterIcon
Ioka.getCards() возвращает список инстансов публичного класса CardModel:
data class CardModel(
// Идентификатор карты
val id: String?,
// Идентификатор клиента, к которому привязана карта
val customerId: String?,
// Время привязки карты к пользователю
val createdAt: String?,
// Замаскированный PAN-номер карты
val panMasked: String?,
// Срок годности карты
val expiryDate: String?,
// Имя обладателя карты
val holder: String?,
// Платежная система карты (VISA, MASTERCARD, и т.д.)
val paymentSystem: String?,
// Банк-эмиттент привязанной карты (Alfa, Kaspi, и т.д.)
val emitter: String?,
// Флаг, который определяет нужно ли подтверждение CVV для оплаты данной картой
// Используется во флоу оплаты сохраненной картой
val cvcRequired: Boolean?,
)
Для отображения типа карты (Mastercard, Visa) используйте виджет CardTypeIcon
:
return CardTypeIcon(
type: savedCard.cardTypeString, // Геттер в [SavedCard] - возвращает тип карты
size: 24.0,
);
4.1. Метод удаления сохраненной карты
Если вы даете возможность удалить сохраненную карту на этом экране, то используйте соответствующий метод SDK.
- iOS
- Android
- Flutter
Используйте метод deleteSavedCard()
. Необходимо передать customer_access_token
и id
карты, которую нужно удалить.
// Выбранная пользователем карта
let savedCard = ...
Ioka.shared.deleteSavedCard(customerAccessToken: customerAccessToken, cardId: savedCard.id) { error in
if let error = error {
// Отобразите ошибку в своём интерфейсе
} else {
// Удалите карту из списка
}
}
Для удаления сохраненной карты пользователя, вызовите следующий suspend
метод:
// cardId достаем из CardModel
// Возвращает Boolean со значением: true, если удаление успешно; false, если нет
Ioka.removeCard(customerAccessToken: String, cardId: String): Boolean
Используйте метод deleteSavedCard()
. Необходимо передать customer_access_token
и id
карты, которую нужно удалить.
// Карта, которую мы хотим удалить
final savedCard = ...;
// Удаляем эту карту
await Ioka.instance.deleteSavedCard(
customerAccessToken: widget.customerAccessToken,
cardId: savedCard.id,
);
4.2. Метод получения сохраненной карты
Если вы хотите получить сохраненную карту по id карты, то используйте соответствующий метод SDK.
- iOS
- Android
Используйте метод getSavedById()
. Необходимо передать customer_access_token
и id
карты, которую нужно получить.
let cardId = ...
Ioka.shared.getSavedCardById(customerAccessToken: customerAccessToken, cardId: cardId) { result in
switch result {
case .success(let savedCard):
// Полученная сохраненная карта
case .failure(let error):
// Ошибка произошедшая во время получения сохраненной карты
}
}
Для получения сохраненной карты пользователя по ее идентификатору, вызовите следующий suspend
метод:
// Возвращает CardModel
Ioka.getCardById(customerAccessToken: String, cardId: String): CardModel
4.3. Метод создания экземпляра сохраненной карты
Если вы хотите создать экземпляр сохраненной карты, то используйте соответствующий метод SDK.
- iOS
Используйте метод createSavedCardInstance()
. Необходимо передать id сохраненной карты, маскированный PAN карты, срок действия карты, срок действия. Опционально: платежная систему и код банка.
/// Идентификатор сохраненной карты.
let cardId: String = ...
/// Маскированный PAN карты в формате "555555******5599".
let let maskedPan: String = ...
/// Срок действия карты в формате "12/24"
let expirationDate: String? = ...
/// Платежная система карты (VISA, MASTERCARD, и тд.)
let paymentSystem: String? = ...
/// Код банка, выпустившего карту
let emtter: String? = ...
/// Необходимость ввода cvc при оплате
let cvvRequired: Bool = ...
let savedCard = Ioka.shared.createSavedCardInstance(id: cardId, maskedPan: maskedPan, expirationDate: expirationDate, paymentSystem: paymentSystem, emitter: emitter, cvvRequired: svvRequired)
5. Вызвать метод оплаты в SDK
В зависимости от того, какой способ оплаты выбрал пользователь, вызовите либо метод оплаты сохраненной картой, либо метод оплаты новой картой.
5.1. Метод оплаты сохраненной картой
Метод запускает сценарий оплаты сохраненной картой. Отображает при необходимости форму ввода CVV и форму 3DSecure, также отображает результат оплаты.
- iOS
- Android
- Flutter
Вызовите Ioka.shared.startPaymentWithSavedCardFlow()
, передав в него sourceViewController
, orderAccessToken
и savedCard
.
// Выбранная пользователем карта
let savedCard = ...
Ioka.shared.startPaymentWithSavedCardFlow(sourceViewController: self, orderAccessToken: orderAccessToken, card: savedCard) { _ in
// ...
}
Экраны, которые отображаются в рамках сценария оплаты сохраненной картой в ioka SDK:
// activity - Activity, из которого стартует флоу оплаты сохраненной картой
// orderAccessToken получаем из сервиса мерчанта
// CardDvo - класс, который используется для отображения информации по карте
// Configuration - класс для кастомизации UI-компонентов
Ioka.startPaymentWithSavedCardFlow(activity: Activity, orderAccessToken: String, card: CardDvo, configuration: Configuration? = null)
Класс CardDvo используется для отображения информации о карте:
data class CardDvo(
// Идентификатор карты
val cardId: String,
// Замаскированный PAN-номер карты
val cardNumber: String,
// Код платежной системы карты (получать из CardModel.paymentSystem)
val cardType: String,
// Флаг, который определяет нужно ли подтверждение CVV для оплаты данной картой
val cvvRequired: Boolean,
)
Экраны, которые отображаются в рамках сценария оплаты сохраненной картой в ioka SDK:
Вызовите Ioka.instance.startCheckoutWithSavedCardFlow()
, передав в него context
, orderAccessToken
и savedCard
.
// Выбранная пользователем карта
final savedCard = ...;
ElevatedButton(
onPressed: () async {
// Начинаем оплату
final result = await Ioka.instance.startCheckoutWithSavedCardFlow(
context: context,
orderAccessToken: widget.orderAccessToken,
savedCard: savedCard,
);
},
child: const Text('Оформить'),
);
Экраны, которые отображаются в рамках сценария оплаты сохраненной картой в ioka SDK:
Подробнее о взаимодействиях с сохраненными картами можно прочитать в соответствующей инструкции.
5.2. Метод оплаты новой картой
- iOS
- Android
- Flutter
Вызовите Ioka.shared.startPaymentFlow()
, передав в него orderAccessToken
и другие необходимые параметры.
// activity - Activity, из которого стартует флоу оплаты банковской картой
// orderAccessToken получаем из сервиса мерчанта
// Configuration - это класс для кастомизации UI-компонентов
Ioka.startPaymentFlow(activity: Activity, orderAccessToken: String, configuration: Configuration? = null)
Вызовите Ioka.instance.startCheckoutFlow()
, передав в него context
и orderAccessToken
.
Этот метод такой же, как и в Оплата без использования функционала сохраненных карт.
5.3 Обработка результата
В обоих сценариях оплаты ioka SDK отображает результат оплаты в своём интерфейсе. После того, как пользователь закрывает экран результата оплаты, результат передаётся вам, чтобы вы могли его обработать. Например, очистить корзину при успешной оплате.
- iOS
- Android
- Flutter
Оба метода оплаты принимают completion
блок, в который передаётся результат оплаты.
// result, который передаётся в completion блок в методах оплаты
let result = ...
switch result {
case .succeeded:
// Ваша логика для успешной оплаты. Например, очистка корзины.
case .failed(let error):
// Ваша логика для неудачной оплаты.
case .cancelled:
// Ваша логика для закрытия пользователем экрана оплаты.
}
Для отправки результата на вызывающий Activity
мы используем метод Activity.startActivityForResult()
. Для передачи результата используется sealed класс FlowResult
:
/**
* Класс используется для отправки результата до активити мерчанта
* Любой флоу имеет три варианта исхода:
*
* [Succeeded] - флоу завершен успешно, пример: карта сохранена успешно
* [Failed] - флоу завершен неуспешно, пример: не удалось оплатить платеж
* @param [cause] - причина ошибки
* [Cancelled] - пользователь завершил флоу вручную, пример: вернулся на страницу мерчанта по нажатию "Назад"
*/
sealed class FlowResult {
object Succeeded : FlowResult()
class Failed(val cause: String) : FlowResult()
object Cancelled : FlowResult()
}
Поэтому для получения результата оплаты (Succeeded, Cancelled, Failed), переопределите метод onActivityResult()
. requestCode
для флоу оплаты сохраненной картой используется публичная константа IOKA_PAYMENT_REQUEST_CODE
(можете импортировать из ioka SDK). Пример получения результата:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
...
if (requestCode == IOKA_PAYMENT_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
val result = data?.getParcelableExtra<FlowResult>(IOKA_EXTRA_RESULT_NAME)
result?.let {
if (it is FlowResult.Succeeded)
// Оплата прошла успешно
else if (it is FlowResult.Failed)
// Оплата прошла неуспешно
}
} else if (resultCode == RESULT_CANCELED) {
// Флоу оплаты завершен пользователем, пример: нажал "Назад"
}
}
}
Методы оплаты возвращают Future
типа ExtendedPayment
- подробнее об этом классе можно прочитать в документации API.
В случае, если пользователь прервал оплату, то функции возвращает null
.
// Результат, который возвращают методы оплаты
final result = ...
if (result != null) {
// Возможно прошла оплата - необходимо проверить [result.status]
if (result.status == PaymentStatus.captured ||
result.status == PaymentStatus.approved) {
// Успешно проведена оплата, например, очищаем корзину
Provider.of<CartProvider>().clear();
}
else {
// Оплата не прошла и пользователь решил не повторять попытку
}
}
else {
// Пользователь отменил оплату
}
// Закрываем страницу оформления заказа
Navigator.pop(context);