Přeskočit na hlavní obsah

Karetní data

Karetní platby probíhají prostřednictvím zabezpečených vstupních komponent — Secure Fields. Tyto komponenty zajišťují bezpečné zadávání, validaci a ochranu karetních údajů. Hostitelská aplikace nikdy nemá přístup k citlivým údajům v nechráněné podobě.

Secure Fields

Knihovna poskytuje čtyři komponenty pro zadávání údajů v platebním formuláři:

SecurePanField

Pole pro zadání čísla karty (PAN — Primary Account Number).

  • Přijímá pouze číslice
  • Automaticky detekuje karetní síť (Visa, Mastercard)
  • Formátuje číslo karty s mezerami dle karetní sítě (např. 4111 1111 1111 1111)
  • Omezuje délku vstupu podle detekované karetní sítě
  • Validuje číslo karty pomocí Luhnova algoritmu
  • Podporuje systémový autofill
  • Zpřístupňuje vlastnost 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.

  • Přijímá pouze čí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).

  • Přijímá pouze číslice
  • Délka je fixně 3 číslice
  • 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.

  • Přijímá textový vstup (včetně mezer)
  • Podporuje systémový autofill jména
  • Je validní při neprázdné hodnotě
  • Po připojení k ComgateSecureSession se jeho hodnota automaticky použije jako fullName
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()
)
Informace

PaymentParams.fullName má vždy přednost před hodnotou z SecureFullNameField — pokud je fullName v PaymentParams vyplněný, pole SecureFullNameField není vyžadováno. Pokud je fullName prázdný, použije se hodnota z připojeného pole. Je-li prázdné obojí, platba selže s chybou MISSING_CARDHOLDER_NAME.

Společné vlastnosti

Všechny Secure Fields (SecurePanField, SecureExpiryField, SecureCvvField, SecureFullNameField) sdílejí tyto vlastnosti a metody:

Vlastnost / MetodaTypPopis
isFieldValidBooleanAktuální stav validace pole (read-only).
onValidationChanged(Boolean) -> UnitCallback volaný při změně validačního stavu.
showLabelBooleanZobrazení labelu nad polem. Výchozí true. Nastavte false pro skrytí labelu.
labelTextString?Vlastní text labelu. Pokud je null, použije se výchozí přeložený label podle session.translation.
setHint(hint)UnitNastaví placeholder text.
setEnabled(enabled)UnitPovolí/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).

  • Výchozí text labelu se bere z session.translation
  • Label lze skrýt přes showLabel = false
  • Výchozí 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 jejich celkový validační stav. Je vyžadován pro zpracování platby.

import cz.comgate.sdk.compose.*

// Stav polí — raw karetní data 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šechna tři pole validní
}
)

Předávání focusu mezi poli

rememberSecureCardCollector ve výchozím stavu automaticky předává 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
)

Pokud chcete focus řídit sami, vypněte automatiku:

val collector = rememberSecureCardCollector(
panState = panState,
expiryState = expiryState,
cvvState = cvvState,
autoAdvanceFocus = false
)

Při implementaci pomocí Android View můžete předávání focusu zapojit ručně přes nextSecureField:

panField.nextSecureField = expiryField
expiryField.nextSecureField = cvvField
Vlastnost / MetodaTypPopis
isValidBooleantrue pokud jsou všechna tři pole validní.
onValidationChanged(Boolean) -> UnitCallback volaný při změně validačního stavu kteréhokoliv pole.

SecurePayButton

SecurePayButton je předpřipravené platební tlačítko, 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í zpracování platby prostřednictvím ComgateSecureSession
  • Během zpracování zobrazuje shimmer sweep animaci přes tlačítko (animaci lze vypnout)
  • Vrací výsledek platby přes callback

