Mobile SDK Core
Това е по-скоро библиотека, отколкото SDK. Тя се използва за шифроване на данните на картата в seToken, който може безопасно да се предаде и съхрани в която и да е система (например на сървъра на продавача). Това е добро решение за продавачи, които искат максимална гъвкавост или не искат да се занимават с данните на картата на своите сървъри.
Начини на плащане, поддържани от този SDK:
| Начин на плащане | Поддръжка |
|---|---|
| Банкова карта | Да |
| Съхранени потребителски данни/карта | Да |
| Apple Pay | Не се изисква |
| Google Pay | Не се изисква |
Процес на плащане SDK Core
Web View за 3DS
На приведената по-долу диаграма е показан процесът на плащане SDK Core с пренасочване 3DS чрез Web View.
-
Клиентът създава поръчка
-
Мобилният сървър регистрира тази поръчка в платежния шлюз чрез register.do. Използвайте параметъра
returnUrlкато маркер за затваряне на Web View след пренасочването от ACS на Стъпка 14. -
Мобилният сървър получава в отговора уникален номер на поръчка
mdOrder. -
Клиентът попълва платежните данни в мобилното приложение.
-
Мобилното приложение извиква SDK за създаване на seToken (secure token). (Android: sdkCore.generateWithCard; iOS: CKCToken.generateWithCard).
Публичният ключ, който се изисква в съответния метод, трябва да се взема от online ресурса https://uat.dskbank.bg/payment/se/keys.do. Ако на този линк са достъпни няколко ключа, следва да се използва първият ключ. (Имайте предвид, че за тестовата и работната среда се използват различни ключове.)
-
Мобилното приложение изпраща seToken на мобилния сървър.
-
Мобилният сървър използва този seToken за извършване на плащане чрез paymentorder.do.
- Използвайте seToken вместо pan, cvc и дата на изтичане.
- Не забравяйте да посочите името на притежателя на картата в полето
TEXT. Ако не събирате името на притежателя на картата, просто изпратете стойносттаCARDHOLDER.
-
Мобилният сървър получава отговор без пренасочване към ACS. Това означава, че плащането е завършено и трябва да преминем към Стъпка 16.
-
Мобилният сървър получава отговор с пренасочване към ACS.
-
Мобилното приложение отваря Web View с данните за пренасочване към ACS.
-
Клиентът въвежда своята еднократна парола във формата на ACS.
-
ACS пренасочва клиента към платежния шлюз.
-
Платежният шлюз осъществява плащането.
-
Платежният шлюз пренасочва клиента към
returnUrl, който може да се използва като маркер за затваряне на Web View. -
Мобилното приложение затваря Web View.
-
Платежният шлюз изпраща известие за обратна връзка на сървъра на продавача, ако е настроено за продавача.
-
Мобилният сървър проверява окончателния статус на плащането чрез getOrderStatusExtended.do.
-
Мобилното приложение показва резултата от плащането на клиента.
IOS
iOS-интеграция
Интеграция SDKCore.framework
Можете да интегрирате SDKCore.framework, като го добавите ръчно.
SDKCore.framework
-
Изтеглете последната версия на фреймуорка тук.
-
Изберете файл
SDKCore.frameworkи го добавете в папката на проекта.

- Отворете страницата Targets -> General -> Frameworks, Libraries, and Embedded Content. За
SDKCore.frameworkв колона Embed заменетеDo not EmbedсEmbed & Sign.

