Git Product home page Git Product logo

acquiringsdk_ios's Introduction

Tinkoff Acquiring SDK for iOS

Acquiring SDK позволяет интегрировать Интернет-Эквайринг в мобильные приложения для платформы iOS.

Возможности SDK

  • Прием платежей (в том числе рекуррентных)
  • Сохранение банковских карт клиента
  • Работа с привязанными картами
  • Поддержка английской локализации
  • Интеграция с онлайн-кассами
  • Оплата с помощью Системы Быстрых Платежей
  • Оплата с помощью TinkoffPay
  • Оплата с помощью YandexPay
  • Конфигурация формы оплаты

Требования и ограничения

Для работы Tinkoff Acquiring SDK необходимо:

  • Поддержка iOS 12.3 и выше

Подключение

Cocoapods

Для подключения добавьте в файл Podfile зависимости:

pod 'TinkoffASDKCore'
pod 'TinkoffASDKUI'

Swift Package Manager

Используя Package.swift

Чтобы интегрировать AcquiringSdk в ваш проект используя Package.swift нужно указать зависимость:

dependencies: [
	.package(url: "https://github.com/Tinkoff/AcquiringSdk_IOS.git", .upToNextMajor(from: "2.10.1"))
]

Через Xcode

File -> Add packages -> https://github.com/Tinkoff/AcquiringSdk_IOS.git

Выберите нужные библиотеки:

  • TinkoffASDKCore - если вам нужен только Core функционал без UI части.

  • TinkoffASDKUI - уже включает в себя Core часть. Полное sdk - Core + UI часть.

spm-products

Подготовка к работе

⚠️ Необходимо хранить сильную ссылку на экземпляр AcquiringUISDK

Для начала работы с SDK вам понадобятся:

  • Terminal key - терминал Продавца
  • Public key – публичный ключ. Используется для шифрования данных. Необходим для интеграции вашего приложения с интернет-эквайрингом Тинькофф.

Данные выдаются в личном кабинете после подключения к Интернет-Эквайрингу.

Подробнее о настройке Личного кабинета можно прочитать тут

Начало работы

В начале нужно создать конфигурацию, используем объект AcquiringSdkConfiguration, обязательные параметры:

  • credential: AcquiringSdkCredential - учетные данные, полученные в личном кабинете
  • serverEnvironment: AcquiringSdkEnvironment - тестовый или боевой сервер

Дополнительные параметры которые можно установить:

  • logger - Интерфейс для логирование работы. Есть реализация по умолчанию - LoggerDelegate, форматирующий и выводящий данные о работе SDK в консоль
  • language - Язык платежной формы. На каком языке сервер будет присылать тексты ошибок клиенту.
  • showErrorAlert: Bool - Показывать ошибки после выполнения запроса системным UIAlertViewController
  • tokenProvider: ITokenProvider - протокол, предоставляющий токен для подписи запроса в API эквайринга. Необходим только для терминалов, с включенной проверкой токена

После инициализации SDK им можно пользоваться и вызывать форму для оплаты, и список карт.

Для проведения оплаты в модуле TinkoffASDKUI/AcquiringUISDK реализованы методы для различных сценариев оплаты. Доступны:

  • presentPaymentView(paymentData: PaymentInitData) - показать форму оплаты для выбора источника оплаты (сохраненная карта или реквизиты новой) и оплатить
  • presentPaymentView(paymentData: PaymentInitData, parentPatmentId Int64) быстрая оплата, оплатить рекуррентный/регулярный платеж.
  • presentPaymentSBP(paymentData: PaymentInitData) оплатить используя Систему Быстрых Платежей
  • presentPaymentAcceptanceQR() - сгенерировать и показать QR-код для приема платежей

Для работы со списком сохраненных карты реализован метод:

  • presentCardList показать список сохраненных карт, и отредактировать список карт - добавить карту, удалить карту.

Предоставление токена для подписи запросов

Если ваш терминал поддерживает валидацию токена, присылаемого в запросах к API эквайринга, то необходимо реализовать протокол ITokenProvider и передать его в AcquiringSdkConfiguration:

func provideToken(
	forRequestParameters parameters: [String: String], // Параметры, участвующие в генерации токена
	completion: @escaping (Result<String, Error>) -> Void // Замыкание, которое необходимо вызвать, передав результат генерации токена
)

Для генерации токена необходимо:

  • Добавить пароль от терминала в словарь с ключом Password
  • Отсортировать пары ключ-значение по ключам в алфавитном порядке
  • Конкатенировать значения всех пар
  • Для полученной строки вычислить хэш SHA-256

