Skip to content

IOS SDK

SDK (Software Development Kit) для IOS— это набор инструментов, библиотек и документации, предназначенных для разработки приложений под операционную систему Android. SDK IOS может использоваться для интеграции с API платежных систем. Он предоставляет инструменты и библиотеки, которые помогают разработчикам создавать приложения, способные взаимодействовать с платежными API.

V2 - новая версия

1 Подключение sdk

2 Flutter - дополнительные шаги интеграции

3 Подключение нативного ApplePay

4 API создания платежа

5 API формы стандартного флоу

6 API ApplePay

7 API сохраненных карт


1 Подключение sdk

  1. SPM -> GitHub - developerslicense/apay-ios
  2. Нужно добавить конфиги в info.plist

KEY -> Privacy - Face ID Usage Description

TYPE -> String

VALUE -> “Запрос доступа к сохраненным картам”

Untitled

KEY -> Privacy - Privacy - Camera Usage Description

TYPE -> String

VALUE -> “Предоставьте разрешение для использования сканнера банковских карт”

Untitled

  1. Нужно добавить import AirbaPay ****в файле App и в месте использования в приложении. В App нужно выполнить регистрацию шрифтов при инициализации.
swift
@main
struct TestApp: App {
    init() {
        AirbaPayFonts.registerCustomFonts()
        ~~~
    }

Для инициализации sdk нужно выполнить AirbaPaySdk.initSdk(). Функция возвращает экземпляр класса AirbaPaySdk.

ПараметрТипОписание
isProd*boolПродовская или тестовая среда airbapay
lang*AirbaPaySdk.LangКод языка для UI
phone*stringТелефон пользователя
userEmailstringЕмейл пользователя, куда будет отправлена квитанция. В случае отсутствия емейла
colorBrandMainColorБрендовый цвет кнопок, переключателей и текста
colorBrandInversionColorЦвет текста у кнопок с брендовым цветом
enabledLogsForProdboolФлаг для включения логов
needDisableScreenShotBoolФлаг включения/отключения защиты от скриншота страниц. По дефолту выключен
actionOnCloseProcessing*@escaping (Bool?, UINavigationController) -> VoidЗамыкание для возврата в приложение. Bool - результат успех или ошибка. UINavigationController - для вызова функций возврата
openCustomPageSuccess(() -> Void)?Замыкание для перехода на кастомную страницу успеха
openCustomPageFinalError(() -> Void)?Замыкание для перехода на кастомную страницу финальной ошибки
swift
let airbaPaySdk = AirbaPaySdk.initSdk(
   isProd: false,
   lang: AirbaPaySdk.Lang.RU(),
   phone: PHONE,
   userEmail: "test@test.com",
   colorBrandMain: Color.red,
   actionOnCloseProcessing: { isSuccess, navigation in
      navigation.present(~)   
   }
)

2 Flutter - дополнительные шаги интеграции

  1. В dart добавьте:
dart
final MethodChannel channel = MethodChannel("com.example.testFlutter/AirbaPayChannel");

Future<void> callNativeMethod() async {
    try {
      await channel.invokeMethod('pay');
    } catch (e) {
      print('Error calling native method: $e');
    }
}

И нужно вызвать callNativeMethod для перехода на страницы SDK.

  1. Создайте файл AirbaPayHandler
dart
import Foundation;
import Flutter;
import SwiftUI;

func handleAirbaPayChannel(
  _ app: AppDelegate,
  _ call: FlutterMethodCall,
  _ result: OneShotFlutterResult
) {

  if call.method == "pay" {
    let airbaPaySdk = AirbaPaySdk.initSdk(
      ~
      actionOnCloseProcessing: { result, uiNavigationController in
         // Здесь нужно использовать OneShotFlutterResult для возврата результата
         // и закрытия сдк через uiNavigationController.dismiss(animated: false) или другие способы
      )
    )
    airbaPaySdk.standardFlow(
         isApplePayNative: true,
         applePayMerchantId: "merchant.~",
         shopName: "Shop Name"
    )
 
  } else {
    result.submit(FlutterMethodNotImplemented)
  }
}


class OneShotFlutterResult {
  private var result: FlutterResult?
  
