Fonctionnalités avancées SDK Android

Configuration avancée et intégrations personnalisées pour Android.

Options de montage alternatives

Le flux de base utilise l'affichage automatique des modes de paiement. Pour plus de contrôle, utilisez ces alternatives :

Sélection d'un mode de paiement personnalisé (startPaymentLite)

Contrôlez le mode de paiement à afficher :

// 1. Fetch available methods
val methods = fetchPaymentMethods(sessionId)

// 2. Display in your UI
// 3. Start payment with selected method

startPaymentLite(
    paymentMethodType = selectedMethod, // "CARD", "PIX", etc.
    vaultedToken = null,
    showPaymentStatus = true,
    callbackOTT = { token ->
        token?.let { createPayment(it, checkoutSession) }
    }
)

Flux simplifié (startPaymentSeamlessLite)

Similaire à Lite, mais avec création automatique des paiements :

startPaymentSeamlessLite(
 paymentMethodType "CARD",
 vaultedToken  null,
 showPaymentStatus  true
)

Inscription (enregistrer les cartes)

Enregistrer pendant le paiement

// When creating payment on backend, include vault_on_success flag
suspend fun createPayment(token: String, checkoutSession: String) {
    apiClient.post("/payment/create", mapOf(
        "one_time_token" to token,
        "checkout_session" to checkoutSession,
        "vault_on_success" to true // Save after successful payment
    ))
}

// Configure SDK to show save checkbox
startCheckout(
    callbackPaymentState = { state -> handlePaymentState(state) }
)

// Update with session - SDK will show "Save card" checkbox automatically
updateCheckoutSession(
    checkoutSession = session.checkoutSession,
    countryCode = "US"
)

Inscription séparée

// Create customer session on backend
val customerSession = createCustomerSession("cus_123")

// Start enrollment
initEnrollment(
    customerSession = customerSession.id,
    countryCode = "US"
)

// Start enrollment flow
startEnrollment(
    showEnrollmentStatus = true,
    callback = { vaultedToken ->
        vaultedToken?.let {
            println("Card saved: $it")
        }
    }
)

Token voûtés

startPaymentLite(
 paymentMethodType "CARD",
 vaultedToken "vtok_saved_card_123",
 showPaymentStatus  true,
 callbackOTT { token >
 token?.let { createPayment(it, checkoutSession) }
    }
)

Interface utilisateur personnalisée (intégration sans interface graphique)

Créez des formulaires de paiement entièrement personnalisés avec un contrôle total de l'interface utilisateur lorsque vous avez besoin d'un contrôle complet sur chaque élément de l'interface utilisateur, d'expériences de paiement hautement personnalisées ou que vous disposez de ressources de développement pour une interface utilisateur personnalisée.

import com.yuno.sdk.Yuno
import com.yuno.sdk.api.ApiClientPayment

lifecycleScope.launch {
    // 1. Initialize 
    val apiClient = Yuno.apiClientPayment(
 countryCode "US",
 checkoutSession "session_id"
    )
    
    // 2. Collectez les données de la carte dans votre interface utilisateur personnalisée.
    val token  apiClient.generateToken(
 checkoutSession "session_id",
        paymentMethod = PaymentMethod(
            type = "CARD",
            card = CardData(
                number = "4111111111111111",
                expirationMonth = 12,
                expirationYear = 25,
                securityCode = "123",
                holderName = "John Doe",
                type = "CREDIT"
            )
        )
    )
    
    // 3. Créer un paiement avec token
 
    createPayment(token.oneTimeToken)
    
    // 4. Gérer la continuation si nécessaire
    apiClient.continuePayment(
        activity = this@PaymentActivity,
        onPaymentResult = { result ->
            handlePaymentResult(result)
        }
    )
}

Avec Token voûté

val token  apiClient.generateToken(
 checkoutSession "session_id",
    paymentMethod = PaymentMethod(
        type = "CARD",
 vaultedToken "saved_token_id",
        card = CardData(securityCode = "123")
    )
)