След това импортирайте фреймуорка във файла ViewController.swift .
//ViewController.swift
...
import SDKCore
...Работа с API V1
Външни зависимости
За генериране на токен е необходимо да се зададе открит ключ.
let publicKey: String =
"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"Метод за генериране на токен
let sdkCore = SdkCore()
let cardParams = CardParams(
pan: "4111111111111111",
cvc: "123",
expiryMMYY: "12/28",
cardholder: "TEST CARDHOLDER",
mdOrder: "mdOrder",
pubKey: publicKey
)
let cardParamsConfig = SDKCoreConfig(
paymentMethodParams: .cardParams(params: cardParams)
)
let tokenResult = sdkCore.generateWithConfig(config: cardParamsConfig)
let bindignParams = BindingParams(
pubKey: publicKey,
bindingId: "das",
cvc: "123",
mdOrder: "mdOrder"
)
let bindingParamsConfig = SDKCoreConfig(
paymentMethodParams: .bindingParams(params: bindignParams)
)
let tokenResult = sdkCore.generateWithConfig(config: bindingParamsConfig)Модели
CardParams
| Име на свойство | Тип данни | Стойност по подразбиране | Незадължително | Описание |
|---|---|---|---|---|
| mdOrder | String | - | Не | Номер на поръчката |
| pan | String | - | Не | Номер на картата |
| cvc | String | - | Не | Таен код на картата |
| expiryMMYY | String | - | Не | Срок на валидност на картата |
| cardHolder | String | - | Да | Име и фамилия на притежателя на картата |
| pubKey | String | - | Не | Публичен ключ |
BindingParams
| Име на свойство | Тип данни | Стойност по подразбиране | Незадължително | Описание |
|---|---|---|---|---|
| mdOrder | String | - | Не | Номер на поръчката |
| bindingId | String | - | Не | Номер на запазените платежни данни за карта |
| cvc | String | - | Да | Таен код на картата |
| pubKey | String | - | Не | Публичен ключ |
Грешки при валидация на полетата
| ParamField | Грешка | Описание |
|---|---|---|
| UNKNOWN | - | Неизвестна грешка |
| PAN | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| invalid-format | Използват се недопустими символи. Достъпни са само цифри. | |
| CVC | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| EXPIRY | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| invalid-format | Форматът не съответства на шаблона MM/YY | |
| CARDHOLDER | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| invalid-format | Използват се недопустими символи. Достъпни са само букви и интервали. | |
| BINDING_ID | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| MD_ORDER | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| PUB_KEY | required | Посочено е празно поле |
Android
Android-интеграция
Свързване към Gradle проект чрез добавяне на .aar файлове на библиотеката
Необходимо е да добавите файла на библиотеката sdk_core-release.aar в папката libs, а след това да посочите зависимостта на добавената библиотека.
build.gradle.kts
allprojects {
repositories {
// ...
flatDir {
dirs("libs")
}
}
}
dependencies {
// dependency is mandatory to add
implementation(group = "", name = "sdk_core-release", ext = "aar")
}build.gradle
allprojects {
repositories {
// ...
flatDir {
dirs 'libs'
}
}
}
dependencies {
// dependency is mandatory to add
implementation(group: '', name: 'sdk_core-release', ext: 'aar')
}Конфигурация за Android
Логиране
Вътрешните процеси се логират с таг SDK-Core.
Можете също така да логирате собствените си процеси.
Логирането е достъпно чрез обекта Logger.
-
За добавяне на log- интерфейси е необходимо да се извика
Logger-методътaddLogInterface().Пример за логиране в LogCat:
...
Logger.addLogInterface(object : LogInterface {
override fun log(classMethod: Class<Any>, tag: String, message: String, exception: Exception?) {
Log.i(tag, "$classMethod: $message", exception)
}
})
...По подразбиране се използва тагът SDK-Core. Можете да зададете свой собствен, ако желаете.
-
За логиране на собствени събития е необходимо да се извика
Logger-методътlog().Пример:
...
Logger.log(this.javaClass, "MyTag", "My process...", null)
...Пример Kotlin_core (без графичен интерфейс)
Пример за формиране на криптограма
import net.payrdr.mobile.payment.sdk.core.SDKCore
import net.payrdr.mobile.payment.sdk.core.TokenResult
import net.payrdr.mobile.payment.sdk.core.model.BindingParams
import net.payrdr.mobile.payment.sdk.core.model.CardParams
import net.payrdr.mobile.payment.sdk.core.validation.BaseValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardCodeValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardExpiryValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardHolderValidator
import net.payrdr.mobile.payment.sdk.core.validation.CardNumberValidator
import net.payrdr.mobile.payment.sdk.core.validation.OrderNumberValidator
class MainActivity : AppCompatActivity() {
// initialization of validators for card information entry fields
private val cardNumberValidator by lazy { CardNumberValidator(this) }
private val cardExpiryValidator by lazy { CardExpiryValidator(this) }
private val cardCodeValidator by lazy { CardCodeValidator(this) }
private val cardHolderValidator by lazy { CardHolderValidator(this) }
private val orderNumberValidator by lazy { OrderNumberValidator(this) }
private val sdkCore by lazy { SDKCore(context = this) }
override fun onCreate(savedInstanceState: Bundle?) {
// инсталиране на валидатори на полетата за въвеждане на информация за карта
cardNumberInput.setupValidator(cardNumberValidator)
cardExpiryInput.setupValidator(cardExpiryValidator)
cardCodeInput.setupValidator(cardCodeValidator)
cardHolderInput.setupValidator(cardHolderValidator)
mdOrderInput.setupValidator(orderNumberValidator)
// създаване на обект и инициализация на полета за нова карта
val params = NewPaymentMethodCardParams(
pan = cardNumberInput.text.toString(),
cvc = cardCodeInput.text.toString(),
expiryMMYY = cardExpiryInput.text.toString(),
cardHolder = cardHolderInput.text.toString(),
pubKey = pubKeyInput.text.toString()
)
// извикване на метод за получаване на криптограма за нова карта
sdkCore.generateWithConfig(SDKCoreConfig(params))
// Създаване на обект и инициализация на полета за свързана карта
val params = NewPaymentMethodStoredCardParams(
storedPaymentId = "storedPaymentMethodId",
cvc = "123",
pubKey = pubKeyInput.text.toString()
)
// извикване на метод за получаване на криптограма за свързаната карта
sdkCore.generateWithConfig(SDKCoreConfig(params))
}
}Модели
NewPaymentMethodCardParams
| Име на свойството | Тип данни | Стойност по подразбиране | Незадължително | Описание |
|---|---|---|---|---|
| pan | String | - | Не | Номер на карта |
| cvc | String | - | Не | Таен код на карта |
| expiryMMYY | String | - | Не | Срок на валидност на карта |
| cardHolder | String | - | Не | Име и фамилия на притежателя на карта |
| pubKey | String | - | Не | Публичен ключ |
NewPaymentMethodStoredCardParams
| Име на свойството | Тип данни | Стойност по подразбиране | Незадължително | Описание |
|---|---|---|---|---|
| storedPaymentId | String | - | Не | Номер на съхранени платежни данни за карта |
| cvc | String | - | Не | Таен код на карта |
| pubKey | String | - | Не | Публичен ключ |
TokenResult
| Име на свойството | Тип данни | Стойност по подразбиране | Незадължително | Описание |
|---|---|---|---|---|
| token | String | - | Не | Token като низ |
| errors | Map<ParamField, String> | - | Не | Грешка при генериране на token |
Грешки при валидиране на полета
| ParamField | Грешка | Описание |
|---|---|---|
| PAN | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| invalid-format | Използват се недопустими символи. Достъпни са само цифри. | |
| CVC | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| EXPIRY | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| invalid-format | Форматът не съответства на шаблона MM/YY. | |
| CARDHOLDER | required | Посочено е празно поле |
| invalid | Некоректна стойност | |
| invalid-format | Използват се недопустими символи. Достъпни са само букви и интервали. | |
| PUB_KEY | required | Посочено е празно поле |
| STORED_PAYMENT_ID | requrired | Посочено е празно поле |
| invalid | Некоректна стойност |
Работа с API V1
Външни зависимости
За генериране на token е необходимо да се зададе публичен ключ.
val publicKey: String =
"-----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoIITqh9xlGx4tWA+aucb0V0YuFC9aXzJb0epdioSkq3qzNdRSZIxe/dHqcbMN2SyhzvN6MRVl3xyjGAV+lwk8poD4BRW3VwPUkT8xG/P/YLzi5N8lY6ILlfw6WCtRPK5bKGGnERcX5dqL60LhOPRDSYT5NHbbp/J2eFWyLigdU9Sq7jvz9ixOLh6xD7pgNgHtnOJ3Cw0Gqy03r3+m3+CBZwrzcp7ZFs41bit7/t1nIqgx78BCTPugap88Gs+8ZjdfDvuDM+/3EwwK0UVTj0SQOv0E5KcEHENL9QQg3ujmEi+zAavulPqXH5907q21lwQeemzkTJH4o2RCCVeYO+YrQIDAQAB-----END PUBLIC KEY-----"Метод за генериране на token
// TokenResult with CardParams
val cardParams: CardParams = CardParams(
mdOrder = "mdOrder",
pan = "4111111111111111",
cvc = "123",
expiryMMYY = "12/28",
cardHolder = "TEST CARDHOLDER",
pubKey = "publicKey"
)
val tokenResult = sdkCore.generationWithConfig(paymentCardParams = cardParams)
// TokenResult with BindingParams
val bindingParams: BindingParams = BindingParams(
mdOrder = "mdOrder",
bindingID = "das",
cvc = "123",
pubKey = "publicKey"
)
val tokenResult = sdkCore.generationWithConfig(paymentCardParams = bindingParams)Кросплатформени фреймуърци
Mobile SDK Core може да се използва не само в нативни приложения: извикванията на SDK се прехвърлят в нативния код чрез мост, който декларирате от страната на приложението.
React Native
За реализацията на интеграция на Mobile SDK Core в React Native приложение е необходимо да настроите мост — обвивка на Kotlin/Java или Swift/Objective-C, която ще приема извиквания от JavaScript и ще ги предава в нативния код на SDK.
Мостовете в React Native позволяват на вашия JS код да извиква методи на нативни библиотеки толкова просто, колкото обикновените асинхронни функции: вие декларирате нативен модул с методи, които връщат резултат чрез Promise, React Native автоматично свързва тези методи с JavaScript, и след това работите с тях в приложението без дълбоки познания за платформените API.
IOS
-
Интегрирайте SDKCore във вашия проект в съответствие с раздел iOS-интеграция.
-
Проверете, че за фреймуорка
SDKCore.xcframeworkв колоната Embed е избрано Embed & Sign. -
Създайте Swift модул
RadarSdkBridge.swiftсъс следното съдържание:import Foundation import React import SDKCore @objc(RadarSdk) class RadarSdkBridge: NSObject { private let sdkCore = SdkCore() @objc func generateNewCardToken( _ pan: String, cvc: String, expiryMMYY: String, cardHolder: String, mdOrder: String, pubKey: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock ) { do { let params = CardParams( pan: pan, cvc: cvc, expiryMMYY: expiryMMYY, cardholder: cardHolder, mdOrder: mdOrder, pubKey: pubKey ) let config = SDKCoreConfig(paymentMethodParams: .cardParams(params: params)) let result = try sdkCore.generateWithConfig(config: config) resolve(result.token) } catch { reject("TOKEN_ERROR", error.localizedDescription, error) } } @objc func generateStoredCardToken( _ storedPaymentId: String, cvc: String, pubKey: String, mdOrder: String, resolver resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock ) { do { let params = BindingParams( pubKey: pubKey, bindingId: storedPaymentId, cvc: cvc, mdOrder: mdOrder ) let config = SDKCoreConfig(paymentMethodParams: .bindingParams(params: params)) let result = try sdkCore.generateWithConfig(config: config) resolve(result.token) } catch { reject("TOKEN_ERROR", error.localizedDescription, error) } } @objc static func requiresMainQueueSetup() -> Bool { return false } } -
Реализирайте Objective-C мост в файла
RadarSdkBridge.m:#import <React/RCTBridgeModule.h> @interface RCT_EXTERN_MODULE(RadarSdk, NSObject) RCT_EXTERN_METHOD(generateNewCardToken: (NSString *)pan cvc:(NSString *)cvc expiryMMYY:(NSString *)expiryMMYY cardHolder:(NSString *)cardHolder mdOrder:(NSString *)mdOrder pubKey:(NSString *)pubKey resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject ) RCT_EXTERN_METHOD(generateStoredCardToken: (NSString *)storedPaymentId cvc:(NSString *)cvc pubKey:(NSString *)pubKey mdOrder:(NSString *)mdOrder resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject ) @end
Android
-
Изтеглете файловете
sdk_core-release.aarиsdk_logs-release.aarи ги копирайте в папкатаandroid/app/libs/според раздел Android-интеграция. -
Добавете плоския репозиторий и зависимостите във файла
android/app/build.gradle:android { // … останалата конфигурация на вашия проект … } repositories { flatDir { dirs 'libs' } } dependencies { // … други зависимости … implementation(name: 'sdk_core-release', ext: 'aar') implementation(name: 'sdk_logs-release', ext: 'aar') }
Реализация на Native Module за Kotlin
-
Създайте файла
RadarSdkModule.ktв директориятаandroid/app/src/main/java/.../radar/:package com.mobilesdkdemo.radar import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import net.payrdr.mobile.payment.sdk.core.SDKCore import net.payrdr.mobile.payment.sdk.core.model.SDKCoreConfig import net.payrdr.mobile.payment.sdk.core.model.CardParams import net.payrdr.mobile.payment.sdk.core.model.BindingParams class RadarSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { override fun getName(): String = "RadarSdk" private val sdkCore by lazy { SDKCore(context = reactApplicationContext) } @ReactMethod fun generateNewCardToken( pan: String, cvc: String, expiryMMYY: String, cardHolder: String, mdOrder: String, pubKey: String, promise: Promise ) { try { val params = CardParams( pan = pan, cvc = cvc, expiryMMYY = expiryMMYY, cardHolder = cardHolder, mdOrder = mdOrder, pubKey = pubKey ) val config = SDKCoreConfig(paymentCardParams = params) val result = sdkCore.generateWithConfig(config) promise.resolve(result.token) } catch (e: Exception) { promise.reject("TOKEN_ERROR", e) } } @ReactMethod fun generateStoredCardToken( storedPaymentId: String, cvc: String, pubKey: String, mdOrder: String, promise: Promise ) { try { val params = BindingParams( bindingID = storedPaymentId, mdOrder = mdOrder, cvc = cvc, pubKey = pubKey ) val config = SDKCoreConfig(paymentCardParams = params) val result = sdkCore.generateWithConfig(config) promise.resolve(result.token) } catch (e: Exception) { promise.reject("TOKEN_ERROR", e) } } } -
Създайте пакета
RadarSdkPackage.ktв същата директория:package com.mobilesdkdemo.radar import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ViewManager class RadarSdkPackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> = listOf(RadarSdkModule(reactContext)) override fun createViewManagers( reactContext: ReactApplicationContext ): List<ViewManager<*, *>> = emptyList() } -
Регистрирайте създадения пакет в
MainApplication.kt:package com.mobilesdkdemo import android.app.Application import com.facebook.react.PackageList import com.facebook.react.ReactApplication import com.facebook.react.ReactNativeHost import com.facebook.react.ReactHost import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.soloader.SoLoader import com.mobilesdkdemo.radar.RadarSdkPackage class MainApplication : Application(), ReactApplication { override val reactNativeHost: ReactNativeHost = object : DefaultReactNativeHost(this) { override fun getPackages(): List<ReactPackage> = PackageList(this).packages.apply { add(RadarSdkPackage()) // Регистрираме пакета } override fun getJSMainModuleName(): String = "index" override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED } override val reactHost: ReactHost get() = getReactNativeHost(applicationContext, reactNativeHost) override fun onCreate() { super.onCreate() SoLoader.init(this, false) if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { load() } } }
Използване
Използвайте методите от JavaScript/TypeScript по следния начин:
import { NativeModules } from 'react-native';
const { RadarSdk } = NativeModules;
// Генериране на токен за нова карта
const token = await RadarSdk.generateNewCardToken(
'4111111111111111', // PAN
'123', // CVC
'12/25', // Expiry MM/YY
'CARDHOLDER NAME', // Име на притежателя на картата
'mdOrder', // Номер, получен при регистрация на поръчката
'-----BEGIN PUBLIC KEY-----...' // Публичен ключ от /payment/se/keys.do
);
// Генериране на токен за свързана карта
const bindToken = await RadarSdk.generateStoredCardToken(
'bindingId', // ID на запазената карта
'123', // CVC
'-----BEGIN PUBLIC KEY-----…', // Публичен ключ от /payment/se/keys.do
'mdOrder' // Номер, получен при регистрация на поръчката
);Демо приложение
Пример за интеграция на Mobile Sdk Core в приложение на React Native може да се види на GitHub.
Flutter
За реализиране на интеграцията на Mobile SDK Core в Flutter приложение е необходимо да настроите platform channel — канал, чрез който Dart кодът извиква native методи на SDK на Android и iOS.
Platform channel свързва Dart и native кода по име на канала: вие декларирате MethodChannel с едно и също име на двете страни, извиквате метод от Dart и получавате резултата чрез Future. Името на канала е единственото, което свързва страните, затова при несъвпадение извикването ще завърши с изключение MissingPluginException в runtime, а не с грешка при компилация.
Аргументите се предават като Map<String, dynamic> и се разбират на native страната по имена на ключовете. Чрез канала преминават само стойности, разбираеми от стандартния кодек — примитиви, списъци и речници; обектите на SDK се създават на native страната и не се предават чрез канала.
iOS
-
Интегрирайте SDKCore във вашия проект в съответствие с раздел iOS-интеграция.
-
Проверете, че за framework
SDKCore.xcframeworkв колоната Embed е избрано Embed & Sign. Framework-ът вътре вxcframeworkе динамична библиотека: ако само се свърже, но не се вгради, проектът ще се компилира, а приложението ще се срине при стартиране. -
Създайте файл
RadarSdkBridge.swiftв targetRunner:import Flutter import Foundation import SDKCore final class RadarSdkBridge: NSObject { static let channelName = "radar_sdk" private let channel: FlutterMethodChannel private let sdkCore = SdkCore() init(messenger: FlutterBinaryMessenger) { channel = FlutterMethodChannel(name: RadarSdkBridge.channelName, binaryMessenger: messenger) super.init() channel.setMethodCallHandler { [weak self] call, result in self?.handle(call, result: result) } } private func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "generateNewCardToken": generateNewCardToken(call, result: result) case "generateStoredCardToken": generateStoredCardToken(call, result: result) default: result(FlutterMethodNotImplemented) } } private func generateNewCardToken(_ call: FlutterMethodCall, result: @escaping FlutterResult) { guard let args = call.arguments as? [String: Any], let pan = args["pan"] as? String, let cvc = args["cvc"] as? String, let expiryMMYY = args["expiryMMYY"] as? String, let cardHolder = args["cardHolder"] as? String, let mdOrder = args["mdOrder"] as? String, let pubKey = args["pubKey"] as? String else { result(FlutterError(code: "TOKEN_ERROR", message: "Invalid arguments", details: nil)) return } do { let params = CardParams( pan: pan, cvc: cvc, expiryMMYY: expiryMMYY, cardholder: cardHolder, mdOrder: mdOrder, pubKey: pubKey ) let config = SDKCoreConfig(paymentMethodParams: .cardParams(params: params)) let tokenResult = try sdkCore.generateWithConfig(config: config) result(tokenResult.token) } catch { result(FlutterError(code: "TOKEN_ERROR", message: error.localizedDescription, details: nil)) } } private func generateStoredCardToken(_ call: FlutterMethodCall, result: @escaping FlutterResult) { guard let args = call.arguments as? [String: Any], let storedPaymentId = args["storedPaymentId"] as? String, let cvc = args["cvc"] as? String, let pubKey = args["pubKey"] as? String, let mdOrder = args["mdOrder"] as? String else { result(FlutterError(code: "TOKEN_ERROR", message: "Invalid arguments", details: nil)) return } do { let params = BindingParams( pubKey: pubKey, bindingId: storedPaymentId, cvc: cvc, mdOrder: mdOrder ) let config = SDKCoreConfig(paymentMethodParams: .bindingParams(params: params)) let tokenResult = try sdkCore.generateWithConfig(config: config) result(tokenResult.token) } catch { result(FlutterError(code: "TOKEN_ERROR", message: error.localizedDescription, details: nil)) } } } -
Регистрирайте моста в
AppDelegate.swift:import Flutter import UIKit @main @objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { // Мостът трябва да се пази в свойство: обект, създаден в локална // променлива, се освобождава и мълчаливо престава да отговаря на извиквания от Dart. private var radarSdkBridge: RadarSdkBridge? func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) if let messenger = engineBridge.pluginRegistry.registrar(forPlugin: "RadarSdkBridge")?.messenger() { radarSdkBridge = RadarSdkBridge(messenger: messenger) } } }
Android
-
Свалете файловете
sdk_core-release.aarиsdk_logs-release.aarи ги копирайте в папкатаandroid/app/libs/според раздел Android-интеграция. -
Добавете зависимостите в файла
android/app/build.gradle.kts:android { // … останалата конфигурация на вашия проект … } dependencies { // … други зависимости … implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar")))) } -
Създайте файл
RadarSdkBridge.ktв директориятаandroid/app/src/main/kotlin/.../:package com.mobilesdkdemo import android.content.Context import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import net.payrdr.mobile.payment.sdk.core.SDKCore import net.payrdr.mobile.payment.sdk.core.model.BindingParams import net.payrdr.mobile.payment.sdk.core.model.CardParams import net.payrdr.mobile.payment.sdk.core.model.SDKCoreConfig private const val CHANNEL_NAME = "radar_sdk" class RadarSdkBridge(private val context: Context) : MethodChannel.MethodCallHandler { private val sdkCore by lazy { SDKCore(context = context) } fun register(messenger: BinaryMessenger) { MethodChannel(messenger, CHANNEL_NAME).setMethodCallHandler(this) } override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { when (call.method) { "generateNewCardToken" -> generateNewCardToken(call, result) "generateStoredCardToken" -> generateStoredCardToken(call, result) else -> result.notImplemented() } } private fun generateNewCardToken(call: MethodCall, result: MethodChannel.Result) { try { val params = CardParams( pan = call.argument<String>("pan")!!, cvc = call.argument<String>("cvc")!!, expiryMMYY = call.argument<String>("expiryMMYY")!!, cardHolder = call.argument<String>("cardHolder")!!, mdOrder = call.argument<String>("mdOrder")!!, pubKey = call.argument<String>("pubKey")!! ) val config = SDKCoreConfig(paymentCardParams = params) val token = sdkCore.generateWithConfig(config).token result.success(token) } catch (e: Exception) { result.error("TOKEN_ERROR", e.message, null) } } private fun generateStoredCardToken(call: MethodCall, result: MethodChannel.Result) { try { val params = BindingParams( bindingID = call.argument<String>("storedPaymentId")!!, mdOrder = call.argument<String>("mdOrder")!!, cvc = call.argument<String>("cvc")!!, pubKey = call.argument<String>("pubKey")!! ) val config = SDKCoreConfig(paymentCardParams = params) val token = sdkCore.generateWithConfig(config).token result.success(token) } catch (e: Exception) { result.error("TOKEN_ERROR", e.message, null) } } } -
Регистрирайте моста в
MainActivity.kt:package com.mobilesdkdemo import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine class MainActivity : FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) RadarSdkBridge(applicationContext).register(flutterEngine.dartExecutor.binaryMessenger) } }
Използване
-
Създайте обвивка над канала в
lib/radar_sdk.dart. Името на канала и имената на ключовете в аргументите трябва да съвпадат с нативната страна:import 'package:flutter/services.dart'; class RadarSdk { const RadarSdk._(); static const MethodChannel _channel = MethodChannel('radar_sdk'); static Future<String?> generateNewCardToken({ required String pan, required String cvc, required String expiryMMYY, required String cardHolder, required String mdOrder, required String pubKey, }) { return _channel.invokeMethod<String>('generateNewCardToken', { 'pan': pan, 'cvc': cvc, 'expiryMMYY': expiryMMYY, 'cardHolder': cardHolder, 'mdOrder': mdOrder, 'pubKey': pubKey, }); } static Future<String?> generateStoredCardToken({ required String storedPaymentId, required String cvc, required String pubKey, required String mdOrder, }) { return _channel.invokeMethod<String>('generateStoredCardToken', { 'storedPaymentId': storedPaymentId, 'cvc': cvc, 'pubKey': pubKey, 'mdOrder': mdOrder, }); } } -
Използвайте методите от Dart по следния начин:
// Генериране на токен за нова карта final token = await RadarSdk.generateNewCardToken( pan: '4111111111111111', // PAN cvc: '123', // CVC expiryMMYY: '12/25', // Срок на валидност MM/YY cardHolder: 'CARDHOLDER NAME', // Име на притежателя на картата mdOrder: 'mdOrder', // Номер, получен при регистрация на поръчката pubKey: '-----BEGIN PUBLIC KEY-----...', // Публичен ключ от /payment/se/keys.do ); // Генериране на токен за свързана карта final bindToken = await RadarSdk.generateStoredCardToken( storedPaymentId: 'bindingId', // ID на съхранената карта cvc: '123', // CVC pubKey: '-----BEGIN PUBLIC KEY-----…', // Публичен ключ от /payment/se/keys.do mdOrder: 'mdOrder', // Номер, получен при регистрация на поръчката );
Грешките от нативната страна идват в Dart като PlatformException: при неуспешно генериране на токен мостът отговаря с код TOKEN_ERROR, а в полето message се предава текстът на грешката от SDK.
try {
final token = await RadarSdk.generateNewCardToken(/* … */);
} on PlatformException catch (e) {
// e.code == 'TOKEN_ERROR', e.message — текст на грешката от SDK
}Демо приложение
Пример за интеграция на Mobile SDK Core в приложение на Flutter може да се види в GitHub.
Mobile SDK Source
iOS
Изисквания: iOS 10.0 или по-висока версия
Android
Изисквания: Android 5.0 или по-висока версия