  init(_ result: @escaping FlutterResult) {
    self.result = result
  }
  
  func submit(_ data: Any) {
    if (result != nil) {
      result!(data)
      result = nil
    }
  }
}
  1. Добавьте в AppDelegate
dart
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
   
let airbaPayChannel = FlutterMethodChannel(
     name: "com.example.testFlutter/AirbaPayChannel",
     binaryMessenger: controller.binaryMessenger
)
      
airbaPayChannel.setMethodCallHandler({ call, result -> Void in
     handleAirbaPayChannel(self, call, OneShotFlutterResult(result))
})

3 Подключение нативного ApplePay

  1. Добавить параметры в standardFlow()

    isApplePayNative: true

    applePayMerchantId: "merchant.~"

    shopName: "Shop Name"

  2. Перейти в консоль ApplePay https://developer.apple.com/account/resources/identifiers/list

  3. Добавьте в Certificates

    1й Type -> Apple Pay Payment Processing Certificate Name -> merchant...pf

    2й Type -> Apple Pay Merchant Identity Certificate Name -> merchant...pf

    3й Type -> Apple Pay Payment Processing Certificate Name -> merchant...spf

    4й Type -> Apple Pay Merchant Identity Certificate Name -> merchant...spf

  4. Перейти во внутрь идентификатора приложения. Поставьте галочку в Apple Pay Payment Processing и кликните edit

  5. Выберите

    • Apple Pay Prod Service merchant.~.pf
    • Apple Pay Test Service merchant.~.spf

    и нажмите continue

  6. Нажмите Save

  7. Зайдите в XCode в Targets -> Signing & Capabilities добавьте Apple Pay айди мерчантов поставьте галочки


4 API создания платежа

Запрос на авторизацию в системе AirbaPay через передачу логина, пароля и айди терминала. Возвращает токен. authPassword()

ПараметрТипОписание
terminalId*StringID терминала под которым создаётся платеж
shopId*StringID магазина в системе AirbaPay
password*StringПароль в системе AirbaPay
paymentIdString?ID платежа. В абсолютном большинстве случаев в этом запросе будет null. Нужен для обновления токена с новым paymentId
onSuccess*@escaping (String) -> VoidЛямбда на успех. Возвращает токен
onError*@escaping () -> VoidЛямбда на ошибку
swift
airbaPaySdk.authPassword(
      terminalId: "123qdfssdf",
      shopId: "test", 
      password: "test123!"
      onSuccess: { token in ~  },
      onError: { ~ }    
)

Запрос на авторизацию в системе AirbaPay через передачу JWT. authJwt()

ПараметрТипОписание
jwt*StringJWT токен
onSuccess*@escaping () -> VoidЛямбда на успех.
onError*@escaping () -> VoidЛямбда на ошибку
swift
airbaPaySdk.authJwt(
     onSuccess: { ~  },
     onError: { ~ },
     jwt: "~"
)

Запрос на инициализацию платежа в системе AirbaPay. Возвращает AirbaPaySdk.CreatePaymentResult. createPayment()

ПараметрТипОписание
authToken*StringТокен, полученный из auth или другой реализацией получения токена
failureCallback*StringURL вебхука при ошибке
successCallback*StringURL вебхука при успехе
purchaseAmount*DoubleСумма платежа
accountId*StringID аккаунта пользователя
invoiceId*StringID платежа в системе магазина
orderNumber*StringНомер заказа в системе магазина
onSuccess*(AirbaPaySdk.CreatePaymentResult) -> VoidЛямбда на успех. Возвращает AirbaPaySdk.CreatePaymentResult
onError*() -> VoidЛямбда на ошибку
renderApplePayBool?Флаг настройки показа функционала ApplePay в стандартном флоу. NULL - параметры с сервера
renderSavedCardsBool?Флаг настройки показа функционала сохраненных карт в стандартном флоу. NULL - параметры с сервера
renderSecurityBiometryBool?Флаг глобальной настройки в сдк для биометрии при оплате сохраненной картой или ApplePay. NULL - параметры с сервера
renderSecurityCvvBool?Флаг глобальной настройки в сдк для показа боттомщита с CVV при оплате сохраненной картой. NULL - параметры с сервера
autoChargeIntАвтоматическое подтверждение при 2х-стадийном режиме 0 - нет, 1 - да
goods[AirbaPaySdk.Goods]Список продуктов для оплаты. Если есть необходимость передачи списка товаров в систему
settlementPayments[AirbaPaySdk.SettlementPayment]Распределение платежа по компаниям. В случае одной компании, может быть null
swift
airbaPaySdk.createPayment(
    authToken: token,
    failureCallback: "https://site.kz/failure-clb",
    successCallback: "https://site.kz/success-clb",
    purchaseAmount: 1500.45,
    accountId: "77061111112",
    invoiceId: "1111111111",
    orderNumber: "ab1111111111"
    onSuccess: { result -> ~ },
    onError: { ~ }
)

AirbaPaySdk.CreatePaymentResult

ПараметрТипОписание
tokenString?Обновленный токен
paymentIdString?ID созданного платежа

5 API формы стандартного флоу

Предварительно выполнить airbaPaySdk.authPassword() вместе с airbaPaySdk.createPayment() Или выполнить только airbaPaySdk.authJwt()

Есть два варианта реализации стандартного флоу:

standardFlow().

ПараметрТипОписание
isApplePayNative*BoolФлаг, определяющий показ нативной кнопки ApplePay вместо вебвьюшки
applePayMerchantId*String?ID мерчанта ApplePay. Нужен для нативной формы. В случае вебверсии NIL
shopNameStringНазвание магазина, передающееся в боттомщит ApplePay
swift
airbaPaySdk.standardFlow(
     isApplePayNative: true,
     applePayMerchantId: "merchant.~",
     shopName: "Shop Name"
)

или для вебверсии ApplePay

airbaPaySdk.standardFlow(
     isApplePayNative: false,
     applePayMerchantId: nil
)

standardFlowWebView()

ПараметрТипОписание
isLoadingComplete*@escaping () -> VoidЗамыкание на завершение загрузки данных о платеже
onError*@escaping () -> VoidЗамыкание на ошибку
shouldOverrideUrlLoading*@escaping (AirbaPaySdk.ShouldOverrideUrlLoading) -> Void)Замыкание, в котором описаны действия на коллбэки с вебвьюшки

