Funciones avanzadas SDK para Android

Configuración avanzada e integraciones personalizadas para Android.

Opciones de montaje alternativas

El flujo básico utiliza la visualización automática pago . Para un mayor control, utiliza estas alternativas:

Selección de pago personalizado (startPaymentLite)

Controla qué pago mostrar:

// 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) }
    }
)

Flujo simplificado (startPaymentSeamlessLite)

Similar a Lite, pero con pago automática pago :

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

Inscripción (Guardar tarjetas)

Ahorra durante pago

// 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"
)

Inscripción por separado

// 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 almacenados

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

Interfaz de usuario personalizada (integración sin interfaz gráfica)

Crea pago totalmente personalizados con control total de la interfaz de usuario cuando necesites un control completo sobre cada elemento de la interfaz, experiencias de pago altamente personalizadas o dispongas de recursos de desarrollo para una interfaz de usuario personalizada.

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. Recopila los datos de la tarjeta en tu interfaz de usuario personalizada
    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. Crea pago  token
 token
    createPayment(token.oneTimeToken)
    
    // 4. Gestionar la continuación si es necesario
    apiClient.continuePayment(
        activity = this@PaymentActivity,
        onPaymentResult = { result ->
            handlePaymentResult(result)
        }
    )
}

Con Token almacenado

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

Integración del modo de renderizado

Muestra pago dentro de tu vista personalizada.

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()
        }
    }
}

Estilo

Personaliza la apariencia del SDK con temas.

colores.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>

Aplicar tema:

Yuno.setTheme(R.style.YunoSDKTheme)

Escaneado de tarjetas (OCR)

Activa el escaneo de tarjetas con la cámara.

Añadir dependencia:

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

Habilitar en la configuración:

Yuno.initialize(
    this,
    publicApiKey = "tu-clave",
    config = YunoConfig(
        cardScanEnabled = true
    )
)

El botón para escanear tarjetas aparece automáticamente en el formulario de tarjetas.

Integración con ClearSale

Habilita la prevención de fraudes.

Añadir SDK de 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 de ClearSale fingerprint recopila y envía automáticamente.

Gestión de errores

Gestionar los errores en la devolución de llamada pago y en pago :

// 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}")
            }
        }
    }
)

Pruebas y depuración

Habilitar registro

Yuno.setLogLevel(LogLevel.VERBOSE)

Modo de prueba

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

Actuación

Inicialización diferida

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

Precarga el SDK

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

Retorno del navegador externo (enlaces profundos)

Gestiona los usuarios que regresan a tu aplicación después de pago externos, como desafíos de autenticación 3DS, redireccionamientos de transferencias bancarias, pagos PIX y pago alternativos con redireccionamientos externos.

1. Establece callback_url en la sesión de pago.

Incluir callback_url al crear la sesión de pago en tu backend:

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

Importante

Sin callback_url, los usuarios pueden quedarse atrapados en el navegador externo sin posibilidad de volver a la aplicación.

2. Configurar el manejo de enlaces profundos

Añadir un intent-filter a tu actividad en 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>

El régimen (myapp) y anfitrión (return) deben coincidir con su callback_url.

3. Gestionar la intención de devolución

Gestiona el enlace profundo cuando el usuario regresa:

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. Ejemplo de integración completa

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")
    }
}

Mejores prácticas

  • Incluye siempre callback_url en pago que pueden redirigir
  • Prueba el manejo de enlaces profundos en múltiples dispositivos y versiones de Android.
  • Manejar con elegancia los datos de enlaces profundos que faltan o están mal formados.
  • Actualiza pago en tu interfaz de usuario después de volver del navegador externo.