Kartové údaje
Kartové platby prebiehajú prostredníctvom zabezpečených vstupných komponentov — Secure Fields. Tieto komponenty zaisťujú bezpečné zadávanie, validáciu a ochranu kartových údajov. Hostiteľská aplikácia nikdy nemá prístup k citlivým údajom v nechránenej podobe.
Secure Fields
Knižnica poskytuje štyri komponenty na zadávanie údajov v platobnom formulári:
SecurePanField
Pole na zadanie čísla karty (PAN — Primary Account Number).
- Prijíma iba číslice
- Automaticky detekuje kartovú sieť (Visa, Mastercard)
- Formátuje číslo karty s mezerami dle kartové siete (napr.
4111 1111 1111 1111) - Omezuje délku vstupu podle detekované kartové siete
- Validuje číslo karty pomocou Luhnovho algoritmu
- Podporuje systémový autofill
- Sprístupňuje vlastnosť
last4— posledné 4 číslice karty (bezpečné na zobrazenie v UI)
import cz.comgate.sdk.compose.*
val panState = rememberSecurePanFieldState()
SecurePanField(
state = panState,
modifier = Modifier.fillMaxWidth()
)
SecureExpiryField
Pole na zadanie dátumu expirácie karty.
- Prijíma iba číslice
- Automaticky formátuje vstup v tvare MM/YY
- Validuje mesiac (1–12) a kontroluje, či karta nie je expirovaná
- Podporuje autofill vo formátoch MMYY aj MMYYYY
val expiryState = rememberSecureExpiryFieldState()
SecureExpiryField(
state = expiryState,
modifier = Modifier.fillMaxWidth()
)
SecureCvvField
Pole na zadanie bezpečnostného kódu karty (CVV/CVC).
- Prijíma iba číslice
- Dĺžka sa automaticky prispôsobuje detekovanej kartovej sieti
- Validuje minimálnu požadovanú dĺžku
val cvvState = rememberSecureCvvFieldState()
SecureCvvField(
state = cvvState,
modifier = Modifier.fillMaxWidth()
)
SecureFullNameField
Pole na zadanie mena a priezviska platiteľa.
- Prijíma textový vstup (vrátane mezer)
- Podporuje systémový autofill mena
- Je validné pri neprázdnej hodnote
- Po pripojení k
ComgateSecureSessionsa jeho hodnota automaticky použije akofullName
import androidx.compose.runtime.DisposableEffect
import cz.comgate.sdk.compose.*
val fullNameState = rememberSecureFullNameFieldState()
DisposableEffect(session) {
fullNameState.attachTo(session)
onDispose { fullNameState.detachFrom(session) }
}
SecureFullNameField(
state = fullNameState,
modifier = Modifier.fillMaxWidth()
)
PaymentParams.fullName má vždy prednosť pred hodnotou zo SecureFullNameField — ak je fullName v PaymentParams vyplnený, pole SecureFullNameField nie je vyžadované. Ak je fullName prázdny, použije sa hodnota z pripojeného poľa. Ak sú prázdne obidve, platba zlyhá s chybou MISSING_CARDHOLDER_NAME.
Společné vlastnosťi
Všechny Secure Fields (SecurePanField, SecureExpiryField, SecureCvvField, SecureFullNameField) sdílejí tieto vlastnosťi a metody:
| Vlastnosť / Metóda | Typ | Popis |
|---|---|---|
isFieldValid | Boolean | Aktuálny stav validácie poľa (read-only). |
onValidationChanged | (Boolean) -> Unit | Callback volaný pri zmene validačného stavu. |
showLabel | Boolean | Zobrazenie labelu nad poľom. Predvolené true. Nastavte false na skrytie labelu. |
labelText | String? | Vlastný text labelu. Ak je null, použije sa predvolený preložený label podľa session.translation. |
setHint(hint) | String | Nastaví placeholder text. |
setEnabled(enabled) | Boolean | Povolí/zakáže pole. |
clear() | — | Vymaže obsah poľa a resetuje validáciu. |
Labely vstupných polí
Každé pole má label nad vstupom (SecurePanField, SecureExpiryField, SecureCvvField, SecureFullNameField).
- Predvolený text labelu se bere z
session.translation - Label možno skryť cez
showLabel = false - Predvolený preklad možno prepísať cez
labelText
SecurePanField(
state = panState,
modifier = Modifier.fillMaxWidth(),
update = {
showLabel = true
labelText = "Číslo platební karty"
}
)
SecureCardDataCollector
SecureCardDataCollector prepája tri samostatné Secure Fields a sleduje ich celkový validačný stav. Je vyžadovaný na spracovanie platby.
import cz.comgate.sdk.compose.*
// Stav polí — raw kartové údaje zostávajú vnútri SDK
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
// Kolektor propojující pole a sledující celkovou validaci
val collector = rememberSecureDataCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
onValidationChanged = { isValid ->
// isValid je true, keď sú všetky tri polia validné
}
)
Odovzdávanie focusu medzi poľami
rememberSecureDataCollector v predvolenom stave automaticky odovzdáva focus medzi poľami v poradí:
PAN -> Expirácia -> CVV
K presunu dôjde vo chvíli, keď je aktuálne pole kompletne vyplnené a validné.
val collector = rememberSecureDataCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
autoAdvanceFocus = true // vychozi hodnota
)
Ak chcete focus riadiť sami, vypnite automatiku:
val collector = rememberSecureDataCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
autoAdvanceFocus = false
)
Pri implementácii pomocou Android View môžete odovzdávanie focusu zapojiť ručne cez nextSecureField:
panField.nextSecureField = expiryField
expiryField.nextSecureField = cvvField
| Vlastnosť / Metóda | Typ | Popis |
|---|---|---|
isValid | Boolean | true ak sú všetky tri polia validné. |
onValidationChanged | (Boolean) -> Unit | Callback volaný pri zmene validačného stavu ktoréhokoľvek poľa. |
SecurePayButton
SecurePayButton je predpripravené platobné tlačidlo, ktoré sa automaticky integruje so session a kolektorom:
- Automaticky sa aktivuje/deaktivuje podľa validačného stavu kartových polí
- Tlačidlo zostane deaktivované, kým nie je session úspešne inicializovaná
- Po kliknutí zahájí spracovania platby prostredníctvom
ComgateSecureSession - Počas spracovania zobrazuje shimmer sweep animáciu cez tlačidlo (animáciu možno vypnúť)
- Vracia výsledok platby cez callback
Nastavenie tlačidla
Composable SecurePayButton prijíma parametre session, kolektora, callbacku a providera platobných parametrov:
import cz.comgate.sdk.compose.*
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result ->
// Spracovanie výsledku platby
},
paymentParamsProvider = {
PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Názov platby",
refId = "ref-123",
fullName = "Jan Novák",
country = "CZ", // voliteľné
expirationTime = "1h", // voliteľné
billingAddrCity = "Hradec Králové", // voliteľné
billingAddrStreet = "Jiráskova 115", // voliteľné
billingAddrPostalCode = "50304", // voliteľné
billingAddrCountry = "CZ" // voliteľné
)
},
modifier = Modifier.fillMaxWidth()
)
Parameter paymentParamsProvider je lambda, ktorá je zavolaná v okamihu kliknutia na tlačidlo. Vďaka tomu možno dynamicky čítať aktuálne hodnoty z UI (napr. sumu z textového poľa).
PaymentParams
| Parameter | Typ | Povinný | Popis |
|---|---|---|---|
email | String | Áno | E-mailová adresa platiteľa. |
price | Int | Áno | Suma platby v halieroch/centoch (napr. 10000 = 100,00 CZK). |
curr | String | Áno | Kód meny — ISO 4217 (napr. "CZK", "EUR"). Viď PaymentParams.supportedCurrencies pre úplný zoznam. |
label | String | Áno | Krátky popis produktu (1–16 znakov). |
refId | String | Ano | Variabilní symbol alebo číslo objednávky (vaše interní ID). |
fullName | String | Podmienene | Meno a priezvisko platiteľa. Ak je neprázdny, má prednosť pred hodnotou zo SecureFullNameField. Ak je prázdny, použije sa hodnota z pripojeného SecureFullNameField (vtedy povinného). Ak sú prázdne obidve, platba zlyhá s chybou MISSING_CARDHOLDER_NAME. |
country | String | Nie | Kód krajiny podľa ISO 3166-1 alpha-2 (napr. "CZ", "SK"). Predvolené: "CZ". Akákoľvek hodnota mimo zoznamu je pred odoslaním normalizovaná na "ALL". Hodnota sa odovzdáva tiež do platobného dialógu Google Pay. Viď PaymentParams.supportedCountries pre úplný zoznam. |
account | String? | Nie | Identifikátor bankového účtu klienta v systéme Comgate. |
name | String? | Nie | Identifikátor produktu (zobrazí sa v dennom CSV ako „Produkt"). |
preauth | Boolean? | Nie | Označí platbu ako predautorizáciu — rezervuje prostriedky na karte bez okamžitého stiahnutia. true — predautorizácia, null — predvolené správanie. Nemožno kombinovať s initRecurring = true. |
initRecurring | Boolean? | Nie | Označí platbu ako prvú v sérii opakovaných platieb. true — iniciačná platba. Nemožno kombinovať s preauth = true. |
expirationTime | String? | Ne | Doba expirace platby (napr. "30m", "3h", "5d"). Rozsah: 30 minut — 7 dní. |
dynamicExpiration | Boolean? | Nie | Dynamická expirácia platby (true na zapnutie). |
billingAddrCity | String? | Nie | Fakturačná adresa — mesto. |
billingAddrStreet | String? | Nie | Fakturačná adresa — ulica. |
billingAddrPostalCode | String? | Nie | Fakturačná adresa — PSČ. |
billingAddrCountry | String? | Nie | Fakturačná adresa — kód krajiny (ISO 3166-1 alpha-2). |
delivery | String? | Nie | Spôsob doručenia ("HOME_DELIVERY", "PICKUP", "ELECTRONIC_DELIVERY"). |
homeDeliveryCity | String? | Nie | Doručovacia adresa — mesto (len pri delivery = "HOME_DELIVERY"). |
homeDeliveryStreet | String? | Ne | Doručovací adresa — ulice (jen pri delivery = "HOME_DELIVERY"). |
homeDeliveryPostalCode | String? | Ne | Doručovací adresa — PSČ (jen pri delivery = "HOME_DELIVERY"). |
homeDeliveryCountry | String? | Nie | Doručovacia adresa — kód krajiny (len pri delivery = "HOME_DELIVERY"). |
category | String? | Nie | Kategória produktu ("PHYSICAL_GOODS_ONLY", "OTHER"). |
require3ds | Boolean? | Nie | Iba v dev režime (devMode = true). Vynucuje typ 3DS priebehu na testovacom serveri. true — vynúti priebeh s challenge, false — vynúti frictionless priebeh (bez challenge), null — server rozhodne sám. V produkcii ignorované. |
errorReason | ErrorReason? | Nie | Iba v dev režime (devMode = true). Simuluje konkrétny dôvod zamietnutia platby. |
Podporované meny a krajiny
Podporované meny (PaymentParams.supportedCurrencies)
PaymentParams.supportedCurrencies vracía zoznam ISO 4217 kódov mien prijateľných platebná bránou Comgate. Tento zoznam možno využiť napríklad na naplnenie výberu meny v UI.
BGN, CHF, CZK, DKK, EUR, GBP, HUF, NOK, PLN, RON, SEK, USD
Podporované krajiny (PaymentParams.supportedCountries)
PaymentParams.supportedCountries vracía zoznam ISO 3166-1 alpha-2 kódov krajín prijateľných pre parameter country. Hodnota "ALL" reprezentuje žiadne obmedzenie na konkrétnu krajinu. Akákoľvek iná hodnota mimo tohto zoznamu je serverom normalizovaná na "ALL".
ALL, AT, BE, CY, CZ, DE, EE, EL, ES, FI, FR, GB, HR, HU, IE, IT, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK, US
Príklad použitia pre naplnenie výberu meny a krajiny
// Dostupné meny pre výber v UI
val currencies = PaymentParams.supportedCurrencies // ["BGN", "CHF", "CZK", ...]
// Dostupné krajiny pre výber v UI
val countries = PaymentParams.supportedCountries // ["ALL", "AT", "BE", "CY", "CZ", ...]
PaymentParams(
email = "zakaznik@example.com",
price = 10000,
curr = selectedCurrency, // hodnota z výberu
country = selectedCountry, // hodnota z výberu
label = "Objednávka",
refId = "order-123",
fullName = "Ján Novák"
)
Opakované platby a predautorizácia
initRecurring
Parameter initRecurring = true označí platbu ako prvú (iniciačnú) transakciu v sérii opakovaných platieb. Banka tým dostane signál, že v budúcnosti budú prebiehať ďalšie automatické platby (napr. predplatné, pravidelné poplatky).
PaymentParams(
email = "zakaznik@example.com",
price = 9900,
curr = "CZK",
label = "Předplatné — první platba",
refId = "sub-001",
fullName = "Jan Novák",
initRecurring = true // Tato platba zahájí sérii opakovaných plateb
)
Parameter initRecurring nemožno kombinovať s preauth = true.
preauth
Parameter preauth = true označí platbu ako predautorizáciu — banka dočasne rezervuje požadovanú sumu na karte platiteľa, ale prostriedky nie sú ihneď stiahnuté. K zachyteniu (stiahnutiu) dochádza až pri potvrdení transakcie na strane backendu.
Predautorizácia sa typicky využíva v situáciách, kde konečná výška platby nie je v čase autorizácie ešte jasná (napr. požičovne, hotely, tankovanie).
PaymentParams(
email = "zakaznik@example.com",
price = 50000,
curr = "CZK",
label = "Rezervace vozidla",
refId = "reservation-42",
fullName = "Jan Novák",
preauth = true // Rezervace prostředků bez okamžitého stržení
)
Parameter preauth nemožno kombinovať s initRecurring = true.
Stylovaní tlačidla
Voliteľný update blok umožňuje programovo štylizovať tlačidlo pri každej rekompozícii. Dostupné metódy sú popísané v sekcii Štylizácia komponentov.
import cz.comgate.sdk.compose.*
// Stav polí a kolektoru
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
val collector = rememberSecureDataCollector(panState, expiryState, cvvState)
// Platobné tlačidlo
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result -> handleResult(result) },
paymentParamsProvider = {
PaymentParams(
price = 10000, curr = "CZK",
label = "Objednávka", refId = "ref-1", fullName = "Jan Novák"
)
},
modifier = Modifier.fillMaxWidth(),
update = {
// Voliteľná programová štylizácia — viď sekcia Štylizácia
setText("Zaplatit")
setButtonBackgroundColor(Color.parseColor("#1E88E5"))
setButtonTextColor(Color.WHITE)
setButtonCornerRadius(12f * resources.displayMetrics.density)
setDisabledBackgroundColor(Color.parseColor("#CFD8DC"))
setDisabledTextColor(Color.parseColor("#78909C"))
setLoadingAnimationEnabled(true)
}
)
Vlastné tlačidlo a priame volanie processPayment
Ak vám predpripravené SecurePayButton nevyhovuje (napr. chcete vlastný dizajn, animácie alebo zložitejšiu logiku), môžete platbu spustiť priamo volaním metódy session.processPayment() na inštancii ComgateSecureSession.
Metóda processPayment šifruje kartové údaje, odosiela ich na platobnú bránu a v prípade potreby automaticky vykoná 3D Secure autentizáciu. Citlivé údaje nikdy neopustia knižnicu v nechránenej podobe.
Signatúra metódy
suspend fun processPayment(
activity: Activity,
collector: SecureCardDataCollector,
params: PaymentParams
): PaymentResult
| Parameter | Typ | Popis |
|---|---|---|
activity | Activity | Aktuálna aktivita — nutná na zobrazenie 3DS challenge UI. |
collector | SecureCardDataCollector | Kolektor prepájajúci Secure Fields (PAN, expirácia, CVV). |
params | PaymentParams | Parametre platby (cena, mena, popis, refId, meno platiteľa a i.). |
Príklad implementácie
class PaymentActivity : AppCompatActivity() {
private lateinit var session: ComgateSecureSession
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Inicializace session
session = ComgateSecureSession(
checkoutId = "váš-checkout-id",
context = applicationContext,
threeDSConfig = ThreeDSConfig(),
lifecycleOwner = this,
onInitialized = { result ->
result.onFailure { e ->
Toast.makeText(this, "Chyba inicializace: ${e.message}", Toast.LENGTH_LONG).show()
}
}
)
setContent {
MaterialTheme {
Surface(modifier = Modifier.fillMaxSize()) {
CustomPaymentScreen(session)
}
}
}
}
}
@Composable
private fun CustomPaymentScreen(session: ComgateSecureSession) {
val activity = LocalContext.current as Activity
var isProcessing by remember { mutableStateOf(false) }
var isFormValid by remember { mutableStateOf(false) }
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
val statusState = rememberPaymentStatusState()
val collector = rememberSecureDataCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
onValidationChanged = { isValid ->
isFormValid = isValid
}
)
val scope = rememberCoroutineScope()
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
SecurePanField(state = panState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
SecureExpiryField(state = expiryState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
SecureCvvField(state = cvvState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(16.dp))
// Vlastné tlačidlo — priame volanie processPayment
Button(
onClick = {
if (!isProcessing) {
isProcessing = true
scope.launch {
val result = session.processPayment(
activity = activity,
collector = collector,
params = PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Objednávka #123",
refId = "order-123",
fullName = "Jan Novák"
)
)
isProcessing = false
statusState.showStatus(result)
when (result) {
is PaymentResult.Paid -> { /* Platba úspěšná */ }
is PaymentResult.Authorized -> { /* Platba autorizovaná (predautorizácia) */ }
is PaymentResult.Pending -> { /* Platba se zpracovává */ }
is PaymentResult.Cancelled -> { /* Platba zrušená / zamietnutá */ }
is PaymentResult.Failed -> { /* Chyba knižnice */ }
}
}
}
},
enabled = isFormValid && !isProcessing,
modifier = Modifier.fillMaxWidth()
) {
Text(if (isProcessing) "Zpracování..." else "Zaplatit")
}
SecurePaymentStatusView(
state = statusState,
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
)
}
}
Pred volaním processPayment sa uistite, že:
- Session je úspešne inicializovaná (callback
onInitializedvrátilResult.success). - Kartové údaje sú validné (
collector.isValid == true).
Ak tieto podmienky nie sú splnené, metóda okamžite vráti PaymentResult.Cancelled.
Spôsoby implementácie
Knižnica podporuje implementáciu pomocou troch samostatných komponentov (SecurePanField, SecureExpiryField, SecureCvvField) prepojených cez SecureCardDataCollector.
Samostatné polia
Každé pole je umiestnené nezávisle v Compose layoute. Tento prístup poskytuje plnú kontrolu nad rozložením a štylizáciou.
class PaymentActivity : AppCompatActivity() {
private lateinit var session: ComgateSecureSession
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
session = ComgateSecureSession(/* ... */)
setContent {
MaterialTheme {
Surface(modifier = Modifier.fillMaxSize()) {
PaymentScreen(session)
}
}
}
}
}
@Composable
private fun PaymentScreen(session: ComgateSecureSession) {
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
val statusState = rememberPaymentStatusState()
val collector = rememberSecureDataCollector(panState, expiryState, cvvState)
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
SecurePanField(state = panState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
SecureExpiryField(state = expiryState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
SecureCvvField(state = cvvState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(16.dp))
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result ->
when (result) {
is PaymentResult.Paid -> statusState.showStatus(result)
is PaymentResult.Authorized -> statusState.showStatus(result)
is PaymentResult.Pending -> statusState.showStatus(result)
is PaymentResult.Cancelled -> statusState.showStatus(result)
is PaymentResult.Failed -> statusState.showStatus(result)
}
},
paymentParamsProvider = {
PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Testovací platba",
refId = "ref-123",
fullName = "Jan Novák",
country = "CZ", // voliteľné
expirationTime = "1h" // voliteľné
)
},
modifier = Modifier.fillMaxWidth()
)
SecurePaymentStatusView(
state = statusState,
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
)
}
}
3D Secure
Knižnica poskytuje kompletní podporu 3D Secure autentifikácie. Ak je 3DS nakonfigurováno, knižnica automaticky:
- Pripraví autentizačné parametre pri spracovaní platby
- Vyhodnotí odpoveď servera (frictionless / challenge)
- V prípade potreby zobrazí challenge obrazovku
- Vrátí výsledek autentifikácie prostredníctvom
PaymentResult
Konfigurácia
3DS sa konfiguruje prostredníctvom triedy ThreeDSConfig, ktorá sa odovzdáva do konštruktora ComgateSecureSession:
val threeDSConfig = ThreeDSConfig(
uiCustomization = threeDSUi, // Přizpůsobení vzhledu (volitelné)
challengeTimeoutMinutes = 5, // Timeout pro challenge (predvolené: 5)
defaultMessageVersion = "2.2.0", // Verze 3DS protokolu (predvolené: "2.2.0")
challengeWindowCornerRadiusDp = 16 // Zaoblení rohů challenge okna (volitelné)
)
val session = ComgateSecureSession(
checkoutId = "váš-checkout-id",
context = applicationContext,
threeDSConfig = threeDSConfig,
lifecycleOwner = this
)
Parameter lifecycleOwner riadi, kedy session automaticky uvoľní prostriedky. Vo vyššie uvedených príkladoch sa odovzdáva this (aktivita).
Ak session vytvárate vnútri Fragmentu, odovzdajte viewLifecycleOwner (dostupný od onViewCreated):
- Activity:
lifecycleOwner = this - Fragment:
lifecycleOwner = viewLifecycleOwner(niethis— Fragment prežíva opätovné vytvorenie view a spôsobilo by memory leak)
Parametre ThreeDSConfig
| Parameter | Typ | Predvolené | Popis |
|---|---|---|---|
uiCustomization | ThreeDSUiCustomization? | null | Prispôsobenie vzhľadu challenge obrazovky. Ak je null, použijú sa predvolené štýly. |
defaultMessageVersion | String | "2.2.0" | Verzia 3DS protokolu. |
challengeTimeoutMinutes | Int | 5 | Maximálny čas čakania na dokončenie challenge v minútach (1–30). |
challengeWindowCornerRadiusDp | Int? | null | Zaoblenie rohov challenge okna v dp. Ak je null, použije sa predvolená hodnota z motívu. |
Prispôsobenie vzhľadu challenge obrazovky
Trieda ThreeDSUiCustomization umožňuje detailné prispôsobenie vzhľadu 3DS challenge obrazovky:
val threeDSUi = ThreeDSUiCustomization(
buttons = mapOf(
ThreeDSButtonType.SUBMIT to ThreeDSButtonStyle(
backgroundColor = "#4287f5",
cornerRadius = 48,
textColor = "#FFFFFF",
textFontSize = 16
),
ThreeDSButtonType.CONTINUE to ThreeDSButtonStyle(
backgroundColor = "#4287f5",
cornerRadius = 48,
textColor = "#FFFFFF",
textFontSize = 16
),
ThreeDSButtonType.RESEND to ThreeDSButtonStyle(
backgroundColor = "#F0F0F0",
cornerRadius = 48,
textColor = "#4287f5",
textFontSize = 16
)
),
labelStyle = ThreeDSLabelStyle(
headingTextColor = "#4287f5",
textColor = "#333333"
),
textBoxStyle = ThreeDSTextBoxStyle(
cornerRadius = 16,
borderColor = "#4287f5",
textColor = "#333333",
borderWidth = 4
),
toolbarStyle = ThreeDSToolbarStyle(
buttonText = "Zrušit",
headerText = "Ověření platby",
backgroundColor = "#F0F0F0",
textColor = "#333333"
)
)
ThreeDSButtonStyle
Prispôsobenie tlačidiel na challenge obrazovke.
| Parameter | Typ | Popis |
|---|---|---|
backgroundColor | String? | Farba pozadí ve formátu #RRGGBB alebo #AARRGGBB. |
cornerRadius | Int? | Zaoblenie rohov tlačidla v dp. |
textColor | String? | Farba textu ve formátu #RRGGBB alebo #AARRGGBB. |
textFontSize | Int? | Veľkosť písma v sp (8–48). |
Tlačidlá sa konfigurujú v mape podľa typu:
| Typ tlačidla | Popis |
|---|---|
ThreeDSButtonType.SUBMIT | Tlačidlo na odoslanie (potvrdenie). |
ThreeDSButtonType.CONTINUE | Tlačidlo na pokračovanie. |
ThreeDSButtonType.NEXT | Tlačidlo na ďalší krok. |
ThreeDSButtonType.CANCEL | Tlačidlo na zrušenie. |
ThreeDSButtonType.RESEND | Tlačidlo na opätovné odoslanie kódu. |
ThreeDSLabelStyle
Prispôsobenie textových popiskov.
| Parameter | Typ | Popis |
|---|---|---|
headingTextColor | String? | Farba nadpisu. |
headingTextFontSize | Int? | Veľkosť nadpisu v sp (8–48). |
textColor | String? | Farba bežného textu. |
textFontSize | Int? | Veľkosť bežného textu v sp (8–48). |
ThreeDSTextBoxStyle
Prispôsobenie vstupných polí na challenge obrazovke.
| Parameter | Typ | Popis |
|---|---|---|
borderWidth | Int? | Šírka orámovania v dp (0–10). |
borderColor | String? | Farba orámovania. |
cornerRadius | Int? | Zaoblenie rohov v dp. |
textColor | String? | Farba textu. |
textFontSize | Int? | Veľkosť textu v sp (8–48). |
ThreeDSToolbarStyle
Prispôsobenie toolbaru challenge obrazovky.
| Parameter | Typ | Popis |
|---|---|---|
backgroundColor | String? | Farba pozadí toolbaru. |
headerText | String? | Text v hlavičke toolbaru. |
buttonText | String? | Text tlačidla v toolbaru (typicky „Zrušit"). |
textColor | String? | Farba textu. |
textFontSize | Int? | Veľkosť textu v sp (8–48). |
Farby sa zadávajú ako reťazce vo formáte #RRGGBB alebo #AARRGGBB. Neplatné formáty sú v runtime ignorované a použijú sa predvolené hodnoty.
Motívy challenge okna
Knižnica obsahuje štyri preddefinované motívy na zobrazenie challenge obrazovky:
| Motív | Popis |
|---|---|
ComgateSdk | Svetlý dialóg (90 % šírky obrazovky, centrovaný) — predvolené |
ComgateSdk.Dark | Tmavý dialóg |
Theme.SecureFields.3DS.FullScreen | Svetlý celoobrazovkový režim |
Theme.SecureFields.3DS.FullScreen.Dark | Tmavý celoobrazovkový režim |
Na prepnutie motívu stačí pridať do res/values/styles.xml vašej aplikácie prepis štýlu Theme.SecureFields.3DS.Challenge:
<!-- res/values/styles.xml -->
<style name="Theme.SecureFields.3DS.Challenge"
parent="Theme.SecureFields.3DS.FullScreen" />
Zaoblenie rohov dialógového okna možno prispôsobiť definovaním dimenzie securefields_3ds_dialog_corner_radius v resources vašej aplikácie:
<!-- res/values/dimens.xml -->
<dimen name="securefields_3ds_dialog_corner_radius">16dp</dimen>
Alternatívne možno zaoblenie nastaviť programovo cez parameter challengeWindowCornerRadiusDp v ThreeDSConfig.
Testovanie 3DS platieb
Na uľahčenie vývoja a testovania ponúka knižnica v dev režime (devMode = true) možnosť simulovať rôzne priebehy 3DS autentifikácie bez nutnosti použiť skutočnú bankovú kartu.
Testovacie správanie sa riadi parametrom require3ds v PaymentParams:
Hodnota require3ds | Priebeh platby |
|---|---|
true | Server vráti challenge — zobrazí sa 3DS challenge obrazovka, používateľ musí zadať OTP alebo vykonať overenie. |
false | Server vráti frictionless výsledok — platba prebehne bez zobrazenia challenge obrazovky. |
null (predvolené) | Server rozhodne sám; v produkci standardní chování. |
Parameter require3ds je funkčný výhradne v dev režime (devMode = true). V produkcii (devMode = false) je hodnota tohto parametra ignorovaná a platba prebehne štandardným spôsobom.
Simulácia 3DS challenge
Nastavte require3ds = true. Knižnica zobrazí 3DS challenge obrazovku, kde používateľ vykoná overenie. Výsledok platby bude závisieť od akcie používateľa:
- Dokončenie overenia →
PaymentResult.Paid - Zrušenie challenge →
PaymentResult.Failed(ComgateError.ThreeDSChallengeCancelled) - Vypršanie časového limitu →
PaymentResult.Failed(ComgateError.ThreeDSChallengeTimeout)
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result -> /* ... */ },
paymentParamsProvider = {
PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Testovací platba",
refId = "test-001",
fullName = "Jan Novák",
require3ds = true // Vynutí 3DS challenge průběh — iba devMode
)
},
modifier = Modifier.fillMaxWidth()
)
Simulácia frictionless priebehu
Nastavte require3ds = false. Platba prebehne bez zobrazenia challenge obrazovky — autentifikácia je vyhodnotená serverom v pozadí. Výsledkom je PaymentResult.Paid, ak platba prebehne úspešne.
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result -> /* ... */ },
paymentParamsProvider = {
PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Testovací platba",
refId = "test-001",
fullName = "Jan Novák",
require3ds = false // Frictionless průběh bez challenge — iba devMode
)
},
modifier = Modifier.fillMaxWidth()
)
Simulácia chybového dôvodu — ErrorReason
V dev režime (devMode = true) možno pomocou parametra errorReason v PaymentParams simulovať konkrétny dôvod zamietnutia alebo zlyhania platby. Táto možnosť umožňuje testovať, ako aplikácia reaguje na rôzne chybové scenáre bez nutnosti skutočnej bankovej karty.
import cz.comgate.sdk.ErrorReason
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result -> /* ... */ },
paymentParamsProvider = {
PaymentParams(
price = 100,
curr = "CZK",
label = "Testovací platba",
refId = "test-001",
fullName = "Jan Novák",
errorReason = ErrorReason.NO_FUNDS // Simulace nedostatku prostředků — iba devMode
)
},
modifier = Modifier.fillMaxWidth()
)
Parameter errorReason je funkčný výhradne v dev režime (devMode = true).
Hodnota (vrátane null) je vždy odovzdaná serveru, ak bežíte v dev móde.
V produkcii je tento parameter úplne ignorovaný.
Dostupné hodnoty výčtu ErrorReason:
| Hodnota | Popis |
|---|---|
CUSTOMER_CLICK | Zrušené platiteľom. |
FRAUD_SUSPECTED | Podozrenie na podvod. |
ESHOP_CANCELLED | Zrušené obchodníkom. |
PROVIDER_REPORT | Zrušené providerom. |
PROVIDER_TIMEOUT | Vypršal časový limit poskytovateľa. |
CUSTOMER_TIMEOUT | Vypršal časový limit platby. |
ACS_TIMEOUT | Vypršal časový limit na overenie. |
INVALID_CARDNO_EXPIRY | Nesprávne zadané číslo karty alebo dátum platnosti karty. |
INVALID_CVC | Nesprávne zadaný CVC / CVV kód. |
LIMIT_EXCEEDED | Limit karty bol prekročený. |
NO_FUNDS | Na účte nie je dostatočný zostatok. |
REJECTED_BY_BANK | Platba bola zamietnutá bankou. |
3DS_AUTH_FAIL | Overenie 3DS nebolo úspešné. |
NOT_SPECIFIED | Nešpecifikované. |
Kompletný príklad
Nasledujúci príklad ukazuje kompletnú implementáciu kartovej platby s 3D Secure od inicializácie po spracovanie výsledku:
class PaymentActivity : AppCompatActivity() {
private lateinit var session: ComgateSecureSession
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 1. Konfigurácia 3DS
val threeDSConfig = ThreeDSConfig(
uiCustomization = ThreeDSUiCustomization(
toolbarStyle = ThreeDSToolbarStyle(
buttonText = "Zrušit",
headerText = "Ověření platby"
)
),
challengeTimeoutMinutes = 5
)
// 2. Vytvorenie session
session = ComgateSecureSession(
checkoutId = "váš-checkout-id",
context = applicationContext,
threeDSConfig = threeDSConfig,
lifecycleOwner = this,
onInitialized = { result ->
result.onSuccess {
// Session je pripravená
}.onFailure { e ->
Toast.makeText(this, "Chyba inicializace: ${e.message}", Toast.LENGTH_LONG).show()
}
}
)
// 3. Nastavenie Compose UI
setContent {
MaterialTheme {
Surface(modifier = Modifier.fillMaxSize()) {
PaymentScreen(session)
}
}
}
}
}
@Composable
private fun PaymentScreen(session: ComgateSecureSession) {
// 4. Stav polí — raw kartové údaje zostávajú vnútri SDK
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
val statusState = rememberPaymentStatusState()
var cardInfo by remember { mutableStateOf("Vyplňte údaje karty") }
// Kolektor sleduje validáciu všetkých troch polí
val collector = rememberSecureDataCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
onValidationChanged = { isValid ->
cardInfo = if (isValid) "✓ Karta končící na ${panState.last4}" else "Vyplňte údaje karty"
}
)
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.verticalScroll(rememberScrollState())
) {
Text(text = cardInfo, modifier = Modifier.padding(bottom = 8.dp))
// 5. Kartové polia
SecurePanField(state = panState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
SecureExpiryField(state = expiryState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(8.dp))
SecureCvvField(state = cvvState, modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(16.dp))
// 6. Platobné tlačidlo
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result ->
when (result) {
is PaymentResult.Paid -> {
statusState.showStatus(result)
// Platba úspešná
}
is PaymentResult.Authorized -> {
statusState.showStatus(result)
// Platba autorizovaná — čaká na zachytenie
}
is PaymentResult.Pending -> {
statusState.showStatus(result)
// Platba sa spracováva
}
is PaymentResult.Cancelled -> {
statusState.showStatus(result)
}
is PaymentResult.Failed -> {
statusState.showStatus(result)
}
}
},
paymentParamsProvider = {
PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Objednávka #123",
refId = "order-123",
fullName = "Jan Novák",
country = "CZ", // voliteľné
expirationTime = "1h", // voliteľné
billingAddrCity = "Hradec Králové", // voliteľné
billingAddrStreet = "Jiráskova 115", // voliteľné
billingAddrPostalCode = "50304", // voliteľné
billingAddrCountry = "CZ" // voliteľné
)
},
modifier = Modifier.fillMaxWidth()
)
// Stavový banner
SecurePaymentStatusView(
state = statusState,
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
)
}
}