AirbaPaySdk.ShouldOverrideUrlLoading

ПараметрТипОписание
isCallbackSuccess*BoolФлаг, что можно вызвать переход на страницу успеха
isCallbackBackToApp*BoolФлаг, что можно вызвать переход в приложение. true - если была нажата стрелака "назад" или кнопка "Вернуться в магазин" на страницах ошибки
navAction*WKNavigationActionПроброс WKNavigationAction из коллбэка вебвьюшки
decisionHandler*(WKNavigationActionPolicy) -> ())Проброс (WKNavigationActionPolicy) -> () из коллбэка вебвьюшки
navController*UINavigationControllerКонтроллер навигации
swift
import WebKit

airbaPaySdk.standardFlowWebView(
   isLoadingComplete: { isLoading = false },
   shouldOverrideUrlLoading: { obj in
      if(obj.navAction.navigationType == .other) {
         obj.decisionHandler(.allow)
         return

      } else {
         if let redirectedUrl = obj.navAction.request.url {

               if obj.isCallbackSuccess {
                    // открыть страницу успеха
                     
               } else if obj.isCallbackBackToApp { 
                    // клик на кнопку "Вернуться в магазин" или на стрелку "назад"

               } else {
                     obj.decisionHandler(.allow)
                     return
                }
            }
      }

      obj.decisionHandler(.allow)

   },
   onError: { ~ }
)

6 API ApplePay

Для работы с ApplePay за пределами стандартного флоу:

  1. Полностью реализовать на стороне приложения механизм вызова ApplePay боттомщита и получения ApplePay токена.
  2. Выполнить пункт "3 Подключение нативного ApplePay"
  3. Предварительно выполнить airbaPaySdk.authPassword() вместе с airbaPaySdk.createPayment() Или выполнить только airbaPaySdk.authJwt()
  4. Вызвать после получения токена ApplePay функцию processExternalApplePay()
ПараметрТипОписание
applePayToken*StringТокен ApplePay
swift
airbaPaySdk.processExternalApplePay(applePayToken: applePayToken)