Nastavení tlačítka

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 ->
// Zpracování výsledku platby
},
paymentParamsProvider = {
PaymentParams(
email = "zakaznik@example.com",
price = 100,
curr = "CZK",
label = "Název platby",
refId = "ref-123",
fullName = "Jan Novák",
country = "CZ", // 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 zavolána v okamžiku kliknutí na tlačítko. Díky tomu lze dynamicky číst aktuální hodnoty z UI (např. částku z textového pole).

PaymentParams

ParametrTypPovinnýPopis
emailStringAnoE-mailová adresa plátce.
priceIntAnoČástka platby v haléřích/centech (např. 10000 = 100,00 CZK).
currStringAnoKód měny — ISO 4217 (např. "CZK", "EUR"). Viz PaymentParams.supportedCurrencies pro úplný seznam.
labelStringAnoKrátký popis produktu (1–16 znaků).
refIdStringAnoVariabilní symbol nebo číslo objednávky (vaše interní ID).
fullNameStringPodmíněněJméno a příjmení plátce. Pokud je neprázdný, má přednost před hodnotou z SecureFullNameField. Pokud je prázdný, použije se hodnota z připojeného SecureFullNameField (tehdy povinného). Je-li prázdné obojí, platba selže s chybou MISSING_CARDHOLDER_NAME.
countryStringNeKód země dle ISO 3166-1 alpha-2 (např. "CZ", "SK"). Výchozí: "CZ". Jakákoli hodnota mimo seznam je před odesláním normalizována na "ALL". Hodnota se předává také do platebního dialogu Google Pay. Viz PaymentParams.supportedCountries pro úplný seznam.
accountString?NeIdentifikátor bankovního účtu klienta v systému Comgate.
nameString?NeIdentifikátor produktu (zobrazí se v denním CSV jako „Produkt").
preauthBoolean?NeOznačí platbu jako předautorizaci — rezervuje prostředky na kartě bez okamžitého stržení. true — předautorizace, null — výchozí chování. Nelze kombinovat s initRecurring = true.
initRecurringBoolean?NeOznačí platbu jako první v sérii opakovaných plateb. true — iniciální rekurentní platba, null — výchozí chování. Nelze kombinovat s preauth = true.
billingAddrCityString?NeFakturační adresa — město.
billingAddrStreetString?NeFakturační adresa — ulice.
billingAddrPostalCodeString?NeFakturační adresa — PSČ.
billingAddrCountryString?NeFakturační adresa — kód země (ISO 3166-1 alpha-2).
deliveryString?NeZpůsob doručení ("HOME_DELIVERY", "PICKUP", "ELECTRONIC_DELIVERY").
homeDeliveryCityString?NeDoručovací adresa — město (jen při delivery = "HOME_DELIVERY").
homeDeliveryStreetString?NeDoručovací adresa — ulice (jen při delivery = "HOME_DELIVERY").
homeDeliveryPostalCodeString?NeDoručovací adresa — PSČ (jen při delivery = "HOME_DELIVERY").
homeDeliveryCountryString?NeDoručovací adresa — kód země (jen při delivery = "HOME_DELIVERY").
categoryString?NeKategorie produktu ("PHYSICAL_GOODS_ONLY", "OTHER").
require3dsBoolean?NePouze 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.
errorReasonErrorReason?NePouze v dev režimu (devMode = true). Simuluje konkrétní důvod zamítnutí nebo selhání platby. Hodnota (včetně null) je vždy předána serveru při dev módu. V produkci ignorováno. Viz ErrorReason.

Podporované měny a země

Podporované měny (PaymentParams.supportedCurrencies)

PaymentParams.supportedCurrencies vrací seznam ISO 4217 kódů měn přijímaných platební bránou Comgate. Tento seznam lze využít například k naplnění výběru měny v UI.

BGN, CHF, CZK, DKK, EUR, GBP, HUF, NOK, PLN, RON, SEK, USD

Podporované země (PaymentParams.supportedCountries)

PaymentParams.supportedCountries vrací seznam ISO 3166-1 alpha-2 kódů zemí přijímaných pro parametr country. Hodnota "ALL" reprezentuje žádné omezení na konkrétní zemi. Jakákoli jiná hodnota mimo tento seznam je serverem normalizována 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

Příklad použití pro naplnění výběru měny a země

// Dostupné měny pro výběr v UI
val currencies = PaymentParams.supportedCurrencies // ["BGN", "CHF", "CZK", ...]

// Dostupné země pro výběr v UI
val countries = PaymentParams.supportedCountries // ["ALL", "AT", "BE", "CY", "CZ", ...]

PaymentParams(
email = "zakaznik@example.com",
price = 10000,
curr = selectedCurrency, // hodnota z výběru
country = selectedCountry, // hodnota z výběru
label = "Objednávka",
refId = "order-123",
fullName = "Jan Novák"
)

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 (např. 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
)
Informace

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ž při potvrzení transakce na straně backendu.

Předautorizace se typicky využívá v situacích, kde konečná výše platby není v době autorizace ještě jasná (např. 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í
)
Informace

Parametr preauth nelze kombinovat s initRecurring = true.

Statické parametry

Pokud 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ázev platby",
refId = "ref-123",
fullName = "Jan Novák",
country = "CZ", // volitelné
billingAddrCity = "Hradec Králové", // volitelné
billingAddrStreet = "Jiráskova 115", // volitelné
billingAddrPostalCode = "50304", // volitelné
billingAddrCountry = "CZ" // volitelné
),
modifier = Modifier.fillMaxWidth()
)

Stylovaní tlačítka

Volitelný update blok umožňuje programaticky stylovat tlačítko při každé rekomposici. Dostupné metody jsou popsány v sekci 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čítko
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čítko a přímé volání processPayment

Pokud vám předpřipravené SecurePayButton nevyhovuje (např. chcete vlastní design, animace nebo složitější logiku), můžete platbu spustit přímo voláním metody session.processPayment() na instanci ComgateSecureSession.

Tip

Metoda processPayment šifruje karetní data, odesílá je na platební bránu a v případě potřeby automaticky provede 3D Secure autentizaci. Citlivé údaje nikdy neopustí knihovnu v nechráněné podobě.

Signatura metody

suspend fun processPayment(
activity: Activity,
collector: SecureCardDataCollector,
params: PaymentParams
): PaymentResult
ParametrTypPopis
activityActivityAktuální aktivita — nutná pro zobrazení 3DS challenge UI.
collectorSecureCardDataCollectorKolektor propojující Secure Fields (PAN, expirace, CVV).
paramsPaymentParamsParametry 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čítko — 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šena / zamítnuta */ }
is PaymentResult.Failed -> { /* Chyba knihovny */ }
}
}
}
},
enabled = isFormValid && !isProcessing,
modifier = Modifier.fillMaxWidth()
) {
Text(if (isProcessing) "Zpracování..." else "Zaplatit")
}

