Funciones avanzadas SDK para iOS

Configuración avanzada e integraciones personalizadas para iOS.

Opciones de montaje alternativas

El flujo básico utiliza Yuno.startPayment() que gestiona automáticamente todo el pago . Para tener más control, utiliza estas alternativas:

Selección de pago personalizado (startPaymentLite)

Selecciona qué pago mostrar. Tu delegado debe implementar YunoPaymentFullDelegate con las propiedades requeridas:

class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
    var checkoutSession: String { return _checkoutSession }
    var countryCode: String { "US" }
    var language: String? { "en" }
    var viewController: UIViewController? { self }
    
    private var _checkoutSession: String = ""
    
    func setupPayment() async {
        // 1. Create session
        let session = await createCheckoutSession()
        _checkoutSession = session.checkoutSession
        
        // 2. Fetch available methods
        let methods = await fetchPaymentMethods(sessionId: checkoutSession)
        
        // 3. Display in your UI, then start payment with selected method
        Yuno.startPaymentLite(
            paymentMethodType: selectedMethod, // "CARD", "PIX", etc.
            vaultedToken: nil, // or saved token
            delegate: self
        )
    }
}

Flujo simplificado (startPaymentSeamlessLite)

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

Yuno.startPaymentSeamlessLite(
 paymentMethodType: "CARD",
 vaultedToken: nil,
    delegate: self
)

Inscripción (Guardar tarjetas)

Ahorra durante pago

Tu delegado proporciona la información de la sesión a través de las propiedades:

class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
    var checkoutSession: String { _checkoutSession }
    var countryCode: String { "US" }
    var language: String? { "en" }
    var viewController: UIViewController? { self }
    
    private var _checkoutSession: String = ""
    
    func setupPayment() async {
        let session = await createCheckoutSession()
        _checkoutSession = session.checkoutSession
        
        // Start payment - SDK will show save card checkbox automatically
        Yuno.startPayment()
    }
    
    // In delegate:
    func yunoCreatePayment(with token: String, information: [String: Any]) {
        Task {
            await createPayment(
                token: token,
                vaultOnSuccess: true // Save after successful payment
            )
            Yuno.continuePayment(showPaymentStatus: true)
        }
    }
}

Inscripción por separado

class EnrollmentViewController: UIViewController, YunoEnrollmentDelegate {
    var customerSession: String { _customerSession }
    var countryCode: String { "US" }
    var language: String? { "en" }
    var viewController: UIViewController? { self }
    
    private var _customerSession: String = ""
    
    func setupEnrollment() async {
        // Create customer session on backend
        let session = await createCustomerSession(customerId: "cus_123")
        _customerSession = session.id
        
        // Start enrollment - SDK reads session from delegate
        Yuno.enrollPayment(delegate: self)
    }
    
    func yunoEnrollmentStatus(status: Yuno.EnrollmentStatus, vaultedToken: String?) {
        if status == .successful, let token = vaultedToken {
            print("Card saved:", token)
        }
    }
    
    func yunoDidSelect(enrollmentMethod: EnrollmentMethodSelected) {
        print("Selected enrollment method:", enrollmentMethod)
    }
}

Token almacenados

Utiliza las tarjetas guardadas proporcionando el token almacenado en la bóveda token startPaymentLite:

class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
    var checkoutSession: String { _checkoutSession }
    var countryCode: String { "US" }
    var language: String? { "en" }
    var viewController: UIViewController? { self }
    
    private var _checkoutSession: String = ""
    
    func payWithSavedCard(vaultedToken: String) {
        Yuno.startPaymentLite(
            paymentMethodType: "CARD",
            vaultedToken: vaultedToken,
            delegate: self
        )
    }
}

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 YunoSDK

class CustomPaymentVC: UIViewController {
    
    func processWithCustomUI() async {
        // 1. Initialize headless client
        let apiClient = Yuno.apiClientPayment(
            countryCode: "US",
            checkoutSession: "session_id"
        )
        
        // 2. Collect card data in your custom UI
        let cardData = CardData(
            number: "4111111111111111",
            expirationMonth: 12,
            expirationYear: 25,
            securityCode: "123",
            holderName: "John Doe",
            type: .credit
        )
        
        // 3. Generate token
        do {
            let result = try await apiClient.generateToken(data: TokenCollectedData(
                checkoutSession: "session_id",
                paymentMethod: CollectedData(
                    type: "CARD",
                    card: cardData
                )
            ))
            
            // 4. Create payment with token
            await createPayment(token: result.token)
            
            // 5. Handle continuation if needed
            if apiClient.shouldContinue {
                try await apiClient.continuePayment()
            }
        } catch {
            print("Error: \(error)")
        }
    }
}

Con Token almacenado

let resultado = try await apiClient.generateToken(datos: TokenCollectedData(
 checkoutSession: "session_id",
    método de pago: CollectedData(
        tipo: "CARD",
 vaultedToken: "saved_token_id",
        tarjeta: CardData(código de seguridad: "123")
    )
))

Integración del modo de renderizado

Muestra pago dentro de tu vista personalizada.

class PaymentViewController: UIViewController, YunoPaymentRenderFlowProtocol {
    
    func startRenderMode() async {
        let session = try await createCheckoutSession()
        
        let config = YunoConfig(
            checkoutSession: session.id,
            countryCode: "US"
        )
        
        Yuno.startPaymentRenderFlow(with: config, delegate: self)
    }
    