7 API сохраненных карт

Запрос списка сохраненных карт пользователя getCards()

Предварительно выполнить airbaPaySdk.authPassword() или airbaPaySdk.authJwt()

ПараметрТипОписание
onSuccess*@escaping ([BankCard]) -> VoidЗамыкание на успех со списком сохраненных карт
onNoCards*@escaping () -> VoidЗамыкание на отсутствие сохраненных карт

Запрос удаления сохраненной карты пользователя deleteCard()

Предварительно выполнить airbaPaySdk.authPassword() или airbaPaySdk.authJwt()

ПараметрТипОписание
cardId*StringID сохраненной карты
onSuccess*@escaping () -> VoidЗамыкание на успех
onError*@escaping () -> VoidЗамыкание на ошибку

Запрос проведения оплаты по сохраненной карте пользователя paySavedCard()

Предварительно выполнить airbaPaySdk.authPassword() или airbaPaySdk.authJwt()

ПараметрТипОписание
isLoading*@escaping (Bool) -> VoidЗамыкание для показа прогрессбара
onError*@escaping () -> VoidЗамыкание на ошибку
bankCard*BankCardЭкземпляр карты, получаемый из запроса getCards

V1 - первая версия SDK до обновления, для новых партнеров использовать V2.

1.1 Подключение sdk

1.2 Вызов стартовой формы

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

1.4 Подключение нативного ApplePay

1.5 Подключение API внешнего взаимодействия с ApplePay (Нативный)

1.6 Подключение API внешнего взаимодействия с ApplePay (Вебвью)

1.7 Рекомендация в случае интеграции в flutter

1.1 Подключение sdk

  1. SPM -> GitHub - developerslicense/apay-ios
  2. Нужно добавить конфиги в info.plist

KEY -> Privacy - Face ID Usage Description

TYPE -> String

VALUE -> “Запрос доступа к сохраненным картам”

Untitled

KEY -> Privacy - Privacy - Camera Usage Description

TYPE -> String

VALUE -> “Предоставьте разрешение для использования сканнера банковских карт”

Untitled

  1. Нужно добавить import AirbaPay в файле App и в месте использования в приложении. В App нужно выполнить регистрацию шрифтов при инициализации.
swift
@main
struct TestApp: App {
    init() {
        AirbaPayFonts.registerCustomFonts()
        ~~~
    }
  1. Для инициализации sdk нужно выполнить AirbaPaySdk.initSdk() перед

    вызовом AirbaPaySdk.startAirbaPay() .

ПараметрТипОписание
shopId*stringID магазина в системе AirbaPay
password*stringПароль в системе AirbaPay
terminalId*stringID терминала под которым создали платеж
accountId*stringID аккаунта пользователя
langAirbaPaySdk.LangКод языка для UI
isProdboolПродовская или тестовая среда airbapay
phonestringТелефон пользователя
failureCallbackstringURL вебхука при ошибке
successCallbackstringURL вебхука при успехе
userEmailstringЕмейл пользователя, куда будет отправлена квитанция. В случае отсутствия емейла
colorBrandMainColorБрендовый цвет кнопок, переключателей и текста
colorBrandInversionColorЦвет текста у кнопок с брендовым цветом
autoChargeIntАвтоматическое подтверждение при 2х-стадийном режиме 0 - нет, 1 - да
enabledLogsForProdмФлаг для включения логов
purchaseAmountIntСумма платежа
invoiceIdstringID платежа в системе магазина
orderNumberstringНомер заказа в системе магазина
goodsArray<AirbaPaySdk.Goods>Список продуктов для оплаты
settlementPaymentsArray<AirbaPaySdk.SettlementPayment>Распределение платежа по компаниям. В случае одной компании, может быть nil
shopNamestringНазвание магазина для нативного ApplePay
isApplePayNativeBoolФлаг, определяющий показ нативной кнопки ApplePay вместо вебвьюшки
applePayMerchantIdstringАйдишка мерчанта, прописанная в консоли ApplePay
needDisableScreenShotBoolФлаг включения/отключения защиты от скриншота страниц. По дефолту выключен
swift
let goods = [
          AirbaPaySdk.Goods(
              model: "Чай Tess Banana Split черный 20 пирамидок",
              brand: "Tess",
              category: "Черный чай",
              quantity: 1,
              price: 1000
          )
      ]