Intégration du mode de rendu

Affichez le formulaire de paiement dans votre vue personnalisée.

class PaymentActivity : ComponentActivity(), YunoPaymentRenderListener {
    
    private lateinit var paymentController: YunoPaymentFragmentController
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        setContent {
            var paymentView by remember { mutableStateOf<View?>(null) }
            
            Column {
                Button(onClick = { startRenderMode() }) {
                    Text("Pay Now")
                }
                
                paymentView?.let {
                    AndroidView(factory = { it })
                }
            }
        }
    }
    
    private fun startRenderMode() {
        lifecycleScope.launch {
            val session = createCheckoutSession()
            
            paymentController = Yuno.startPaymentRender(
                activity = this@PaymentActivity,
                checkoutSession = session.id,
                countryCode = "US",
                listener = this@PaymentActivity
            )
        }
    }
    
    override fun onFormView(view: View) {
        // Add view to your layout
        findViewById<FrameLayout>(R.id.payment_container).addView(view)
    }
    
    override fun onSubmitForm() {
        // Customer submitted form
    }
    
    override fun onPaymentResult(result: PaymentResult) {
        if (result.status == PaymentStatus.SUCCEEDED) {
            navigateToSuccess()
        }
    }
}

Stylisme

Personnalisez l'apparence du SDK à l'aide de thèmes.

couleurs.xml :

<color name="yuno_primary">#007bff</color>
<color name="yuno_background">#ffffff</color>
<color name="yuno_text">#333333</color>
<color name="yuno_error">#dc3545</color>

themes.xml :

<style name="YunoSDKTheme" parent="Theme.MaterialComponents">
    <item name="colorPrimary">@color/yuno_primary</item>
    <item name="colorOnPrimary">@android:color/white</item>
    <item name="android:textColor">@color/yuno_text</item>
</style>

Appliquer le thème :

Yuno.setTheme(R.style.YunoSDKTheme)

Numérisation de cartes (OCR)

Activer la lecture de carte avec l'appareil photo.

Ajouter une dépendance :

dependencies {
    implementation("com.yuno.sdk:card-scan:2.8.1")
}

Activer dans la configuration :

Yuno.initialize(
    this,
    publicApiKey = "your-key",
    config = YunoConfig(
        cardScanEnabled = true
    )
)

Le bouton de numérisation de carte apparaît automatiquement sous forme de carte.

Intégration ClearSale

Activer la prévention contre la fraude.

Ajouter le SDK ClearSale :

dependencies {
    implementation("br.com.clearsale:cs-android-sdk:4.0.0")
}

Initialize:

import br.com.clearsale.androidsdk.ClearSale

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        
        // Initialize ClearSale
        ClearSale.init(this, "your-clearsale-app-key")
        
        // Initialize Yuno
        Yuno.initialize(this, "your-public-key", YunoConfig())
    }
}

fingerprint ClearSale fingerprint automatiquement collectée et envoyée.

Gestion des erreurs

Gérer les erreurs dans le rappel d'état de paiement et le traitement des paiements :

// Set up error handling in payment state callback
startCheckout(
    callbackPaymentState = { state ->
        when (state) {
            "SUCCEEDED" -> handleSuccess()
            "FAIL" -> {
                // Handle payment failure
                showError("Payment failed")
            }
            "REJECT" -> {
                // Handle payment rejection
                showRejectedMessage()
            }
            "PROCESSING" -> showPendingMessage()
            else -> {}
        }
    }
)

// Update session with error handling
try {
    val session = createCheckoutSession()
    updateCheckoutSession(
        checkoutSession = session.checkoutSession,
        countryCode = "US"
    )
} catch (e: Exception) {
    Log.e("Payment", "Session error: ${e.message}")
    showError("Failed to initialize payment")
}