Подробнее о подписи запроса

Пример

В простейшем случае реализация может выглядеть следующим образом:

func provideToken(
	forRequestParameters parameters: [String: String],
	completion: @escaping (Result<String, Error>) -> Void
) {
	let sourceString = parameters
		.merging(["Password": password]) { $1 }
		.sorted { $0.key < $1.key }
		.map(\.value)
		.joined()

	let hashingResult = Result {
		try SHA256.hash(from: sourceString)
	}

	completion(hashingResult)
}

⚠️ Реализация выше приведена исключительно в качестве примера. В целях безопасности не стоит хранить и как бы то ни было взаимодействовать с паролем от терминала в коде мобильного приложения. Наиболее подходящий сценарий - передавать полученные параметры на бекенд, где будет происходить генерация токена на основе параметров и пароля

Форма оплаты с вводом реквизитов карты и ранее сохраненными картами

Для отображения формы оплаты необходимо вызвать метод AcquiringUISDK.presentPaymentView:

public func presentPaymentView(
	on presentingViewController: UIViewController,
	customerKey: String? = nil,
	acquiringPaymentStageConfiguration: AcquiringPaymentStageConfiguration,
	configuration: AcquiringViewConfiguration,
	tinkoffPayDelegate: TinkoffPayDelegate? = nil,
	completionHandler: @escaping PaymentCompletionHandler
)

По завершении платежа будет вызван completionHandler с Result<PaymentStatusResponse, Error>, в котором в случае успеха будут содержаться данные:

  • success: Bool - статус обработки запроса
  • errorCode: Int - номер ошибки в случае неуспешной инициализации платежа, по умолчанию 0
  • errorMessage: String? - описание ошибки
  • errorDetails: String? - детальное описание ошибки
  • terminalKey: String? - идентификатор терминала на котором инициализирован платеж
  • amount: Int64 - сумма платежа в копейках
  • orderId: String - номер заказа в системе продавца
  • paymentId: Int64 - номер для оплаты в системе банка
  • status: PaymentStatus - статус платежа. В случае удачной регистрации платежа на форме оплаты показываются список карт, карточка ввода реквизитов новой карты и кнопка Оплатить. Пользователь выбирает карту, либо вводит реквизиты новой нажимает и нажимает Оплатить

В методе выбор стадии платежа осуществляется с помощью AcquiringPaymentStageConfiguration. Далее рассмотрим доступные стадии

Оплата с инициацией платежа

В этом сценарии ASDK самостоятельно вызывает метод Init API эквайринга при совершении оплаты, передавая информацию о платеже, заданных в PaymentInitData:

  • amount: Int64 - Сумма в копейках. Например, сумма 3руб. 12коп. это число 312. Параметр должен быть равен сумме всех товаров в чеке
  • orderId: String - Номер заказа в системе Продавца
  • customerKey: String - Идентификатор клиента в системе продавца. Например, для этого идентификатора будут сохраняться список карт
  • description: String - Краткое описание покупки
  • payType: PayType - Тип проведения платежа
  • savingAsParentPayment: Bool - Если передается и установлен в true, то регистрирует платёж как рекуррентный (родительский)
  • paymentFormData: [String: String] - JSON объект, содержащий дополнительные параметры в виде [Key: Value].Key: String – 20 знаков, Value: String – 100 знаков. Максимальное количество пар параметров не может превышать 20
  • receipt: Receipt - Данные чека
  • shops: [Shop] - Информация о магазинах
  • receipts: [Receipt] - Информация о чеках для онлайн магазинов
  • redirectDueDate: Date? - Срок жизни ссылки
  • successURL: String? - URL на веб-сайте продавца, куда будет переведен покупатель в случае успешной оплаты (настраивается в Личном кабинете). Если параметр передан – используется его значение. Если нет – значение в настройках терминала
  • failURL: String? - URL на веб-сайте продавца, куда будет переведен покупатель в случае неуспешной оплаты (настраивается в Личном кабинете). Если параметр передан – используется его значение. Если нет – значение в настройках терминала
let paymentData: PaymentInitData = ...
let paymentStageConfiguration = AcquiringPaymentStageConfiguration(paymentStage: .`init`(paymentData: paymentData))

Оплата на основе существующего paymentId

В этом сценарии метод Init API эквайринга вызывается вне SDK, например на бекенде клиентского приложения. Затем в SDK эквайринга полученный paymentId передается с помощью:

let paymentId: Int64 = ...

let paymentStageConfiguration = AcquiringPaymentStageConfiguration(paymentStage: .finish(paymentId: paymentId))