      let settlementPayment = [
          AirbaPaySdk.SettlementPayment(
              amount: 1000,
              companyId: "test_id"
          )
      ]
      
      AirbaPaySdk.initSdk(
           isProd: false,
           lang: AirbaPaySdk.Lang.RU(),
           accountId: ACCOUNT_ID_TEST,
           phone: PHONE,
           userEmail: "test@test.com",
           shopId: "test",
           password: "123!",
           terminalId: "6421c4a48db060dd689",
           failureCallback: "https://site.kz/failure-clb",
           successCallback: "https://site.kz/success-clb",
           colorBrandMain: Color.red,
           autoCharge: autoCharge,
           purchaseAmount: 1500,
           invoiceId: String(someInvoiceId),
           orderNumber: String(someOrderNumber),
           goods: goods,
           settlementPayments: settlementPayment,
           isApplePayNative: true,
           shopName: "Shop Name",
           applePayMerchantId: "merchant.~"
  }

1.2 Вызов стартовой формы

Открытие формы AirbaPay выполняется через AirbaPaySdk.startAirbaPay().

ПараметрТипОписание
isCustomSuccessPageViewBoolФлаг переключения на кастомную вьюшку успешного кейса
isCustomFinalErrorPageViewBoolФлаг переключения на кастомную вьюшку финального неуспешного кейса
actionOnOpenProcessing() -> VoidДействие на открытие процессинга
actionOnCloseProcessing(Bool) -> VoidДействие на закрытие процессинга с возвратом результата
swift
@ObservedObject var navigateCoordinator = AirbaPayCoordinator(
            actionOnOpenProcessing: { ~ },
            actionOnCloseProcessing: { result in  ~ },
            customSuccessPageView: AnyView(~~~)
    )

AirbaPayView

ПараметрТипОписание
navigateCoordinator*@ObservedObject AirbaPayCoordinatorКоординатор навигации
contentView*AnyView?Контент страницы, на которой будет вызван sdk

SwiftUi:

Контент страницы приложения обернуть в AirbaPayView

swift
var body: some View {
     AirbaPayView(
        navigateCoordinator: navigateCoordinator,
        contentView: contentView
     )
}

Storyboards:

Открыть новую страницу с содержимым swiftUi.

Ниже описан кратко вариант интеграции. Более подробно описано в статье https://sarunw.com/posts/swiftui-view-as-uiview-in-storyboard/

  • Добавить Container View и удалить привязанный к нему дефолтный ViewController

  • Добавить UIHostingController и привязать Container View к нему через Embed

  • Связать это с ViewController кодом, указанным в примере:

Пример:

swift
@IBSegueAction func initPage(_ coder: NSCoder) -> UIViewController? {
        
        AirbaPaySdk.initSdk(~)

        return UIHostingController(coder: coder, rootView: SwiftUIView(
            actionOnClick: {
                DispatchQueue.main.async {
                    let hostingController = UIHostingController(
                        rootView: AirbaPayView(
                            navigateCoordinator: self.navigateCoordinator,
                            contentView: {}
                        ).onAppear {
                            self.navigateCoordinator.startProcessing()
                        }
                    )
                    
                    self.navigationController?.pushViewController(hostingController, animated: true)
                }
            },
            navigateCoordinator: navigateCoordinator
        ))
}

struct SwiftUIView: View {
    var actionOnClick: () -> Void
    @ObservedObject var navigateCoordinator: AirbaPayCoordinator

    var body: some View {
        Button(
            action: actionOnClick,
            label: { Text("Продолжить") }
        )  
    }
}

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

В случае наличия на странице системных элементов управления (к примеру, кнопки назад), обязательно нужно скрыть их (в случае навигации в swiftUi через .navigationBarBackButtonHidden(true))

Пример:

swift
struct TestCustomSuccessPage: View {

    var body: some View {
        Button(action: {}, label: { Text("TestSuccessPage") })
    }
}

struct TestPage: View {
    var back: () -> Void
    var phone: String = ""

    @ObservedObject var navigateCoordinator = AirbaPayCoordinator(
            customSuccessPageView: AnyView(TestCustomSuccessPage())
    )

