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)
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)
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"
}
ImportanteSin
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_urlen 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.
Actualizado hace 1 día