TinkoffPay

Для работы с TinkoffPay необходимо добавить в Info.plist в массив по ключу LSApplicationQueriesSchemes значение tinkoffbank.

<key>LSApplicationQueriesSchemes</key>
<array>
  <string>tinkoffbank</string>
</array>
Кнопка TinkoffPay на форме оплаты

При открытии экрана оплаты SDK проверит наличие возможности оплаты через TinkoffPay и, в зависимости от результата, отобразит кнопку оплаты. Отключить отображение кнопки программно можно с помощью параметра tinkoffPayEnabled в featuresOptions в конфигурации AcquiringViewConfiguration.

Совершить платеж можно через общий экран оплаты, вызвав метод у экземпляра AcquiringUISDK.

func presentPaymentView(
	on presentingViewController: UIViewController,
    acquiringPaymentStageConfiguration: AcquiringPaymentStageConfiguration,
    configuration: AcquiringViewConfiguration,
    tinkoffPayDelegate: TinkoffPayDelegate?,
    completionHandler: @escaping PaymentCompletionHandler
)

В момент показа экрана оплаты, будет совершен запрос, который проверит, доступна ли оплата через TinkoffPay для вашего терминала и в случае доступности отобразится кнопка для совершения оплаты.

Для определения возможности оплаты через TinkoffPay SDK посылает запрос на https://securepay.tinkoff.ru/v2/TinkoffPay/terminals/$terminalKey/status.

Ответ на запрос кэшируется на некоторое время. Значение по-умолчанию 300 секунд. Его можно сконфигурировать через параметр tinkoffPayStatusCacheLifeTime у объектаAcquiringSdkConfiguration, который используется при инициализации AcquiringUISDK.

Посредством реализации протокола TinkoffPayDelegate можно получит сообщение о том, что оплата через Tinkoff Pay недоступна.

Можно сконфигурировать стиль кнопки TinkoffPay через параметр tinkoffPayButtonStyle у AcquiringViewConfiguration.

Кнопка TinkoffPay внутри вашего приложения

Для отображения кнопки оплаты через Tinkoff Pay внутри вашего приложения (вне экрана оплаты, предоставляемого SDK) необходимо:

  1. Самостоятельно вызвать метод определения доступности оплаты через Tinkoff Pay. Для этого можно использовать метод:
func getTinkoffPayStatus(completion: @escaping (Result<GetTinkoffPayStatusResponse, Error>) -> Void)
  1. При наличии возможности оплаты отобразить кнопку оплаты через Tinkoff Pay в вашем приложении

  2. По нажатию кнопки вызвать метод(параметр GetTinkoffPayStatusResponse.Status.Version получен на 1 шаге) и показать полученный из метода ViewController

func tinkoffPayViewController(
	acquiringPaymentStageConfiguration: AcquiringPaymentStageConfiguration,
    configuration: AcquiringViewConfiguration,
    version: GetTinkoffPayStatusResponse.Status.Version,
    completionHandler: PaymentCompletionHandler? = nil) -> UIViewController
)

Задача по закрытию ViewController, полученный из метода, ложится на плечи пользователя в момент вызова completionHandler.

API

Если необходимо использовать отдельно методы API для TinkoffPay: У экземпляра AcquiringSdk можно вызвать:

Для проверки доступности TinkoffPay на терминале

func getTinkoffPayStatus(completion: @escaping (Result<GetTinkoffPayStatusResponse, Error>) -> Void)

Для получения deeplink

func getTinkoffPayLink(
	paymentId: Int64,
    version: GetTinkoffPayStatusResponse.Status.Version,
    completion: @escaping (Result<GetTinkoffLinkResponse, Error>) -> Void
)
Кнопка TinkoffPay

Для отрисовки кнопки существует класс TinkoffPayButton.

При инициализации можно указать требуемый стиль кнопки.

При использовании этого инициализатора, у кнопки будет фиксированный стиль.

init(style: TinkoffPayButton.Style)

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

init(dynamicStyle: TinkoffPayButton.DynamicStyle)

Подключение сканера

для сканера нужно использовать любое стороннее решение, подключение сканера к SDK осуществляется через AcquiringViewConfiguration.scaner - это ссылка на объект который реализует протокол CardRequisitesScanerProtocol

protocol CardRequisitesScanerProtocol: class {
  func startScanner(completion: @escaping (_ number: String?, _ yy: Int?, _ mm: Int?) -> Void)
}

Пример использования:

extension RootViewController: AcquiringScanerProtocol {
	func presentScanner(completion: @escaping (_ number: String?, _ yy: Int?, _ mm: Int?) -> Void) -> UIViewController? {
		if let viewController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "CardScanerViewController") as? CardScanerViewController {
      		viewController.onScannerResult = { (numbres) in
      			completion(numbres, nil, nil)
			}
			
    		return viewController
		}
		
		return nil
	}
}

Отобразить список сохраненных карт

public func presentCardList(
	on presentingViewController: UIViewController,
	customerKey: String,
	configuration: AcquiringViewConfiguration
)

Пример создания экземпляра SDK

// терминал
let credential = AcquiringSdkCredential(terminalKey: ASDKStageTestData.terminalKey, publicKey: ASDKStageTestData.testPublicKey)
// конфигурация для старта sdk
let acquiringSDKConfiguration = AcquiringSdkConfiguration(credential: credential)
// включаем логи, результаты работы запросов пишутся в консоль 
acquiringSDKConfiguration.logger = AcquiringLoggerDefault()

if let sdk = try? AcquiringUISDK.init(configuration: acquiringSDKConfiguration) {
	// SDK проинициализировалось, можно приступать к работе
}

Пример создание AcquiringViewConfiguration

let viewConfiguration = AcquiringViewConfiguration()
// подключаем сканер
viewConfiguration.scaner = scaner
// Формируем поля для экрана оплаты
viewConfiguration.fields = []
// Заголовок в UINavigationBar, для случая когда экран оплаты раскрыт на весь экран
viewConfiguration.viewTitle = NSLocalizedString("title.pay", comment: "Оплата")
// 1. Заголовок экрана "Оплата на сумму хх.хх руб."
let title = NSAttributedString(string: NSLocalizedString("title.payment", comment: "Оплата"), attributes: [.font: UIFont.boldSystemFont(ofSize: 22)])
let amountString = Utils.formatAmount(NSDecimalNumber(floatLiteral: productsAmount()))
let amountTitle = NSAttributedString(string: "\(NSLocalizedString("text.totalAmount", comment: "на сумму")) \(amountString)", attributes: [.font : UIFont.systemFont(ofSize: 17)])
// fields.append
viewConfiguration.fields.append(AcquiringViewConfiguration.InfoFields.amount(title: title, amount: amountTitle))

// 2. Описание товаров которые оплачиваем
let productsDetails = NSMutableAttributedString()
productsDetails.append(NSAttributedString(string: "Книги\n", attributes: [.font : UIFont.systemFont(ofSize: 17)]))

let productsDetails = products.map { (product) -> String in
  return product.name
}.joined(separator: ", ")

productsDetails.append(NSAttributedString(string: productsDetails, attributes: [.font : UIFont.systemFont(ofSize: 13), .foregroundColor: UIColor(red: 0.573, green: 0.6, blue: 0.635, alpha: 1)]))
viewConfiguration.fields.append(AcquiringViewConfiguration.InfoFields.detail(title: productsDetails))

// 3. Добавляем поле email 
if AppSetting.shared.showEmailField {
  viewConfiguration.fields.append(AcquiringViewConfiguration.InfoFields.email(value: nil, placeholder: NSLocalizedString("placeholder.email", comment: "Отправить квитанцию по адресу")))
}

// 4. Кнопка для оплаты используя Систему Быстрых Платежей
if AppSetting.shared.paySBP {
  viewConfiguration.fields.append(AcquiringViewConfiguration.InfoFields.buttonPaySPB)
}

Кастомизация

Для того что бы кастомизировать UI компонента(цвет кнопки оплатить и т.д.), необходимо реализовать протокол Style и передать его экземпляр как параметр style при инициализации объекта SDK.

import TinkoffASDKUI

struct MyAwesomeStyle: Style {
...
}
let sdk = try AcquiringUISDK(configuration: acquiringSDKConfiguration style: MyAwesomeStyle())

ASDKSample

Содержит пример интеграции Tinkoff Acquiring SDK в мобильное приложение по продаже книг. Главный экран список заготовок товаров. Второй экран - детали товара и выбор способа оплаты.

Поддержка

  • Просьба, по возникающим вопросам обращаться на [email protected]
  • Баги и feature-реквесты можно направлять в раздел issues
  • Документация на сайте, описание API методов

acquiringsdk_ios's People

Contributors

ivanglushko avatar grishamsc avatar akhaman avatar novixon avatar elektroru avatar nik3212 avatar sigaldev avatar divalue avatar alexanderbrygin avatar artem-tverdokhlebov avatar barhishtan avatar nov1kov avatar pravosudovtinkoff avatar timbaev avatar frodox avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.