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 tři specializované komponenty pro zadávání karetních údajů:
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 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()
)
Společné vlastnosti
Všechny Secure Fields sdílejí tyto vlastnosti a metody:
| Vlastnost / Metoda | Typ | Popis |
|---|---|---|
isFieldValid | Boolean | Aktuální stav validace pole (read-only). |
onValidationChanged | (Boolean) -> Unit | Callback volaný při změně validačního stavu. |
setHint(hint) | String | Nastaví placeholder text. |
setEnabled(enabled) | Boolean | Povolí/zakáže pole. |
clear() | — | Vymaže obsah pole a resetuje validaci. |
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í
}
)
| Vlastnost / Metoda | Typ | Popis |
|---|---|---|
isValid | Boolean | true pokud jsou všechna tři pole validní. |
onValidationChanged | (Boolean) -> Unit | Callback 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(
price = 100,
curr = "CZK",
label = "Název 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 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
| Parametr | Typ | Povinný | Popis |
|---|---|---|---|
price | Int | Ano | Částka platby v haléřích/centech (např. 10000 = 100,00 CZK). |
curr | String | Ano | Kód měny — ISO 4217 (např. "CZK", "EUR"). |
label | String | Ano | Krátký popis produktu (1–16 znaků). |
refId | String | Ano | Variabilní symbol nebo číslo objednávky (vaše interní ID). |
fullName | String | Ano | Jméno a příjmení plátce. |
country | String? | Ne | Kód země dle ISO 3166-1 alpha-2 (např. "CZ", "SK"). Výchozí: "CZ". |
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 | Předautorizace karty (true pro předautorizaci). Pouze kartové platby. |
initRecurring | Boolean? | Ne | Iniciální rekurentní transakce (true pro první opakovanou platbu). |
verification | Boolean? | Ne | Verifikační platba (true pro ověřovací platbu). |
expirationTime | String? | Ne | Doba expirace platby (např. "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 při delivery = "HOME_DELIVERY"). |
homeDeliveryStreet | String? | Ne | Doručovací adresa — ulice (jen při delivery = "HOME_DELIVERY"). |
homeDeliveryPostalCode | String? | Ne | Doručovací adresa — PSČ (jen při delivery = "HOME_DELIVERY"). |
homeDeliveryCountry | String? | Ne | Doručovací adresa — kód země (jen při delivery = "HOME_DELIVERY"). |
category | String? | Ne | Kategorie produktu ("PHYSICAL_GOODS_ONLY", "OTHER"). |
urlPaid | String? | Ne | URL pro přesměrování po úspěšné platbě. |
urlCancelled | String? | Ne | URL pro přesměrování po zrušení platby. |
urlPending | String? | Ne | URL pro přesměrování u čekající platby. |
chargeUnregulatedCardFees | Boolean? | Ne | Účtování neregulovaných karetních poplatků (true pro zapnutí). Deaktivuje Apple Pay / Google Pay. |
enableApplePayGooglePay | Boolean? | Ne | Povolení Apple Pay / Google Pay pro tuto platbu (true / false). Přepíše chargeUnregulatedCardFees. |
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. |
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(
price = 100,
curr = "CZK",
label = "Název 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čí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.
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
fun processPayment(
activity: Activity,
collector: SecureCardDataCollector,
params: PaymentParams,
callback: (PaymentResult) -> Unit
)
| 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.). |
callback | (PaymentResult) -> Unit | Callback volaný na hlavním vlákně s výsledkem platby. |
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",
email = "zakaznik@example.com",
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
}
)
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 = {
isProcessing = true
session.processPayment(
activity = activity,
collector = collector,
params = PaymentParams(
price = 100,
curr = "CZK",
label = "Objednávka #123",
refId = "order-123",
fullName = "Jan Novák"
)
) { result ->
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)
)
}
}
Před voláním processPayment se ujistěte, že:
- Session je úspěšně inicializovaná (callback
onInitializedvrátilResult.success). - 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(
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
Knihovna poskytuje kompletní podporu 3D Secure autentizace. Pokud je 3DS nakonfigurováno, knihovna automaticky:
- Připraví autentizační parametry při zpracování platby
- Vyhodnot í odpověď serveru (frictionless / challenge)
- V případě potřeby zobrazí challenge obrazovku
- 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",
email = "zakaznik@example.com",
context = applicationContext,
threeDSConfig = threeDSConfig,
lifecycleOwner = this
)
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(nethis— Fragment přežívá opětovné vytvoření view a způsobilo by memory leak)
Parametry ThreeDSConfig
| Parametr | Typ | Výchozí | Popis |
|---|---|---|---|
uiCustomization | ThreeDSUiCustomization? | null | Přizpůsobení vzhledu challenge obrazovky. Pokud je null, použijí se výchozí 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. 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.
| Parametr | Typ | Popis |
|---|---|---|
backgroundColor | String? | Barva pozadí ve formátu #RRGGBB nebo #AARRGGBB. |
cornerRadius | Int? | Zaoblení rohů tlačítka v dp. |
textColor | String? | Barva textu ve formátu #RRGGBB nebo #AARRGGBB. |
textFontSize | Int? | Velikost písma v sp (8–48). |
Tlačítka se konfigurují v mapě dle typu:
| Typ tlačítka | 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? | Barva nadpisu. |
headingTextFontSize | Int? | Velikost nadpisu v sp (8–48). |
textColor | String? | Barva 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? | Šířka ohraničení v dp (0–10). |
borderColor | String? | Barva ohraničení. |
cornerRadius | Int? | Zaoblení rohů v dp. |
textColor | String? | Barva textu. |
textFontSize | Int? | Velikost textu v sp (8–48). |
ThreeDSToolbarStyle
Přizpůsobení toolbaru challenge obrazovky.
| Parametr | Typ | Popis |
|---|---|---|
backgroundColor | String? | Barva pozadí toolbaru. |
headerText | String? | Text v hlavičce toolbaru. |
buttonText | String? | Text tlačítka v toolbaru (typicky „Zrušit"). |
textColor | String? | Barva textu. |
textFontSize | Int? | Velikost textu v sp (8–48). |
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:
| Motiv | Popis |
|---|---|
Theme.ComgateSdk.3DS.Dialog | Světlý dialog (90 % šířky obrazovky, centrovaný) — výchozí |
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ší 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ší aplikace:
<!-- res/values/dimens.xml -->
<dimen name="securefields_3ds_dialog_corner_radius">16dp</dimen>
Alternativně lze zaoblení nastavit programaticky přes parametr challengeWindowCornerRadiusDp v ThreeDSConfig.
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 require3ds v PaymentParams:
Hodnota require3ds | Průběh platby |
|---|---|
true | Server vrátí challenge — zobrazí se 3DS challenge obrazovka, uživatel musí zadat OTP nebo provést ověření. |
false | Server vrátí frictionless výsledek — platba proběhne bez zobrazení challenge obrazovky. |
null (výchozí) | Server rozhodne sám; v produkci standardní chová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(
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(
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()
)
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",
email = "zakaznik@example.com",
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(
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)
)
}
}