SecurePaymentStatusView(
state = statusState,
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
)
}
}
Upozornění

Před voláním processPayment se ujistěte, že:

  1. Session je úspěšně inicializovaná (callback onInitialized vrátil Result.success).
  2. Karetní data jsou validní (collector.isValid == true).

Pokud tyto podmínky nejsou splněny, metoda okamžitě vrátí PaymentResult.Cancelled.

Způsoby implementace

Knihovna 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é
)
},
modifier = Modifier.fillMaxWidth()
)

SecurePaymentStatusView(
state = statusState,
modifier = Modifier.fillMaxWidth().padding(top = 8.dp)
)
}
}

3D Secure

Knihovna poskytuje kompletní podporu 3D Secure autentizace. Pokud je 3DS nakonfigurováno, knihovna automaticky:

  1. Připraví autentizační parametry při zpracování platby
  2. Vyhodnotí odpověď serveru (frictionless / challenge)
  3. V případě potřeby zobrazí challenge obrazovku
  4. Vrátí výsledek autentizace prostřednictvím PaymentResult

Konfigurace

3DS se konfiguruje prostřednictvím třídy ThreeDSConfig, která se předává do konstruktoru ComgateSecureSession:

val threeDSConfig = ThreeDSConfig(
uiCustomization = threeDSUi, // Přizpůsobení vzhledu (volitelné)
challengeTimeoutMinutes = 5, // Timeout pro challenge (výchozí: 5)
defaultMessageVersion = "2.2.0", // Verze 3DS protokolu (výchozí: "2.2.0")
challengeWindowCornerRadiusDp = 16 // Zaoblení rohů challenge okna (volitelné)
)

