Kartové údaje
Kartové platby probíhají prostredníctvom zabezpečených vstupních komponent — Secure Fields. Tieto komponenty zajišťují bezpečné zadávanie, validaci a ochranu karetních údajov. Hostitelská aplikace nikdy nemá přístup k citlivým údajovm v nechráněné podobě.
Secure Fields
Knižnica poskytuje čtyři komponenty pro zadávanie údajov v platebním formuláři:
SecurePanField
Pole pro zadání čísla karty (PAN — Primary Account Number).
- Prijíma iba číslice
- Automaticky detekuje karetní síť (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 pomocí Luhnova algoritmu
- Podporuje systémový autofill
- Sprístupňuje vlastnosť
last4— poslední 4 číslice karty (bezpečné pro zobrazení v UI)
import cz.comgate.sdk.compose.*
val panState = rememberSecurePanFieldState()
SecurePanField(
state = panState,
modifier = Modifier.fillMaxWidth()
)
SecureExpiryField
Pole pro zadání data expirace karty.
- Prijíma iba číslice
- Automaticky formátuje vstup ve tvaru MM/YY
- Validuje měsíc (1–12) a kontroluje, zda karta není expirovaná
- Podporuje autofill ve formátech MMYY i MMYYYY
val expiryState = rememberSecureExpiryFieldState()
SecureExpiryField(
state = expiryState,
modifier = Modifier.fillMaxWidth()
)
SecureCvvField
Pole pro zadání bezpečnostního kódu karty (CVV/CVC).
- Prijíma iba číslice
- Délka se automaticky přizpůsobuje detekované karetní síti
- Validuje minimální požadovanou délku
val cvvState = rememberSecureCvvFieldState()
SecureCvvField(
state = cvvState,
modifier = Modifier.fillMaxWidth()
)
SecureFullNameField
Pole pro zadání jména a příjmení plátce.
- Prijíma textový vstup (vrátane mezer)
- Podporuje systémový autofill jména
- Je validní pri neprázdné hodnotě
- Po připojení k
ComgateSecureSessionse jeho hodnota automaticky použije jakofullName
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 přednost před hodnotou z SecureFullNameField — ak je fullName v PaymentParams vyplnený, pole SecureFullNameField není vyžadováno. Ak je fullName prázdny, použije se hodnota z připojeného pole. Ak je prázdné obojí, platba selže s chybou MISSING_CARDHOLDER_NAME.
Společné vlastnosťi
Všechny Secure Fields (SecurePanField, SecureExpiryField, SecureCvvField, SecureFullNameField) sdílejí tieto vlastnosťi a metody:
| Vlastnost / Metoda | Typ | Popis |
|---|---|---|
isFieldValid | Boolean | Aktuální stav validace pole (read-only). |
onValidationChanged | (Boolean) -> Unit | Callback volaný pri změně validačního stavu. |
showLabel | Boolean | Zobrazení labelu nad poľom. Predvolené true. Nastavte false pro skrytí labelu. |
labelText | String? | Vlastní text labelu. Ak je null, použije se predvolené přeložený label podle session.translation. |
setHint(hint) | String | Nastaví placeholder text. |
setEnabled(enabled) | Boolean | Povolí/zakáže pole. |
clear() | — | Vymaže obsah pole a resetuje validaci. |
Labely vstupních polí
Každé pole má label nad vstupem (SecurePanField, SecureExpiryField, SecureCvvField, SecureFullNameField).
- Predvolený text labelu se bere z
session.translation - Label lze skryť přes
showLabel = false - Predvolené překlad lze přepsat přes
labelText
SecurePanField(
state = panState,
modifier = Modifier.fillMaxWidth(),
update = {
showLabel = true
labelText = "Číslo platební karty"
}
)
SecureCardDataCollector
SecureCardDataCollector propojuje tři samostatná Secure Fields a sleduje ich celkový validační stav. Je vyžadován pro spracovania platby.
import cz.comgate.sdk.compose.*
// Stav polí — raw kartové údaje zůstávají uvnitř SDK
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
// Kolektor propojující pole a sledující celkovou validaci
val collector = rememberSecureCardCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
onValidationChanged = { isValid ->
// isValid je true, když jsou všetky tri polia validné
}
)
Předávání focusu mezi poli
rememberSecureCardCollector ve predvoleném stavu automaticky odovzdáva focus mezi poli v pořadí:
PAN -> Expirace -> CVV
K přesunu dojde ve chvíli, kdy je aktuální pole kompletně vyplněné a validní.
val collector = rememberSecureCardCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
autoAdvanceFocus = true // vychozi hodnota
)
Ak chcete focus řídit sami, vypněte automatiku:
val collector = rememberSecureCardCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
autoAdvanceFocus = false
)
Pri implementaci pomocí Android View můžete odovzdávaní focusu zapojit ručně přes nextSecureField:
panField.nextSecureField = expiryField
expiryField.nextSecureField = cvvField
| Vlastnost / Metoda | Typ | Popis |
|---|---|---|
isValid | Boolean | true ak jsou 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é platební tlačidlo, které se automaticky integruje se session a kolektorem:
- Automaticky se aktivuje/deaktivuje podle validačního stavu karetních polí
- Tlačítko zůstane deaktivované, dokud není session úspěšně inicializována
- Po kliknutí zahájí spracovania platby prostredníctvom
ComgateSecureSession - Během spracovania zobrazuje shimmer sweep animaci přes tlačidlo (animaci lze vypnout)
- Vrací výsledek platby přes callback
Nastavenie tlačidla
Composable SecurePayButton přijímá parametry session, kolektoru, callbacku a provideru platebních parametrů:
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", // volitelné
expirationTime = "1h", // volitelné
billingAddrCity = "Hradec Králové", // volitelné
billingAddrStreet = "Jiráskova 115", // volitelné
billingAddrPostalCode = "50304", // volitelné
billingAddrCountry = "CZ" // volitelné
)
},
modifier = Modifier.fillMaxWidth()
)
Parametr paymentParamsProvider je lambda, která je zavolaná v okamihu kliknutí na tlačidlo. Díky tomu lze dynamicky číst aktuální hodnoty z UI (napr. částku z textového pole).
PaymentParams
| Parametr | Typ | Povinný | Popis |
|---|---|---|---|
email | String | Ano | E-mailová adresa plátce. |
price | Int | Ano | Částka platby v haléřích/centech (napr. 10000 = 100,00 CZK). |
curr | String | Ano | Kód měny — ISO 4217 (napr. "CZK", "EUR"). |
label | String | Ano | Krátký popis produktu (1–16 znaků). |
refId | String | Ano | Variabilní symbol alebo číslo objednávky (vaše interní ID). |
fullName | String | Podmíněně | Jméno a příjmení plátce. Ak je neprázdny, má přednost před hodnotou z SecureFullNameField. Ak je prázdny, použije se hodnota z připojeného SecureFullNameField (tehdy povinného). Ak je prázdné obojí, platba selže s chybou MISSING_CARDHOLDER_NAME. |
country | String | Ne | Kód země dle ISO 3166-1 alpha-2 (napr. "CZ", "SK"). Predvolené: "CZ". Povolené hodnoty: AT, BE, CY, CZ, DE, EE, EL, ES, FI, FR, GB, HR, HU, IE, IT, LT, LU, LV, MT, NL, NO, PL, PT, RO, SI, SK, SE, US. Jakákoli jiná hodnota (vrátane prázdného reťazca) je před odesláním normalizována na "ALL". Hodnota se odovzdáva také do platebního dialogu Google Pay. |
account | String? | Ne | Identifikátor bankovního účtu klienta v systému Comgate. |
name | String? | Ne | Identifikátor produktu (zobrazí se v denním CSV jako „Produkt"). |
preauth | Boolean? | Ne | Označí platbu jako předautorizaci — rezervuje prostředky na kartě bez okamžitého stržení. true — předautorizace, null — predvolené chování. Nelze kombinovat s initRecurring = true. |
initRecurring | Boolean? | Ne | Označí platbu jako první v sérii opakovaných plateb. true — iniciální rekurentní platba, null — predvolené chování. Nelze kombinovat s preauth = true. |
expirationTime | String? | Ne | Doba expirace platby (napr. "30m", "3h", "5d"). Rozsah: 30 minut — 7 dní. |
dynamicExpiration | Boolean? | Ne | Dynamická expirace platby (true pro zapnutí). |
billingAddrCity | String? | Ne | Fakturační adresa — město. |
billingAddrStreet | String? | Ne | Fakturační adresa — ulice. |
billingAddrPostalCode | String? | Ne | Fakturační adresa — PSČ. |
billingAddrCountry | String? | Ne | Fakturační adresa — kód země (ISO 3166-1 alpha-2). |
delivery | String? | Ne | Způsob doručení ("HOME_DELIVERY", "PICKUP", "ELECTRONIC_DELIVERY"). |
homeDeliveryCity | String? | Ne | Doručovací adresa — město (jen 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? | Ne | Doručovací adresa — kód země (jen pri delivery = "HOME_DELIVERY"). |
category | String? | Ne | Kategorie produktu ("PHYSICAL_GOODS_ONLY", "OTHER"). |
require3ds | Boolean? | Ne | Pouze v dev režimu (devMode = true). Vynucuje typ 3DS průběhu na testovacím serveru. true — vynutí průběh s challenge, false — vynutí frictionless průběh (bez challenge), null — server rozhodne sám. V produkci ignorováno. |
errorReason | ErrorReason? | Ne | Pouze v dev režimu (devMode = true). Simuluje konkrétní dôvod zamítnutí alebo selhání platby. Hodnota (vrátane null) je vždy odovzdaná serveru pri dev módu. V produkci ignorováno. Viz ErrorReason. |
Opakované platby a předautorizace
initRecurring
Parametr initRecurring = true označí platbu jako první (iniciační) transakci v sérii opakovaných plateb. Banka tím dostane signál, že v budoucnu budou probíhat další automatické platby (napr. předplatné, 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
)
Parametr initRecurring nelze kombinovat s preauth = true.
preauth
Parametr preauth = true označí platbu jako předautorizaci — banka dočasně rezervuje požadovanou částku na kartě plátce, ale prostředky nejsou ihned strženy. K zachycení (stržení) dochází až pri potvrzení transakce na strane backendu.
Předautorizace se typicky využívá v situacích, kde konečná výše platby není v době autorizace ještě jasná (napr. půjčovny, hotely, tankování).
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í
)
Parametr preauth nelze kombinovat s initRecurring = true.
Statické parametry
Ak jsou parametry platby známé předem, lze použít variantu setup() se statickým objektem:
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result -> /* ... */ },
paymentParams = PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Názov platby",
refId = "ref-123",
fullName = "Jan Novák",
country = "CZ", // volitelné
expirationTime = "1h", // volitelné
billingAddrCity = "Hradec Králové", // volitelné
billingAddrStreet = "Jiráskova 115", // volitelné
billingAddrPostalCode = "50304", // volitelné
billingAddrCountry = "CZ" // volitelné
),
modifier = Modifier.fillMaxWidth()
)
Stylovaní tlačidla
Volitelný update blok umožňuje programaticky stylovat tlačidlo pri každé rekomposici. Dostupné metody jsou popsány v sekcii Stylizace komponent.
import cz.comgate.sdk.compose.*
// Stav polí a kolektoru
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
val collector = rememberSecureCardCollector(panState, expiryState, cvvState)
// Platební 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 = {
// Volitelné programatické stylování — viz sekce Stylizace
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 přímé volání processPayment
Ak vám predpripravené SecurePayButton nevyhovuje (napr. chcete vlastní design, animace alebo složitější logiku), můžete platbu spustit priamo voláním metody session.processPayment() na instanci ComgateSecureSession.
Metoda processPayment šifruje kartové údaje, odesílá je na platební bránu a v případě potřeby automaticky provede 3D Secure autentizaci. Citlivé údaje nikdy neopustia knihovnu v nechráněné podobě.
Signatura metody
suspend fun processPayment(
activity: Activity,
collector: SecureCardDataCollector,
params: PaymentParams
): PaymentResult
| Parametr | Typ | Popis |
|---|---|---|
activity | Activity | Aktuální aktivita — nutná pro zobrazení 3DS challenge UI. |
collector | SecureCardDataCollector | Kolektor propojující Secure Fields (PAN, expirace, CVV). |
params | PaymentParams | Parametry platby (cena, měna, popis, refId, jméno plátce aj.). |
Příklad implementace
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 = rememberSecureCardCollector(
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 — přímé volání 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.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)
)
}
}
Před voláním processPayment se ujistěte, že:
- Session je úspěšně inicializovaná (callback
onInitializedvrátilResult.success). - Kartové údaje jsou validní (
collector.isValid == true).
Ak tieto podmínky nejsou splněny, metoda okamžitě vrátí PaymentResult.Cancelled.
Způsoby implementace
Knižnica podporuje implementaci pomocí tří samostatných komponent (SecurePanField, SecureExpiryField, SecureCvvField) propojených přes SecureCardDataCollector.
Samostatná pole
Každé pole je umístěno nezávisle v Compose layoutu. Tento přístup poskytuje plnou kontrolu nad rozložením a stylováním.
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 = rememberSecureCardCollector(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.Cancelled -> statusState.showStatus(result)
is PaymentResult.Failed -> statusState.showStatus(result)
else -> 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", // volitelné
expirationTime = "1h" // volitelné
)
},
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:
- Připraví autentizační parametry pri spracovania platby
- Vyhodnotí odpověď serveru (frictionless / challenge)
- V případě potřeby zobrazí challenge obrazovku
- Vrátí výsledek autentifikácie prostredníctvom
PaymentResult
Konfigurace
3DS se konfiguruje prostredníctvom třídy ThreeDSConfig, která se odovzdáva do konstruktoru 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
)
Parametr lifecycleOwner řídí, kdy book session automaticky uvolní prostředky. Ve výše uvedených příkladech se odovzdáva this (aktivita).
Ak session vytváříte uvnitř Fragmentu, předejte viewLifecycleOwner (dostupný od onViewCreated):
- Activity:
lifecycleOwner = this - Fragment:
lifecycleOwner = viewLifecycleOwner(nethis— Fragment přežívá opätovné vytvorenie view a způsobilo by memory leak)
Parametry ThreeDSConfig
| Parametr | Typ | Predvolené | Popis |
|---|---|---|---|
uiCustomization | ThreeDSUiCustomization? | null | Přizpůsobení vzhledu challenge obrazovky. Ak je null, použijí se predvolené styly. |
defaultMessageVersion | String | "2.2.0" | Verze 3DS protokolu. |
challengeTimeoutMinutes | Int | 5 | Maximální doba čekání na dokončení challenge v minutách (1–30). |
challengeWindowCornerRadiusDp | Int? | null | Zaoblení rohů challenge okna v dp. Ak je null, použije se predvolené hodnota z motivu. |
Přizpůsobení vzhledu challenge obrazovky
Třída ThreeDSUiCustomization umožňuje detailní přizpůsobení vzhledu 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
Přizpůsobení tlačítek na challenge obrazovce.
| Parametr | Typ | Popis |
|---|---|---|
backgroundColor | String? | Farba pozadí ve formátu #RRGGBB alebo #AARRGGBB. |
cornerRadius | Int? | Zaoblení rohů tlačidla v dp. |
textColor | String? | Farba textu ve formátu #RRGGBB alebo #AARRGGBB. |
textFontSize | Int? | Velikost písma v sp (8–48). |
Tlačítka se konfigurují v mapě dle typu:
| Typ tlačidla | Popis |
|---|---|
ThreeDSButtonType.SUBMIT | Tlačítko pro odeslání (potvrzení). |
ThreeDSButtonType.CONTINUE | Tlačítko pro pokračování. |
ThreeDSButtonType.NEXT | Tlačítko pro další krok. |
ThreeDSButtonType.CANCEL | Tlačítko pro zrušení. |
ThreeDSButtonType.RESEND | Tlačítko pro opětovné odeslání kódu. |
ThreeDSLabelStyle
Přizpůsobení textových popisků.
| Parametr | Typ | Popis |
|---|---|---|
headingTextColor | String? | Farba nadpisu. |
headingTextFontSize | Int? | Velikost nadpisu v sp (8–48). |
textColor | String? | Farba běžného textu. |
textFontSize | Int? | Velikost běžného textu v sp (8–48). |
ThreeDSTextBoxStyle
Přizpůsobení vstupních polí na challenge obrazovce.
| Parametr | Typ | Popis |
|---|---|---|
borderWidth | Int? | Šírka orámovania v dp (0–10). |
borderColor | String? | Farba orámovania. |
cornerRadius | Int? | Zaoblení rohů v dp. |
textColor | String? | Farba textu. |
textFontSize | Int? | Velikost textu v sp (8–48). |
ThreeDSToolbarStyle
Přizpůsobení toolbaru challenge obrazovky.
| Parametr | Typ | Popis |
|---|---|---|
backgroundColor | String? | Farba pozadí toolbaru. |
headerText | String? | Text v hlavičce toolbaru. |
buttonText | String? | Text tlačidla v toolbaru (typicky „Zrušit"). |
textColor | String? | Farba textu. |
textFontSize | Int? | Velikost textu v sp (8–48). |
Barvy se zadávají jako reťazca ve formátu #RRGGBB alebo #AARRGGBB. Neplatné formáty jsou v runtime ignorovány a použijí se predvolené hodnoty.
Motivy challenge okna
Knižnica obsahuje čtyři předdefinované motivy pro zobrazení challenge obrazovky:
| Motiv | Popis |
|---|---|
Theme.ComgateSdk.3DS.Dialog | Světlý dialog (90 % šířky obrazovky, centrovaný) — predvolené |
Theme.ComgateSdk.3DS.Dialog.Dark | Tmavý dialog |
Theme.ComgateSdk.3DS.FullScreen | Světlý celoobrazovkový režim |
Theme.ComgateSdk.3DS.FullScreen.Dark | Tmavý celoobrazovkový režim |
Pro přepnutí motivu stačí přidat do res/values/styles.xml vašej aplikace přepis stylu Theme.ComgateSdk.3DS.Challenge:
<!-- res/values/styles.xml -->
<style name="Theme.ComgateSdk.3DS.Challenge"
parent="Theme.ComgateSdk.3DS.FullScreen" />
Zaoblení rohů dialogového okna lze přizpůsobit definováním dimenze securefields_3ds_dialog_corner_radius v resources vašej aplikace:
<!-- res/values/dimens.xml -->
<dimen name="securefields_3ds_dialog_corner_radius">16dp</dimen>
Alternativně lze zaoblenie nastavit programaticky přes parametr challengeWindowCornerRadiusDp v ThreeDSConfig.
Testování 3DS plateb
Pro usnadnění vývoje a testování nabízí knižnica v dev režimu (devMode = true) možnost simulovat různé průběhy 3DS autentifikácie bez nutnosti použít skutečnou bankovní kartu.
Testovací chování se řídí parametrem require3ds v PaymentParams:
Hodnota require3ds | Průběh platby |
|---|---|
true | Server vrátí challenge — zobrazí se 3DS challenge obrazovka, používateľ musí zadat OTP alebo provést ověření. |
false | Server vrátí frictionless výsledek — platba proběhne bez zobrazení challenge obrazovky. |
null (predvolené) | Server rozhodne sám; v produkci standardní chování. |
Parametr require3ds je funkční výhradne v dev režimu (devMode = true). V produkci (devMode = false) je hodnota tohoto parametru ignorována a platba proběhne standardním způsobem.
Simulace 3DS challenge
Nastavte require3ds = true. Knižnica zobrazí 3DS challenge obrazovku, kde používateľ provede ověření. Výsledek platby bude záviset na akci používateľe:
- Dokončení ověření →
PaymentResult.Paid - Zrušení challenge →
PaymentResult.Failed(ComgateError.ThreeDSChallengeCancelled) - Vypršení č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()
)
Simulace frictionless průběhu
Nastavte require3ds = false. Platba proběhne bez zobrazení challenge obrazovky — autentifikácie je vyhodnocena serverem v pozadí. Výsledkem je PaymentResult.Paid, ak platba proběhne úspěšně.
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()
)
Simulace chybového dôvodu — ErrorReason
V dev režimu (devMode = true) lze pomocí parametru errorReason v PaymentParams simulovat konkrétní dôvod zamítnutí alebo selhání platby. Tato možnost umožňuje testovat, jak aplikace reaguje na různé chybové scénáře bez nutnosti skutečné bankovní 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()
)
Parametr errorReason je funkční výhradne v dev režimu (devMode = true).
Hodnota (vrátane null) je vždy odovzdaná serveru, ak běžíte v dev módu.
V produkci je tento parametr zcela ignorován.
Dostupné hodnoty výčtu ErrorReason:
| Hodnota | Popis |
|---|---|
CUSTOMER_CLICK | Zrušeno plátcem. |
FRAUD_SUSPECTED | Podezření na podvod. |
ESHOP_CANCELLED | Zrušeno obchodníkem. |
PROVIDER_REPORT | Zrušeno providerem. |
PROVIDER_TIMEOUT | Vypršel časový limit poskytovatele. |
CUSTOMER_TIMEOUT | Vypršel časový limit platby. |
ACS_TIMEOUT | Vypršel časový limit pro ověření. |
INVALID_CARDNO_EXPIRY | Chybně zadané číslo karty alebo datum platnosti karty. |
INVALID_CVC | Chybně zadaný CVC / CVV kód. |
LIMIT_EXCEEDED | Limit karty byl překročen. |
NO_FUNDS | Na účtu není dostatečný zůstatek. |
REJECTED_BY_BANK | Platba bola zamietnutá bankou. |
3DS_AUTH_FAIL | Ověření 3DS nebylo úspěšné. |
NOT_SPECIFIED | Nespecifikováno. |
Kompletný príklad
Následující příklad ukazuje kompletní implementaci karetní platby s 3D Secure od inicializace po spracovania výsledku:
class PaymentActivity : AppCompatActivity() {
private lateinit var session: ComgateSecureSession
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 1. Konfigurace 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 připravena
}.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 zůstávají uvnitř SDK
val panState = rememberSecurePanFieldState()
val expiryState = rememberSecureExpiryFieldState()
val cvvState = rememberSecureCvvFieldState()
val statusState = rememberPaymentStatusState()
var cardInfo by remember { mutableStateOf("Vyplňte údaje karty") }
// Kolektor sleduje validaci všech tří polí
val collector = rememberSecureCardCollector(
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. Karetní pole
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. Platební tlačidlo
SecurePayButton(
session = session,
collector = collector,
onPaymentResult = { result ->
when (result) {
is PaymentResult.Paid -> {
statusState.showStatus(result)
// Platba úspěšná
}
is PaymentResult.Pending -> {
statusState.showStatus(result)
// Platba se zpracovává
}
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", // volitelné
expirationTime = "1h", // volitelné
billingAddrCity = "Hradec Králové", // volitelné
billingAddrStreet = "Jiráskova 115", // volitelné
billingAddrPostalCode = "50304", // volitelné
billingAddrCountry = "CZ" // volitelné
)
},
modifier = Modifier.fillMaxWidth()
)
// Stavový banner
SecurePaymentStatusView(
state = statusState,
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
)
}
}