    var body: some View {
            AirbaPayView(
                    navigateCoordinator: navigateCoordinator,
                    contentView: {

                        VStack {
                                Button(
                                        action: {

                                            AirbaPaySdk.initSdk(~~~)
                                            navigateCoordinator.startProcessing()

                                        },

                                        label: {
                                            Text("переход на эквайринг")
                                        }
                                )
                                Spacer()
                            }
                    }
            )
    }
}

1.4 Подключение нативного ApplePay

  1. Добавить параметры в initSdk

isApplePayNative = true

applePayMerchantId = "merchant.~"

  1. Перейти в консоль ApplePay https://developer.apple.com/account/resources/identifiers/list

  2. Добавьте в Certificates 1й Type -> Apple Pay Payment Processing Certificate Name -> merchant.~.pf

2й Type -> Apple Pay Merchant Identity Certificate Name -> merchant.~.pf

3й Type -> Apple Pay Payment Processing Certificate Name -> merchant.~.spf

4й Type -> Apple Pay Merchant Identity Certificate Name -> merchant.~.spf

  1. Перейти во внутрь идентификатора приложения. Поставьте галочку в Apple Pay Payment Processing и кликните edit

  2. Выберите ~ Apple Pay Prod Service merchant.~.pf ~ Apple Pay Test Service merchant.~.spf и нажмите continue

  3. Нажмите Save

  4. Зайдите в XCode в Targets -> Signing & Capabilities добавьте Apple Pay айди мерчантов поставьте галочки

1.5 Подключение API внешнего взаимодействия с ApplePay (Нативный)

buyBtnTapped

ПараметрТипОписание
redirectFromStoryboardToSwiftUi(() -> Void)?Замыкание перехода в сдк для storyboard
backToStoryboard(() -> Void)?Замыкание возврата в приложение для storyboard

ApplePayManager

ПараметрТипОписание
navigateCoordinator*@ObservedObject AirbaPayCoordinatorКоординатор навигации

SwiftUI:

  1. Добавить, как указано в примере:
swift
struct TestPage: View {
@ObservedObject var navigateCoordinator = AirbaPayCoordinator(~)

var body: some View {
let applePay = ApplePayManager(navigateCoordinator: navigateCoordinator)

    AirbaPayView(
            navigateCoordinator: navigateCoordinator,
            contentView: {
              // контент страницы приложения
              ~~~

              // кнопка продолжения
              Button(
                 action: {
                    ~~~

                    AirbaPaySdk.initSdk(
                       ~
                       isApplePayNative: true,
                       shopName: ~,
                       applePayMerchantId:  "merchant.~"
                   )

                   applePay.buyBtnTapped()

                 }
              )
            }
    )
}

Storyboards:

Внимание! Для storyboard недоступны кастомные страницы завершения

  1. Добавить импорты воViewController

import SwiftUI import AirbaPay

  1. Добавить @ObservedObject var navigateCoordinator = AirbaPayCoordinator()
  2. Дальше надо выполнить ряд действий для подключения вьюшки в storyboard. Ниже описан кратко вариант интеграции. Более подробно описано в статье https://sarunw.com/posts/swiftui-view-as-uiview-in-storyboard/
  • ДобавитьContainer Viewи удалить привязанный к нему дефолтный ViewController
  • Добавить UIHostingController и привязать Container View к нему через Embed
  • Связать это с ViewController кодом, указанным ниже
swift
@IBSegueAction func addApplePay(_ coder: NSCoder) -> UIViewController? {
        
        AirbaPaySdk.initSdk(~)
        let applePay = ApplePayManager(navigateCoordinator: navigateCoordinator)

        return UIHostingController(coder: coder, rootView: SwiftUIView(
            actionOnClick: {
                let hostingController = UIHostingController(
                    rootView: AirbaPayNextStepApplePayView(navigateCoordinator: self.navigateCoordinator)
                )
                
                self.navigationController?.pushViewController(hostingController, animated: true)
            },
            actionOnClose: {
                self.navigationController?.popViewController(animated: true)
            },
            navigateCoordinator: navigateCoordinator,
            applePay: applePay
        ))
}

struct SwiftUIView: View {
    var actionOnClick: () -> Void
    var actionOnClose: () -> Void
    @ObservedObject var navigateCoordinator: AirbaPayCoordinator
    let applePay: ApplePayManager
 