val session = ComgateSecureSession(
checkoutId = "váš-checkout-id",
context = applicationContext,
threeDSConfig = threeDSConfig,
lifecycleOwner = this
)
Použití ve Fragmentu

Parametr lifecycleOwner řídí, kdy book session automaticky uvolní prostředky. Ve výše uvedených příkladech se předává this (aktivita).

Pokud session vytváříte uvnitř Fragmentu, předejte viewLifecycleOwner (dostupný od onViewCreated):

  • Activity: lifecycleOwner = this
  • Fragment: lifecycleOwner = viewLifecycleOwner (ne this — Fragment přežívá opětovné vytvoření view a způsobilo by memory leak)

Parametry ThreeDSConfig

ParametrTypVýchozíPopis
uiCustomizationThreeDSUiCustomization?nullPřizpůsobení vzhledu challenge obrazovky. Pokud je null, použijí se výchozí styly.
defaultMessageVersionString"2.2.0"Verze 3DS protokolu.
challengeTimeoutMinutesInt5Maximální doba čekání na dokončení challenge v minutách (1–30).
challengeWindowCornerRadiusDpInt?nullZaoblení rohů challenge okna v dp. Pokud je null, použije se výchozí 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.

ParametrTypPopis
backgroundColorString?Barva pozadí ve formátu #RRGGBB nebo #AARRGGBB.
cornerRadiusInt?Zaoblení rohů tlačítka v dp.
textColorString?Barva textu ve formátu #RRGGBB nebo #AARRGGBB.
textFontSizeInt?Velikost písma v sp (8–48).

Tlačítka se konfigurují v mapě dle typu:

Typ tlačítkaPopis
ThreeDSButtonType.SUBMITTlačítko pro odeslání (potvrzení).
ThreeDSButtonType.CONTINUETlačítko pro pokračování.
ThreeDSButtonType.NEXTTlačítko pro další krok.
ThreeDSButtonType.CANCELTlačítko pro zrušení.
ThreeDSButtonType.RESENDTlačítko pro opětovné odeslání kódu.

ThreeDSLabelStyle

Přizpůsobení textových popisků.

ParametrTypPopis
headingTextColorString?Barva nadpisu.
headingTextFontSizeInt?Velikost nadpisu v sp (8–48).
textColorString?Barva běžného textu.
textFontSizeInt?Velikost běžného textu v sp (8–48).

ThreeDSTextBoxStyle

Přizpůsobení vstupních polí na challenge obrazovce.

ParametrTypPopis
borderWidthInt?Šířka ohraničení v dp (0–10).
borderColorString?Barva ohraničení.
cornerRadiusInt?Zaoblení rohů v dp.
textColorString?Barva textu.
textFontSizeInt?Velikost textu v sp (8–48).

ThreeDSToolbarStyle

Přizpůsobení toolbaru challenge obrazovky.

