-
SPM -> GitHub -
developerslicense/apay-ios
-
Нужно добавить конфиги в
info.plist
KEY -> Privacy - Face ID Usage Description TYPE -> String VALUE -> “Запрос доступа к сохраненным картам”
KEY -> Privacy - Privacy - Camera Usage Description TYPE -> String VALUE -> “Предоставьте разрешение для использования сканнера банковских карт”
-
Нужно добавить
import AirbaPay
в файлеApp
и в месте использования в приложении. ВApp
нужно выполнитьрегистрацию шрифтов
при инициализации.
@main
struct TestApp: App {
init() {
AirbaPayFonts.registerCustomFonts()
~~~
}
Для инициализации sdk нужно выполнить AirbaPaySdk.initSdk()
. Функция возвращает экземпляр классаAirbaPaySdk
.
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
isProd | Bool | да | Продовская или тестовая среда airbapay |
lang | AirbaPaySdk.Lang | да | Код языка для UI |
phone | String | да | Телефон пользователя |
userEmail | String | нет | Емейл пользователя, куда будет отправлена квитанция. В случае отсутствия емейла |
colorBrandMain | Color | нет | Брендовый цвет кнопок, переключателей и текста |
colorBrandInversion | Color | нет | Цвет текста у кнопок с брендовым цветом |
enabledLogsForProd | Bool | нет | Флаг для включения логов |
needDisableScreenShot | Bool | нет | Флаг включения/отключения защиты от скриншота страниц. По дефолту выключен |
actionOnCloseProcessing | @escaping (Bool?, UINavigationController) -> Void | да | Лямбда, вызываемая при клике на кнопку "Вернуться в магазин" и при отмене процесса. Разработчику в ней нужно прописать код для возврата в приложение. |
openCustomPageSuccess | (() -> Void)? | нет | Лямбда кастомной страницы успеха |
openCustomPageFinalError | (() -> Void)? | нет | Лямбда кастомной страницы финальной ошибки |
Пример:
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(~)
}
)
-
В 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
для перехода на страницы сдк. -
Создайте файл
AirbaPayHandler
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 } } }
-
Добавьте в
AppDelegate
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)) })
-
Добавить параметры в
standardFlow
isApplePayNative: true
applePayMerchantId: "merchant.~"
shopName: "Shop Name"
-
Перейти в консоль ApplePay https://developer.apple.com/account/resources/identifiers/list
-
Добавьте в 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 -
Перейти во внутрь идентификатора приложения. Поставьте галочку в
Apple Pay Payment Processing
и кликните edit -
Выберите
- Apple Pay Prod Service merchant.~.pf
- Apple Pay Test Service merchant.~.spf
и нажмите continue
-
Нажмите Save
-
Зайдите в XCode в Targets -> Signing & Capabilities добавьте Apple Pay айди мерчантов поставьте галочки
Запрос на авторизацию в системе AirbaPay через передачу логина, пароля и айди терминала. Возвращает токен.
authPassword()
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
terminalId | String | да | ID терминала под которым создаётся платеж |
shopId | String | да | ID магазина в системе AirbaPay |
password | String | да | Пароль в системе AirbaPay |
paymentId | String? | нет | ID платежа. В абсолютном большинстве случаев в этом запросе будет null. Нужен для обновления токена с новым paymentId |
onSuccess | @escaping (String) -> Void | да | Лямбда на успех. Возвращает токен |
onError | @escaping () -> Void | да | Лямбда на ошибку |
airbaPaySdk.authPassword(
terminalId: "123qdfssdf",
shopId: "test",
password: "test123!"
onSuccess: { token in ~ },
onError: { ~ }
)
Запрос на авторизацию в системе AirbaPay через передачу JWT.
authJwt()
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
jwt | String | да | JWT токен |
onSuccess | @escaping () -> Void | да | Лямбда на успех. |
onError | @escaping () -> Void | да | Лямбда на ошибку |
airbaPaySdk.authJwt(
onSuccess: { ~ },
onError: { ~ },
jwt: "~"
)
Запрос на инициализацию платежа в системе AirbaPay.
Возвращает AirbaPaySdk.CreatePaymentResult
.
createPayment()
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
authToken | String | да | Токен, полученный из auth или другой реализацией получения токена |
failureCallback | String | да | URL вебхука при ошибке |
successCallback | String | да | URL вебхука при успехе |
purchaseAmount | Double | да | Сумма платежа |
accountId | String | да | ID аккаунта пользователя |
invoiceId | String | да | ID платежа в системе магазина |
orderNumber | String | да | Номер заказа в системе магазина |
onSuccess | (AirbaPaySdk.CreatePaymentResult) -> Void | да | Лямбда на успех. Возвращает AirbaPaySdk.CreatePaymentResult |
onError | () -> Void | да | Лямбда на ошибку |
renderApplePay | Bool? | нет | Флаг настройки показа функционала ApplePay в стандартном флоу. NULL - параметры с сервера |
renderSavedCards | Bool? | нет | Флаг настройки показа функционала сохраненных карт в стандартном флоу. NULL - параметры с сервера |
renderSecurityBiometry | Bool? | нет | Флаг глобальной настройки в сдк для биометрии при оплате сохраненной картой или ApplePay. NULL - параметры с сервера |
renderSecurityCvv | Bool? | нет | Флаг глобальной настройки в сдк для показа боттомщита с CVV при оплате сохраненной картой. NULL - параметры с сервера |
autoCharge | Int | нет | Автоматическое подтверждение при 2х-стадийном режиме 0 - нет, 1 - да |
goods | [AirbaPaySdk.Goods] | нет | Список продуктов для оплаты. Если есть необходимость передачи списка товаров в систему |
settlementPayments | [AirbaPaySdk.SettlementPayment] | нет | Распределение платежа по компаниям. В случае одной компании, может быть null |
AirbaPaySdk.CreatePaymentResult
Параметр | Тип | Описание |
---|---|---|
token | String? | Обновленный токен |
paymentId | String? | ID созданного платежа |
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 in ~ },
onError: { ~ }
)
Предварительно выполнить airbaPaySdk.authPassword()
вместе с airbaPaySdk.createPayment()
Или выполнить только airbaPaySdk.authJwt()
Есть два варианта реализации стандартного флоу:
standardFlow()
.
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
isApplePayNative | Bool | да | Флаг, определяющий показ нативной кнопки ApplePay вместо вебвьюшки |
applePayMerchantId | String? | да | ID мерчанта ApplePay. Нужен для нативной формы. В случае вебверсии NIL |
shopName | String | нет | Название магазина, передающееся в боттомщит ApplePay |
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.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: { ~ }
)
AirbaPaySdk.ShouldOverrideUrlLoading
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
isCallbackSuccess | Bool | да | Флаг, что можно вызвать переход на страницу успеха |
isCallbackBackToApp | Bool | да | Флаг, что можно вызвать переход в приложение. true - если была нажата стрелака "назад" или кнопка "Вернуться в магазин" на страницах ошибки |
navAction | WKNavigationAction | да | Проброс WKNavigationAction из коллбэка вебвьюшки |
decisionHandler | (WKNavigationActionPolicy) -> () | да | Проброс (WKNavigationActionPolicy) -> () из коллбэка вебвьюшки |
navController | UINavigationController | да | Контроллер навигации |
Для работы с ApplePay за пределами стандартного флоу:
-
Полностью реализовать на стороне приложения механизм вызова ApplePay боттомщита и получения ApplePay токена.
-
Выполнить пункт "3 Подключение нативного ApplePay"
-
Предварительно выполнить
airbaPaySdk.authPassword()
вместе сairbaPaySdk.createPayment()
Или выполнить толькоairbaPaySdk.authJwt()
-
Вызвать после получения токена ApplePay функцию
processExternalApplePay()
Параметр Тип Обязательный Описание applePayToken String да Токен ApplePay airbaPaySdk.processExternalApplePay(applePayToken: applePayToken)
Запрос списка сохраненных карт пользователя
getCards()
Предварительно выполнить airbaPaySdk.authPassword()
или airbaPaySdk.authJwt()
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
onSuccess | @escaping ([BankCard]) -> Void | да | Замыкание на успех со списком сохраненных карт |
onNoCards | @escaping () -> Void | да | Замыкание на отсутствие сохраненных карт |
Запрос удаления сохраненной карты пользователя
deleteCard()
Предварительно выполнить airbaPaySdk.authPassword()
или airbaPaySdk.authJwt()
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
cardId | String | да | ID сохраненной карты |
onSuccess | @escaping () -> Void | да | Замыкание на успех |
onError | @escaping () -> Void | да | Замыкание на ошибку |
Запрос проведения оплаты по сохраненной карте пользователя
paySavedCard()
Предварительно выполнить airbaPaySdk.authPassword()
или airbaPaySdk.authJwt()
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
bankCard | BankCard | да | Экземпляр карты, получаемый из запроса getCards |
isLoading | @escaping (Bool) -> Void | да | Замыкание для показа прогрессбара |
onError | @escaping () -> Void | да | Замыкание на ошибку |
-
SPM -> GitHub -
developerslicense/apay-ios
-
Нужно добавить конфиги в
info.plist
KEY -> Privacy - Face ID Usage Description
TYPE -> String
VALUE -> “Запрос доступа к сохраненным картам”
KEY -> Privacy - Privacy - Camera Usage Description
TYPE -> String
VALUE -> “Предоставьте разрешение для использования сканнера банковских карт”
- Нужно добавить
import AirbaPay
в файлеApp
и в месте использования в приложении. ВApp
нужно выполнитьрегистрацию шрифтов
при инициализации.
@main
struct TestApp: App {
init() {
AirbaPayFonts.registerCustomFonts()
~~~
}
Для инициализации sdk нужно выполнить AirbaPaySdk.initSdk()
перед
вызовом AirbaPaySdk.startAirbaPay()
.
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
shopId | String | да | ID магазина в системе AirbaPay |
password | String | да | Пароль в системе AirbaPay |
terminalId | String | да | ID терминала под которым создали платеж |
accountId | String | да | ID аккаунта пользователя |
lang | AirbaPaySdk.Lang | да | Код языка для UI |
isProd | Bool | да | Продовская или тестовая среда airbapay |
phone | String | да | Телефон пользователя |
failureCallback | String | да | URL вебхука при ошибке |
successCallback | String | да | URL вебхука при успехе |
userEmail | String | да | Емейл пользователя, куда будет отправлена квитанция. В случае отсутствия емейла |
colorBrandMain | Color | нет | Брендовый цвет кнопок, переключателей и текста |
colorBrandInversion | Color | нет | Цвет текста у кнопок с брендовым цветом |
autoCharge | Int | нет | Автоматическое подтверждение при 2х-стадийном режиме 0 - нет, 1 - да |
enabledLogsForProd | Bool | нет | Флаг для включения логов |
purchaseAmount | Double | да | Сумма платежа |
invoiceId | String | да | ID платежа в системе магазина |
orderNumber | String | да | Номер заказа в системе магазина |
goods | Array<AirbaPaySdk.Goods> | да | Список продуктов для оплаты |
settlementPayments | Array<AirbaPaySdk.SettlementPayment> | нет | Распределение платежа по компаниям. В случае одной компании, может быть nil |
shopName | String | нет | Название магазина для нативного ApplePay |
isApplePayNative | Bool | нет | Флаг, определяющий показ нативной кнопки ApplePay вместо вебвьюшки |
applePayMerchantId | String | нет | Айдишка мерчанта, прописанная в консоли ApplePay |
needDisableScreenShot | Bool | нет | Флаг включения/отключения защиты от скриншота страниц. По дефолту выключен |
Пример:
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: "123456!",
terminalId: "64216e7ccc4a48db060dd6891",
failureCallback: "https://site.kz/failure-clb",
successCallback: "https://site.kz/success-clb",
colorBrandMain: Color.red,
autoCharge: autoCharge,
purchaseAmount: 1500.0,
invoiceId: String(someInvoiceId),
orderNumber: String(someOrderNumber),
goods: goods,
settlementPayments: settlementPayment,
isApplePayNative: true,
shopName: "Shop Name",
applePayMerchantId: "merchant.~"
)
@ObservedObject var navigateCoordinator = AirbaPayCoordinator(
actionOnOpenProcessing: { ~ },
actionOnCloseProcessing: { result in ~ },
customSuccessPageView: AnyView(~~~)
)
Открытие формы AirbaPay выполняется через AirbaPaySdk.startAirbaPay().
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
isCustomSuccessPageView | Bool | нет | Флаг переключения на кастомную вьюшку успешного кейса |
isCustomFinalErrorPageView | Bool | нет | Флаг переключения на кастомную вьюшку финального неуспешного кейса |
actionOnOpenProcessing | () -> Void | нет | Действие на открытие процессинга |
actionOnCloseProcessing | (Bool) -> Void | нет | Действие на закрытие процессинга с возвратом результата |
AirbaPayView
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
navigateCoordinator | @ObservedObject AirbaPayCoordinator | да | Координатор навигации |
contentView | AnyView? | да | Контент страницы, на которой будет вызван sdk |
Контент страницы приложения обернуть в AirbaPayView
var body: some View {
AirbaPayView(
navigateCoordinator: navigateCoordinator,
contentView: contentView
)
}
Открыть новую страницу с содержимым swiftUi.
Ниже описан кратко вариант интеграции. Более подробно описано в статье https://sarunw.com/posts/swiftui-view-as-uiview-in-storyboard/
- Добавить
Container View
и удалить привязанный к нему дефолтныйViewController
- Добавить
UIHostingController
и привязатьContainer View
к нему черезEmbed
- Связать это с
ViewController
кодом, указанным ниже
@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("Продолжить") }
)
}
}
В случае наличия на странице системных элементов управления (к примеру, кнопки назад),
обязательно нужно скрыть их (в случае навигации в swiftUi через .navigationBarBackButtonHidden(true)
)
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()
}
}
)
}
}
-
Добавить параметры в initSdk
isApplePayNative: true
applePayMerchantId: "merchant.~"
-
Перейти в консоль ApplePay https://developer.apple.com/account/resources/identifiers/list
-
Добавьте в 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 -
Перейти во внутрь идентификатора приложения. Поставьте галочку в
Apple Pay Payment Processing
и кликните edit -
Выберите ~ Apple Pay Prod Service merchant.
.pf ~ Apple Pay Test Service merchant..spf и нажмите continue -
Нажмите Save
-
Зайдите в XCode в Targets -> Signing & Capabilities добавьте Apple Pay айди мерчантов поставьте галочки
buyBtnTapped
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
redirectFromStoryboardToSwiftUi | (() -> Void)? | нет | Замыкание перехода в сдк для UIKit |
backToStoryboard | (() -> Void)? | нет | Замыкание возврата в приложение для UIKit |
ApplePayManager
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
navigateCoordinator | @ObservedObject AirbaPayCoordinator | да | Координатор навигации |
- Добавить, как указано в примере:
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()
}
)
}
)
}
-
Добавить импорты во
ViewController
import SwiftUI import AirbaPay
-
Добавить
@ObservedObject var navigateCoordinator = AirbaPayCoordinator()
-
Дальше надо выполнить ряд действий для подключения вьюшки в UIKit. Ниже описан кратко вариант интеграции. Более подробно описано в статье https://sarunw.com/posts/swiftui-view-as-uiview-in-storyboard/
- Добавить
Container View
и удалить привязанный к нему дефолтныйViewController
- Добавить
UIHostingController
и привязатьContainer View
к нему черезEmbed
- Связать это с
ViewController
кодом, указанным ниже
@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
)
}
)
}
}
Для работы с ApplePay потребуется вьюшка ApplePayWebViewExternal
из AirbaPay
.
Визуально она не будет отображаться на экране, т.к. занимает всего 0.1. Вьюшку можно поместить вниз экрана.
Параметр | Тип | Обязательный | Описание |
---|---|---|---|
redirectFromStoryboardToSwiftUi | (() -> Void)? | нет | Замыкание перехода в сдк для UIKit |
backToStoryboard | (() -> Void)? | нет | Замыкание возврата в приложение для UIKit |
navigateCoordinator | @ObservedObject AirbaPayCoordinator | да | Координатор навигации |
isLoading | @escaping (Bool) -> Void | да | Замыкание для показа лоадинга или плейсхолдера |
applePayViewModel | @ObservedObject ApplePayViewModel | да | ViewModel для работы с эппл пэй из AirbaPay |
-
Выполнить в
onAppear
AirbaPaySdk.initSdk(~)
-
Добавить, как указано в примере:
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
)
}
)
}
- Добавить импорты во
ViewController
import SwiftUI
import AirbaPay
- Добавить
@ObservedObject var navigateCoordinator = AirbaPayCoordinator()
- Дальше надо выполнить ряд действий для подключения вьюшки в UIKit. Ниже описан кратко вариант интеграции. Более подробно описано в статье https://sarunw.com/posts/swiftui-view-as-uiview-in-storyboard/
- Добавить
Container View
и удалить привязанный к нему дефолтныйViewController
- Добавить
UIHostingController
и привязатьContainer View
к нему черезEmbed
- Связать это с
ViewController
кодом, указанным ниже
@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
)
}
}
}
}
- В 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
для перехода на страницы сдк.
- Создайте файл
AirbaPayHandler
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-baykanat",
password: "baykanat123!",
terminalId: "64216e7ccc4a48db060dd689",
failureCallback: "https://site.kz/failure-clb",
successCallback: "https://site.kz/success-clb",
autoCharge: 0,
enabledLogsForProd: true,
purchaseAmount: 5500.0,
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
}
}
}
- Создайте файл
AirbaPayViewController
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")
}
}
- Добавьте в
AppDelegate
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))
})