    var body: some View {
        Button(
            action: {
               applePay.buyBtnTapped(
                        redirectFromStoryboardToSwiftUi: actionOnClick,
                        backToStoryboard: actionOnClose
               )
            }
        )
    }
}

1.6 Подключение API внешнего взаимодействия с ApplePay (Вебвью)

Для работы с ApplePay потребуется вьюшка ApplePayWebViewExternal из AirbaPay.

Визуально она не будет отображаться на экране, т.к. занимает всего 0.1. Вьюшку можно поместить вниз экрана.

ПараметрТипОписание
redirectFromStoryboardToSwiftUi(() -> Void)?Замыкание перехода в сдк для storyboard
backToStoryboard(() -> Void)?Замыкание возврата в приложение для storyboard
navigateCoordinator*@ObservedObject AirbaPayCoordinatorКоординатор навигации
isLoading*@escaping (Bool) -> VoidЗамыкание для показа лоадинга или плейсхолдера
applePayViewModel*@ObservedObject ApplePayViewModelViewModel для работы с эппл пэй из AirbaPay

SwiftUi:

Примечание: Если вы используете SwiftUi в Storyboards, то применяйте инструкцию для Storyboards.

  1. Выполнить в onAppear AirbaPaySdk.initSdk(~)
  2. Добавить, как указано в примере:
swift
struct TestPage: View {
    
    @ObservedObject var navigateCoordinator = AirbaPayCoordinator(~)
    @ObservedObject var applePayViewModel = ApplePayViewModel()
    
     var body: some View {

        AirbaPayView(
                navigateCoordinator: navigateCoordinator,
                contentView: {
                  // контент страницы приложения 
                  ~~~
                  
                  // кнопка продолжения 
                  Button(
                     action: {
                        ~~~
                        // Нужно показать прогрессбар, т.к. потребуется время для загрузки
                       
                        applePayViewModel.auth(
                               onError: {
                                 // Коллбэк для обработки ошибки и скрытия прогрессбара
                               },
                               onSuccess: {
                                  // Коллбэк для скрытия прогрессбара 
                               }
                           )
                       
                     }
                  )
                  
                   ApplePayWebViewExternal(
                       navigateCoordinator: navigateCoordinator,
                       applePayViewModel: applePayViewModel
                  )
                }
        )
     }

Storyboards:

Внимание! Для storyboard недоступны кастомные страницы завершения

  1. Добавить импорты во ViewController

import SwiftUIimport AirbaPay

  1. Добавить @ObservedObject var navigateCoordinator = AirbaPayCoordinator()
  2. Дальше надо выполнить ряд действий для подключения вьюшки в storyboard. Ниже описан кратко вариант интеграции. Более подробно описано в статье https://sarunw.com/posts/swiftui-view-as-uiview-in-storyboard/
  • Добавить Container View и удалить привязанный к нему дефолтный ViewController
  • Добавить UIHostingController и привязать Container View к нему через Embed
  • Связать это с ViewController кодом, указанным ниже
swift
@IBSegueAction func addApplePay(_ coder: NSCoder) -> UIViewController? {
        
        AirbaPaySdk.initSdk(~)

        return UIHostingController(coder: coder, rootView: SwiftUIView(
            actionOnClick: {
                let hostingController = UIHostingController(
                    rootView: AirbaPayNextStepApplePayView(navigateCoordinator: self.navigateCoordinator)
                )
                
                self.navigationController?.pushViewController(hostingController, animated: true)
            },
            actionOnClose: {
                self.navigationController?.popViewController(animated: true)
            },
            navigateCoordinator: navigateCoordinator

        ))
}

struct SwiftUIView: View {
    var actionOnClick: () -> Void
    var actionOnClose: () -> Void
    @ObservedObject var navigateCoordinator = AirbaPayCoordinator()
    @ObservedObject var applePayViewModel = ApplePayViewModel()
    