ParametrTypPopis
backgroundColorString?Barva pozadí toolbaru.
headerTextString?Text v hlavičce toolbaru.
buttonTextString?Text tlačítka v toolbaru (typicky „Zrušit").
textColorString?Barva textu.
textFontSizeInt?Velikost textu v sp (8–48).
Informace

Barvy se zadávají jako řetězce ve formátu #RRGGBB nebo #AARRGGBB. Neplatné formáty jsou v runtime ignorovány a použijí se výchozí hodnoty.

Motivy challenge okna

Knihovna obsahuje čtyři předdefinované motivy pro zobrazení challenge obrazovky:

MotivPopis
Theme.ComgateSdk.3DS.DialogSvětlý dialog (90 % šířky obrazovky, centrovaný) — výchozí
Theme.ComgateSdk.3DS.Dialog.DarkTmavý dialog
Theme.ComgateSdk.3DS.FullScreenSvětlý celoobrazovkový režim
Theme.ComgateSdk.3DS.FullScreen.DarkTmavý celoobrazovkový režim

Pro přepnutí motivu stačí přidat do res/values/styles.xml vaší aplikace přepis stylu Theme.ComgateSdk.3DS.Challenge:

<!-- res/values/styles.xml -->
<style name="Theme.ComgateSdk.3DS.Challenge"
parent="Theme.ComgateSdk.3DS.FullScreen" />
Tip

Zaoblení rohů dialogového okna lze přizpůsobit definováním dimenze securefields_3ds_dialog_corner_radius v resources vaší aplikace:

<!-- res/values/dimens.xml -->
<dimen name="securefields_3ds_dialog_corner_radius">16dp</dimen>

Alternativně lze zaoblení nastavit programaticky přes parametr challengeWindowCornerRadiusDpThreeDSConfig.

Testování 3DS plateb

Pro usnadnění vývoje a testování nabízí knihovna v dev režimu (devMode = true) možnost simulovat různé průběhy 3DS autentizace bez nutnosti použít skutečnou bankovní kartu.

Testovací chování se řídí parametrem require3dsPaymentParams:

Hodnota require3dsPrůběh platby
trueServer vrátí challenge — zobrazí se 3DS challenge obrazovka, uživatel musí zadat OTP nebo provést ověření.
falseServer vrátí frictionless výsledek — platba proběhne bez zobrazení challenge obrazovky.
null (výchozí)Server rozhodne sám; v produkci standardní chování.
Upozornění

Parametr require3ds je funkční výhradně 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. Knihovna zobrazí 3DS challenge obrazovku, kde uživatel provede ověření. Výsledek platby bude záviset na akci uživatele:

  • 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 — pouze devMode
)
},
modifier = Modifier.fillMaxWidth()
)

Simulace frictionless průběhu

Nastavte require3ds = false. Platba proběhne bez zobrazení challenge obrazovky — autentizace je vyhodnocena serverem v pozadí. Výsledkem je PaymentResult.Paid, pokud 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 — pouze devMode
)
},
modifier = Modifier.fillMaxWidth()
)

Simulace chybového důvodu — ErrorReason

dev režimu (devMode = true) lze pomocí parametru errorReasonPaymentParams simulovat konkrétní důvod zamítnutí nebo 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ů — pouze devMode
)
},
modifier = Modifier.fillMaxWidth()
)
Upozornění

Parametr errorReason je funkční výhradně v dev režimu (devMode = true).
Hodnota (včetně null) je vždy předána serveru, pokud běžíte v dev módu.
V produkci je tento parametr zcela ignorován.

Dostupné hodnoty výčtu ErrorReason:

HodnotaPopis
CUSTOMER_CLICKZrušeno plátcem.
FRAUD_SUSPECTEDPodezření na podvod.
ESHOP_CANCELLEDZrušeno obchodníkem.
PROVIDER_REPORTZrušeno providerem.
PROVIDER_TIMEOUTVypršel časový limit poskytovatele.
CUSTOMER_TIMEOUTVypršel časový limit platby.
ACS_TIMEOUTVypršel časový limit pro ověření.
INVALID_CARDNO_EXPIRYChybně zadané číslo karty nebo datum platnosti karty.
INVALID_CVCChybně zadaný CVC / CVV kód.
LIMIT_EXCEEDEDLimit karty byl překročen.
NO_FUNDSNa účtu není dostatečný zůstatek.
REJECTED_BY_BANKPlatba byla zamítnuta bankou.
3DS_AUTH_FAILOvěření 3DS nebylo úspěšné.
NOT_SPECIFIEDNespecifikováno.

Kompletní příklad

Následující příklad ukazuje kompletní implementaci karetní platby s 3D Secure od inicializace po zpracování 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. Vytvoření 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. Nastavení Compose UI
setContent {
MaterialTheme {
Surface(modifier = Modifier.fillMaxSize()) {
PaymentScreen(session)
}
}
}
}
}

@Composable
private fun PaymentScreen(session: ComgateSecureSession) {
// 4. Stav polí — raw karetní data 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čítko
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é
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)
)
}
}