    // SDK provides view to embed
    func formView() -> UIView? {
        let containerView = UIView(frame: CGRect(x: 0, y: 0, width: 350, height: 500))
        containerView.backgroundColor = .systemBackground
        return containerView
    }
    
    // Handle form submission
    func submitForm() async {
        // Customer submitted payment form
    }
    
    // Handle result
    func yunoPaymentResult(_ result: PaymentResult) {
        if result.status == .succeeded {
            navigateToSuccess()
        }
    }
}

SwiftUI:

struct RenderModeView: View, YunoPaymentRenderFlowProtocol {
    @State private var paymentView: UIView?
    
    var body: some View {
        if let view = paymentView {
            PaymentViewWrapper(view: view)
                .frame(height: 500)
        }
    }
    
    func startPayment() async {
        let config = YunoConfig(checkoutSession: "session_id", countryCode: "US")
        await Yuno.startPaymentRenderFlow(with: config, delegate: self)
    }
    
    func formView() -> UIView? {
        let view = UIView()
        DispatchQueue.main.async {
            paymentView = view
        }
        return view
    }
}

struct PaymentViewWrapper: UIViewRepresentable {
    let view: UIView
    
    func makeUIView(context: Context) -> UIView { view }
    func updateUIView(_ uiView: UIView, context: Context) {}
}

Estilo y apariencia

Personaliza la apariencia del SDK con Yuno.Appearance:

import YunoSDK

func configureAppearance() {
    var appearance = Yuno.Appearance()
    
    // Colores
    appearance.primaryColor = UIColor.systemBlue
    appearance.backgroundColor = UIColor.systemBackground
    appearance.textColor = UIColor.label
    appearance.errorColor = UIColor.systemRed
    
    // Tipografía
    appearance.fontFamily = "SF Pro Display"
    appearance.fontSize = 16
    
    // Radio de esquina
    appearance.cornerRadius = 12
    
    // Aplicar
    Yuno.setAppearance(appearance)
}

Concurrencia en Swift 6

Maneja las advertencias de concurrencia con las anotaciones adecuadas:

@MainActor
class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
    var checkoutSession: String { _checkoutSession }
    var countryCode: String { "US" }
    var language: String? { "en" }
    var viewController: UIViewController? { self }
    
    private var _checkoutSession: String = ""
    
    // Safe to call from any thread
    nonisolated func startPayment() {
        Task { @MainActor in
            Yuno.startPayment()
        }
    }
    
    // UI updates on main thread
    @MainActor
    func yunoPaymentResult(_ result: PaymentResult) {
        updateUI(result)
    }
}

Delegado no aislado:

extension PaymentViewController {
    nonisolated func yunoPaymentResult(_ result: PaymentResult) {
        MainActor.assumeIsolated {
            // UI updates here
            self.showResult(result)
        }
    }
}

Integración con ClearSale

Habilita la prevención de fraudes:

Instala el SDK de ClearSale:

pod 'ClearSaleSDK'

Initialize:

import ClearSale

func application(_ application: UIApplication, 
                didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    // Initialize ClearSale
    ClearSale.setup(apiKey: "your-clearsale-key")
    
    // Initialize Yuno
    Yuno.initialize(apiKey: "your-public-key")
    
    return true
}

Los datos de ClearSale se recopilan automáticamente y se envían junto con los pagos.

Configuración personalizada

Tipos de flujo de tarjetas

Configura el flujo de entrada de tarjetas durante la inicialización de Yuno:

// In AppDelegate or App struct
Yuno.initialize(
    apiKey: "your-public-key",
    cardFlow: .oneStep // or .stepByStep
)

Ocultar nombre del titular de la tarjeta

Configurar la visibilidad del nombre del titular de la tarjeta:

// Set globally
Yuno.hideCardholderName = true

Mostrar/ocultar la pantalla de estado

Pantalla de control pago en continuePayment():

func yunoCreatePayment(with token: String, information: [String: Any]) {
    Task {
        await createPayment(token: token)
        Yuno.continuePayment(showPaymentStatus: false) // Handle result yourself
    }
}

Gestión de errores

func yunoPaymentResult(_ result: PaymentResult) {
    switch result.status {
    case .succeeded:
        handleSuccess(result)
    case .failed:
        handleFailure(result.error)
    case .pending:
        handlePending(result)
    case .rejected:
        handleRejection(result)
    }
}

func handleFailure(_ error: YunoError?) {
    guard let error = error else { return }
    
    switch error.code {
    case "SESSION_EXPIRED":
        // Recreate session
        Task { await createNewSession() }
    case "INVALID_CARD":
        showAlert("Please check your card details")
    case "INSUFFICIENT_FUNDS":
        showAlert("Insufficient funds")
    case "NETWORK_ERROR":
        showAlert("Connection error. Please try again.")
    default:
        showAlert("Payment failed: \(error.message)")
    }
}

Webhooks

Verificar pago en el backend:

// Backend receives webhook
POST /webhooks/yuno
{
  "type": "payment.succeeded",
  "data": {
    "payment_id": "pay_123",
    "status": "SUCCEEDED",
    "amount": 2500
  }
}

Pruebas

Modo de prueba

// Use test key
Yuno.initialize(apiKey: "pk_test_your_key")

Registro de depuración

// Enable logs in development
#if DEBUG
Yuno.setLogLevel(.verbose)
#endif

Actuación

Precarga el SDK

// Preload in background
Task(priority: .background) {
    _ = Yuno.self
}

Carga diferida

// Load only when needed
lazy var yuno: Yuno = {
    Yuno.initialize(apiKey: "pk_test_key")
    return Yuno.shared
}()