    var body: some View {
        ZStack {
            Color.gray
            Color.white
            VStack {   
            
                // кнопка продолжения 
                Button(
                    action: {
                        applePayViewModel.auth(
                            onError: {
                                 // Коллбэк для обработки ошибки и скрытия прогрессбара
                            },
                            onSuccess: {
                                  // Коллбэк для скрытия прогрессбара 
                            }
                        )
                    }
                )
               
               ApplePayWebViewExternal(
                    redirectFromStoryboardToSwiftUi: actionOnClick,
                    backToStoryboard: actionOnClose,
                    navigateCoordinator: navigateCoordinator,
                    applePayViewModel: applePayViewModel
                )
            }
        }
    }
}

1.7 Рекомендация в случае интеграции в flutter

  1. В dart добавьте:

И нужно вызвать callNativeMethod для перехода на страницы сдк.

dart
final MethodChannel channel = MethodChannel("com.example.testFlutter/AirbaPayChannel");

Future<void> callNativeMethod() async {
  try {
    await channel.invokeMethod('pay');
  } catch (e) {
    print('Error calling native method: $e');
  }
}
  1. Создайте файл AirbaPayHandler
swift
import Foundation
import Flutter
import AirbaPay
import SwiftUI

func handleAirbaPayChannel(
  _ app: AppDelegate,
  _ call: FlutterMethodCall,
  _ result: OneShotFlutterResult
) {
  let controller : FlutterViewController = app.window?.rootViewController as! FlutterViewController

  if call.method == "pay" {
    let lang: AirbaPaySdk.Lang = AirbaPaySdk.Lang.RU()

    let someInvoiceId = ~
    let someOrderNumber = ~
      
      let goods = AirbaPaySdk.Goods(
        brand: "TechnoFit",
        category: "Services",
        model: "asdafasfd",
        quantity: 1,
        price: 5500
      )
      
    AirbaPaySdk.initSdk(
      isProd: false,
      lang: lang,
      accountId: "10000001",
      phone: "+77050000010",
      userEmail: "asdasd@sad.com",
      shopId: "test",
      password:  "123!",
      terminalId:  "64216e74a48db060dd689", 
      failureCallback: "https://site.kz/failure-clb",
      successCallback: "https://site.kz/success-clb",
      autoCharge: 0,
      enabledLogsForProd: true,
      purchaseAmount: 5500,
      invoiceId: String(someInvoiceId),
      orderNumber: String(someOrderNumber),
      goods: [goods]
    )

    controller.show(AirbaPayViewController(result: result), sender: controller)
  } else {
    result.submit(FlutterMethodNotImplemented)
  }
}

class OneShotFlutterResult {
  private var result: FlutterResult?
  
  init(_ result: @escaping FlutterResult) {
    self.result = result
  }
  
  func submit(_ data: Any) {
    if (result != nil) {
      result!(data)
      result = nil
    }
  }
}
  1. Создайте файл AirbaPayViewController
swift
import Foundation
import SwiftUI
import AirbaPay

class AirbaPayViewController : UIHostingController<AirbaPayView> {
  private var result: OneShotFlutterResult? = nil
  
  init(
    result: OneShotFlutterResult
  ) {
    var lateSelf: AirbaPayViewController? = nil
    self.result = result
    let navigateCoordinator = AirbaPayCoordinator(
      actionOnCloseProcessing: { r in
        lateSelf?.dismiss(animated: false)
        result.submit(["result": r])
      }
    )
    
    let airbaPayView = AirbaPayView(navigateCoordinator: navigateCoordinator) {}
    
    navigateCoordinator.startProcessing()
    super.init(rootView: airbaPayView)
    lateSelf = self
    view.backgroundColor = UIColor.black.withAlphaComponent(0)
  }
  
  required dynamic init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }
  
  override func viewDidDisappear(_ animated: Bool) {
    result?.submit(["result": false])
  }
  
  override func viewSafeAreaInsetsDidChange() {
    print("safe")
  }
}
  1. Добавьте в AppDelegate
swift
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController

let airbaPayChannel = FlutterMethodChannel(
     name: "com.example.testFlutter/AirbaPayChannel",
     binaryMessenger: controller.binaryMessenger
)
      
airbaPayChannel.setMethodCallHandler({ call, result -> Void in
     handleAirbaPayChannel(self, call, OneShotFlutterResult(result))
})