// Handle errors during payment creation
startPayment(
    showStatusYuno = true,
    callbackOTT = { token ->
        lifecycleScope.launch {
            try {
                createPayment(token, checkoutSession)
            } catch (e: Exception) {
                Log.e("Payment", "Payment creation error: ${e.message}")
                showError("Payment failed: ${e.message}")
            }
        }
    }
)

Test et débogage

Activer la journalisation

Yuno.setLogLevel(LogLevel.VERBOSE)

Mode test

Yuno.initialize(
    this,
    publicApiKey = "pk_test_your_key",
    config = YunoConfig(testMode = true)
)

Performance

Initialisation paresseuse

val yuno by lazy {
    Yuno.initialize(this, "pk_test_key", YunoConfig())
    Yuno.getInstance()
}

Précharger le SDK

lifecycleScope.launch(Dispatchers.IO) {
    Yuno.preload(this@MainActivity)
}

Retour du navigateur externe (liens profonds)

Gérez les utilisateurs qui reviennent sur votre application après des flux de paiement externes tels que les défis d'authentification 3DS, les redirections de virement bancaire, les paiements PIX et les méthodes de paiement alternatives avec redirections externes.

1. Définir callback_url dans la session de paiement

Inclure callback_url lors de la création de la session de paiement sur votre backend :

{
  "callback_url": "myapp://return"
}
❗️

Important

Sans callback_url, les utilisateurs peuvent se retrouver bloqués dans le navigateur externe sans pouvoir revenir à votre application.

2. Configurer la gestion des liens profonds

Ajoutez un intent-filter à votre activité dans AndroidManifest.xml:

<activity android:name=".YourMainActivity">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="myapp"
            android:host="return" />
    </intent-filter>
</activity>

Le régime (myapp) et le host (return) doivent correspondre à votre callback_url.

3. Traiter l'intention de retour

Gérer le lien profond lorsque l'utilisateur revient :

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    // Check if app was opened via deep link
    intent.data?.let { uri ->
        val url = uri.toString()
        if (url.contains("myapp://return")) {
            handlePaymentReturn(uri)
        }
    }
}

private fun handlePaymentReturn(uri: Uri) {
    val sessionId = uri.getQueryParameter("checkoutSession")
    
    sessionId?.let {
        continuePayment(
            showPaymentStatus = true,
            checkoutSession = it,
            countryCode = "US"
        ) { result ->
            result?.let { status ->
                Toast.makeText(this, "Payment status: $status", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

4. Exemple d'intégration complète

class PaymentActivity : ComponentActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Initialize checkout
        startCheckout(
            callbackPaymentState = { state ->
                handlePaymentState(state)
            }
        )
        
        // Handle deep link return
        if (intent?.data != null) {
            handleDeepLinkReturn(intent)
        } else {
            // Normal payment flow
            initializePaymentUI()
        }
    }
    
    private fun handleDeepLinkReturn(intent: Intent) {
        intent.data?.let { uri ->
            if (uri.toString().contains("myapp://return")) {
                val sessionId = extractCheckoutSession(uri)
                
                sessionId?.let {
                    continuePayment(
                        showPaymentStatus = true,
                        checkoutSession = it,
                        countryCode = "US"
                    ) { result ->
                        when (result) {
                            "SUCCEEDED" -> navigateToSuccess()
                            "FAILED" -> showError("Payment failed")
                            else -> showPendingMessage()
                        }
                    }
                }
            }
        }
    }
    
    private fun extractCheckoutSession(uri: Uri): String? {
        return uri.getQueryParameter("checkoutSession")
    }
}

Meilleures pratiques

  • Toujours inclure callback_url dans les flux de paiement susceptibles d'être redirigés
  • Testez la gestion des liens profonds sur plusieurs appareils et versions Android.
  • Gérer correctement les données de liens profonds manquantes ou mal formées
  • Mettre à jour le statut de paiement dans votre interface utilisateur après être revenu d'un navigateur externe