Lite SDK (Pago iOS)


👍

SDK recomendado

Recomendamos utilizar el Seamless SDK iOS para una experiencia de integración sin problemas. Esta opción ofrece una solución de pago flexible con componentes de interfaz de usuario predefinidos y opciones de personalización.

Esta guía te guiará a través de la integración del Lite iOS SDK de Yuno para pagos en tu proyecto.

Requisitos

Antes de implementar el SDK de Yuno para iOS, asegúrate de que cumples estos requisitos:

Paso 1: Incluya la biblioteca en tu proyecto

Puede agregar la biblioteca usando CocoaPods o Swift Package Manager.

CocoaPods

Añade el SDK de Yuno a tu proyecto iOS usando CocoaPods. Si no tienes un Podfile, sigue la guía de CocoaPods para crear uno. Después añade la siguiente línea a tu Podfile:

pod 'YunoSDK', '~> 1.1.22'

A continuación, ejecute la instalación:

instalar pod

Administrador de Paquetes Swift

Añade el SDK de Yuno utilizando Swift Package Manager. Añade YunoSDK como dependencia en tu archivo Package.swift:

dependencias: [
    .package(url: "https://github.com/yuno-payments/yuno-sdk-ios.git", .upToNextMajor(from: "1.1.17"))
]

Paso 2: Initialize el SDK con la clave pública

Initialize el SDK de Yuno para iOS con tu Clave Pública de la API:

import YunoSDK

Yuno.initialize(
    apiKey: "PUBLIC_API_KEY",
    config: YunoConfig(),
    callback: { (value: Bool) in }
)
🚧

UISceneDelegate

Si tu aplicación utiliza un UISceneDelegate, deberá colocar el código de inicialización de Yuno en su SceneDelegate.

Configura la apariencia y el comportamiento del SDK mediante la función YunoConfig clase. Esto es opcional y le permite personalizar la experiencia de pago:

final class YunoConfig {
    let cardFormType: CardFormType,
    let appearance: Yuno.Appearance,
    let saveCardEnabled: Bool,
    let keepLoader: Bool
}

Configura el SDK con las siguientes opciones:

ParámetroDescripción
cardFormTypeEste campo se puede utilizar para elegir el flujo de pago y Tarjeta de Inscripción. Es una propiedad opcional y considera .oneStep por defecto.
appearanceEste campo opcional define la apariencia de la caja. De forma predeterminada, utiliza los estilos de Yuno.
saveCardEnabledEste campo opcional se puede utilizar para elegir si la casilla de verificación Guardar tarjeta se muestra en los flujos de tarjetas. Por defecto es falso.
keepLoaderEste campo opcional proporciona control sobre cuándo ocultar el cargador. Si se establece en true, la hideLoader() se debe llamar a la función para ocultar el cargador. De forma predeterminada, está configurado en false.
hideCardholderNameEste campo opcional te permite ocultar el campo del nombre del titular de la tarjeta en el formulario de la tarjeta. Cuando se establece en true, el campo del nombre del titular de la tarjeta no se muestra. Cuando no se especifica o se establece en false, se muestra el campo del nombre del titular de la tarjeta (comportamiento predeterminado). Ocultar el campo no afecta al PAN, la caducidad, la recopilación del CVV, la lógica BIN ni las validaciones 3DS/proveedor. El comerciante es responsable de garantizar que se proporcione el nombre del titular de la tarjeta cuando lo requiera tu pago .
📘

Cómo acceder a su clave API

Puedes recuperar tu Clave API desde la sección de Desarrolladores en el Panel de Control de Yuno.

Paso 3: Iniciar el proceso de pago

Cree un ViewController que adopte el método YunoPaymentDelegate protocolo:

❗️

Deprecación

El objeto startCheckout ha quedado obsoleto en las últimas versiones del SDK de iOS.

protocol YunoPaymentDelegate: AnyObject {
    var checkoutSession: String { get }
    var countryCode: String { get }
    var language: String? { get }
    var viewController: UIViewController? { get }

    func yunoCreatePayment(with token: String)
    func yunoCreatePayment(with token: String, information: [String: Any])
    func yunoPaymentResult(_ result: Yuno.Result)
}


class ViewController: YunoPaymentDelegate {

    func viewDidLoad() {
        super.viewDidLoad()
    }
}

Parámetros

ParámetroDescripción
checkoutSessionSe refiere a la sesión de checkout del pago actual.
countryCodeEste parámetro determina el país para el que se está configurando el proceso de pago. La lista completa de países admitidos y su código de país está disponible en la página Cobertura de países.
languageDefine el idioma que se utilizará en los formularios de pago. Puede establecerlo en una de las opciones de idioma disponibles:
  • es (español)
  • en (Inglés)
  • pt (portugués)
  • fil (filipino)
  • id (indonesio)
  • ms (malayo)
  • th (tailandés)
  • zh-TW (chino (tradicional, Taiwán))
  • zh-CN (chino simplificado, China)
  • vi (vietnamita)
  • fr (francés)
  • pl (polaco)
  • eso (italiano)
  • de (alemán)
  • ru (ruso)
  • tr (turco)
  • nl (holandés)
  • sv (sueco)
  • ko (coreano)
  • ja (japonés)
viewControllerEsta propiedad representa la UIViewController utilizado para presentar el flujo de pago . Aunque la propiedad sigue siendo opcional por compatibilidad con versiones anteriores, debes proporcionar un controlador visible para que el SDK pueda presentar su interfaz de usuario correctamente.
yunoCreatePayment(with token: String)Este método es responsable de crear un pago con el token proporcionado. Toma un parámetro String llamado token, que representa el token de pago.
yunoCreatePayment(with token: String, information: [String: Any])Este método es responsable de crear un pago con el token proporcionado. Toma un parámetro String llamado token, que representa el token de pago. Además, devuelve toda la información de respuesta del token en un diccionario.
yunoPaymentResult(_ result: Yuno.Result)Este método se llama cuando se completa el proceso de pago, proporcionando el resultado del pago como parámetro de tipo Yuno.Result.
🚧

Nota importante

Puedes llamar yunoCreatePayment con o sin el information Parámetro según sus necesidades. Sin embargo, utiliza solo una versión en tu código, ya que llamar a ambas no es obligatorio y podría causar problemas.

🚧

Requisitos de concurrencia de Swift 6

Si está utilizando Swift 6, deberá implementar el YunoPaymentDelegate Protocolo con consideraciones específicas de concurrencia. Swift 6 introduce requisitos de seguridad de subprocesos más estrictos que afectan la implementación de delegados. Consulte Implementando YunoPaymentDelegate con concurrencia Swift 6 Sección para opciones de implementación detalladas y mejores prácticas.

Paso 4: Iniciar el proceso de pago

Para iniciar efectivamente un pago después de mostrar los métodos de pago, debe llamar al método startPaymentLite, como se presenta en el siguiente fragmento de código:

iniciarPagoLite(
    con: YunoPaymentDelegate,
   paymentSelected: PaymentMethodSelected,
   showPaymentStatus: Bool
)

Para la versión de checkout Lite, debe enviar un parámetro adicional, que puede ser el token guardado y/o el método de pago que utilizará el cliente para realizar el pago.

protocol PaymentMethodSelected {
    var vaultedToken: String? { get }
    var paymentMethodType: String { get }
}

startPaymentLite(with: self, paymentSelected: paymentSelected)

Paso 5: Consigue el OTT (token de un solo uso)

Puedes obtener el token único para realizar el pago consecutivo al final de este proceso. Recibirás el token único en la función. yunoCreatePayment() que se obtiene al implementar el YunoPaymentDelegateA continuación se presenta un ejemplo de recuperación del token de un solo uso:

func yunoCreatePayment(with token: String) { ... }

Paso 6: Crea el pago.

Una vez completados los pasos descritos anteriormente, puede crear un pago. La creación de pagos consecutivos debe realizarse utilizando el endpoint Create Payment . El comerciante debe llamar a su backend para crear el pago dentro de Yuno, utilizando el token de un solo uso y la sesión de pago.

🚧

Continuar el método

Yuno requiere que integres el continuePayment del SDK después de crear el pago porque ciertos métodos de pago asincrónicos requieren una acción adicional por parte del cliente para completarlo. La API le informará de este escenario a través del sdk_action_required de la respuesta, que se devolverá como verdadero. La yuno.continuePayment() La función mostrará las pantallas adicionales a los clientes, donde podrán realizar las acciones necesarias para completar el pago sin necesidad de que usted maneje cada escenario.

YunocontinuePayment()

Paso 7: Gestionar pago (opcional)

❗️

Enlaces profundos y Mercado Pago Checkout Pro

Este paso solo es necesario si utilizas un método de pago que utiliza enlaces profundos o Mercado Pago Checkout Pro. Si tus métodos de pago no utilizan enlaces profundos, puedes omitir este paso.

Algunos métodos de pago sacan a los usuarios de la app para completar la transacción. Una vez finalizado el pago, se redirige al usuario a la app mediante un enlace profundo. El SDK utiliza este enlace profundo para comprobar qué ha sucedido, verificando si el pago se realizó correctamente, falló o se canceló, y puede mostrar una pantalla de estado al usuario.

Para solucionar esto, necesita actualizar su AppDelegate Para devolver la URL entrante al SDK de Yuno. Esto permite que el SDK lea el resultado y, opcionalmente, muestre el estado del pago. El siguiente fragmento de código muestra cómo añadirlo a la aplicación:

func application(_ app: UIApplication,
                 open url: URL,
                 options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {

  guard url.scheme == "yunoexample" else { return false }

  return Yuno.receiveDeeplink(url)
}

Este código detecta enlaces profundos que abren tu aplicación. Al recibir una URL, comprueba si el esquema coincide con el que usaste en el callback_url durante la configuración de la sesión de pago. Si coincide, la URL se pasa al SDK de Yuno mediante Yuno.receiveDeeplink(...)Luego, el SDK lee el resultado del pago y muestra la pantalla de estado correspondiente al usuario.

Asegúrese de que url.scheme En este código coincide con el callback_url que usted proporcionó al crear el checkout_session.

📘

Pulse para pagar

Para obtener asistencia sobre Click to Pay, sigue la guía de integración del SDK de Click to Pay que se encuentra en la sección Carteras.

Llamar de vuelta

El SDK devuelve diferentes estados de transacción tras la finalización pago. La siguiente tabla describe cada estado:

Estado de la transacciónDescripción
successIndica que el proceso de transacción o pago se ha completado con éxito.
failEste estado indica que la transacción o el proceso de pago ha fallado. Significa que hubo un error o problema durante el proceso de pago, impidiendo que se completara exitosamente.
processingIndica que el proceso de transacción o pago se está procesando actualmente. Por lo general, se usa cuando hay un retraso en el procesamiento del pago, como esperar la aprobación de un servicio de terceros o una institución financiera.
rejectEste estado indica que la transacción ha sido rechazada. El rechazo puede ocurrir por varios motivos, como fondos insuficientes, actividad fraudulenta o una solicitud que viola reglas o políticas específicas.
internalErrorSignifica que ocurrió un error inesperado dentro del sistema o la infraestructura que maneja el proceso de pago. Este estado sugiere que hubo un problema en el servidor o en el backend en lugar de un problema con la entrada o la solicitud del usuario.
userCancellEste estado indica que el usuario ha cancelado o abortado voluntariamente la transacción o proceso de pago. Este estado generalmente se usa cuando existe una opción para que el usuario cancele o abandone el proceso de pago.

Validación pago

En esta sección se explica cómo gestiona el SDK pago cuando los usuarios cancelan o abandonan pago , y cómo se relaciona el estado del SDK con pago del backend en estos casos.

Sincronizar pago (Apple Pay)

En el caso de pago sincrónicos, como Apple Pay, cuando tú cancelas o cierras la interfaz de usuario de la cartera antes de recibir la respuesta del proveedor pago (PSP):

  • Estado del SDK: Devoluciones userCancell (CANCELLED)
  • pago en el backend: Restos PENDING hasta el tiempo de espera de PSP o la cancelación por parte del comerciante
  • ImportanteEl SDK no devolverá reject o processing en este escenario

Esto garantiza que el pago backend pago en estado pendiente y pueda ser gestionado correctamente por el sistema del comerciante.

pago asíncronos (métodos basados en PIX y QR)

Para pago asíncronos como PIX, cuando tú cierras la ventana del código QR (haces clic en X) antes de completar el pago:

  • Estado del SDK: Devoluciones PENDING, opcionalmente con un subestado como CLOSED_BY_USER
  • pago en el backend: Restos PENDING y el código QR sigue siendo válido hasta su fecha de caducidad.
  • Reutilización de la sesión de pago: al volver a abrir la misma sesión de pago, se puede mostrar el mismo código QR válido.
  • Sin cancelación automática: El pago PIX no pago cancela automáticamente cuando tú cierras la ventana QR.

Este comportamiento permite a los usuarios volver al pago y completar la transacción utilizando el mismo código QR antes de que caduque.

Pagos asíncronos caducados

Si un código QR PIX caduca de forma natural:

  • Estado del backendActualizado a EXPIRED
  • Estado del SDK: Las devoluciones de llamada del SDK y endpoints de sondeo endpoints EXPIRED de manera constante

Esto garantiza que los comerciantes reciban información precisa sobre el estado cuando un pago ha caducado.

Implementa el delegado para recibir estados de transacciones:

enum Result {
    case reject, success, fail, processing, internalError, userCancell
}

func yunoPaymentResult(_ result: Yuno.Result) { ... }
func yunoEnrollmentResult(_ result: Yuno.Result) { ... }

Características complementarias

El SDK de Yuno iOS proporciona funciones adicionales para mejorar la experiencia del cliente. Utiliza las personalizaciones del SDK  para adaptar la apariencia de tu marca o configurar el cargador.

  • Cargador: Controla el uso del cargador mediante las opciones de configuración del SDK.
  • Guardar tarjeta para futuros pagos: Además, puede mostrar una casilla de verificación para guardar o inscribir tarjetas usando cardSaveEnable: true. A continuación, puede encontrar ejemplos de la casilla de verificación para ambos renderizados de formularios de tarjetas.
  • También puedes elegir una de las opciones de renderizado para el formulario de la tarjeta. A continuación encontrará capturas de pantalla que presentan la diferencia entre cardFormType ONE_STEP y STEP_BY_STEP.

Integración del modo de renderizado

El modo de renderizado del SDK de Yuno ofrece mayor flexibilidad en la interfaz de usuario, lo que permite a los desarrolladores integrar flujos de pago con control total sobre la interfaz de usuario, conservando al mismo tiempo toda la funcionalidad del SDK. Este modo proporciona vistas SwiftUI que se integran perfectamente en la interfaz de usuario existente.

Función principal: startPaymentRenderFlow

El objeto startPaymentRender Esta función es una característica del SDK de Yuno que permite a los comerciantes integrar el proceso de pago de forma más detallada y personalizable. Esta función ofrece control total sobre cuándo y cómo se muestran los formularios de pago, lo que facilita una integración más fluida con la interfaz de usuario de la aplicación del comerciante.

Objetivo

Esta función está diseñada para ofrecer un mayor control sobre el flujo de pago, permitiendo a los comerciantes:

  • Integre formularios de pago de forma personalizada dentro de su propia interfaz de usuario.
  • Controle con precisión cuándo se muestran los formularios de datos de pago.
  • Obtenga un control detallado sobre el proceso de confirmación de pago.
  • Proporcionar una experiencia de usuario más fluida y consistente dentro de la aplicación del comerciante.

Sintaxis

La sección de sintaxis proporciona la firma del método startPaymentRender Función. Esta función es fundamental para integrar el proceso de pago en tu aplicación, ofreciendo un enfoque personalizable y detallado para gestionar los formularios y flujos de pago.

@MainActor static func startPaymentRenderFlow(
    pagoMétodoSeleccionado: PaymentMethodSelected,
    con delegado: YunoPaymentDelegate
) async -> algún YunoPaymentRenderFlowProtocolo

Parámetros

El objeto startPaymentRender requiere parámetros específicos para operar con eficacia. Estos parámetros son esenciales para definir el método de pago y manejar las respuestas del proceso de pago.

ParámetroTipoDescripción
paymentMethodSelectedPaymentMethodSelectedEl método de pago seleccionado por el usuario. Debe incluir el vaultedToken (si existe) y el paymentMethodType
delegateYunoPaymentDelegateEl delegado que gestionará las respuestas del proceso de pago, incluida la creación del token y el resultado final.

Valor de retorno

Devuelve una instancia que cumple con YunoPaymentRenderFlowProtocol, que proporciona métodos para gestionar el flujo de procesamiento de pagos.

Protocolo YunoPaymentRenderFlowProtocol

La instancia devuelta por startPaymentRender se ajusta a este protocolo que incluye los siguientes métodos:

formView(método de pago seleccionado:con:)

func formularioVer(
    métodoPagoSeleccionado: PaymentMethodSelected,
    con delegado: YunoPaymentDelegate
) async -> ¿CualquierVista?
  • Finalidad: Obtiene la vista del formulario para capturar los datos de pago
  • Comportamiento:
    • Si el método de pago requiere mostrar un formulario, devuelve un AnyView con el formulario correspondiente
    • Si el método de pago no necesita mostrar ningún formulario (por ejemplo, métodos ya configurados), devuelve nil
  • Cuándo utilizarlo: Llamar inmediatamente después de crear la instancia de flujo de pago

enviarFormulario()

func submitForm()
  • Finalidad: Enviar los datos del formulario para su validación
  • Comportamiento: Ejecuta todas las validaciones necesarias y, si tiene éxito, procede a generar un nuevo token de un solo uso.
  • Cuándo utilizar: Cuando el usuario ejecuta la acción "pagar" en la aplicación del comerciante.

continuePayment()

func continuePayment() async -> ¿CualquierVista?
  • Finalidad: Continúa el proceso de pago después de que se haya generado el token de un solo uso.
  • Comportamiento: i. Si es necesario mostrar alguna vista adicional (por ejemplo, autenticación 3DS), devuelve un AnyView ii. Si no se requiere vista adicional, devuelve nil
  • Cuándo utilizarlo: Tras recibir el token de un solo uso a través del delegado y crear el pago.

Flujo de implementación

Esta sección describe la secuencia de pasos necesarios para implementar el proceso de procesamiento de pagos utilizando el SDK de Yuno.

Paso 1: Configuración inicial

Para comenzar a utilizar startPaymentRenderAsegúrese de que el SDK esté inicializado correctamente y que tenga un archivo válido. checkoutSessionSiga los pasos a continuación para configurar su entorno:

await Yunoinitialize(apiKey: "tu_clave_api")

Paso 2: Crear una instancia de flujo de pago

Cree una instancia de flujo de pago para administrar y representar el proceso de pago utilizando el método seleccionado.

let paymentFlow = await Yuno.startPaymentRenderFlow(
    métodoPagoSeleccionado: métodoPagoSeleccionado,
    con: yo
)

Paso 3: Obtener y mostrar el formulario

Recupere y presente el formulario de pago para recopilar la información de pago del usuario de manera eficiente.

let formView = await paymentFlow.formView(
    paymentMethodSelected: selectedPaymentMethod,
    with: self
)

if let formView = formView {
    VStack {
        Text("Payment Information")

        formView

        Button("Pay") {
            paymentFlow.submitForm()
        }
    }
} else {
    paymentFlow.submitForm()
}

Paso 4: Gestionar el token de un solo uso

Implemente el método delegado para recibir el token:

extension MyViewController: YunoPaymentDelegate {
    var checkoutSession: String {
        return "your_checkout_session"
    }

    var countryCode: String {
        return "CO"
    }

    var viewController: UIViewController? {
        return self
    }

    func yunoCreatePayment(with token: String, information: [String: Any]) {
        createPaymentInBackend(token: token) { [weak self] success in
            if success {
                Task {
                    let additionalView = await self?.paymentFlow?.continuePayment()
                    if let additionalView = additionalView {
                        self?.showAdditionalView(additionalView)
                    }
                }
            }
        }
    }

    func yunoPaymentResult(_ result: Yuno.Result) {
        switch result {
        case .succeeded:
            showSuccessMessage()
        case .reject:
            showRejectionMessage()
        case .fail:
            showErrorMessage()
        case .processing:
            showProcessingMessage()
        case .userCancell:
            handleCancellation()
        case .internalError:
            showInternalErrorMessage()
        }
    }
}

Ejemplo completo

import SwiftUI
import YunoSDK

struct PaymentRenderView: View {
    @State private var paymentFlow: YunoPaymentRenderFlowProtocol?
    @State private var formView: AnyView?
    @State private var additionalView: AnyView?

    let selectedPaymentMethod: PaymentMethodSelected
    let delegate: YunoPaymentDelegate

    var body: some View {
        VStack(spacing: 20) {
            Text("Complete Purchase")
                .font(.title2)
                .fontWeight(.bold)

            OrderSummaryView()

            if let formView = formView {
                VStack(alignment: .leading) {
                    Text("Payment Information")
                        .font(.headline)

                    formView
                }
            }

            if let additionalView = additionalView {
                additionalView
            }

            Spacer()

            Button(action: {
                paymentFlow?.submitForm()
            }) {
                Text("Confirm Payment")
                    .font(.headline)
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity)
                    .padding()
                    .background(Color.blue)
                    .cornerRadius(10)
            }
        }
        .padding()
        .onAppear {
            setupPaymentFlow()
        }
    }

    private func setupPaymentFlow() {
paymentFlow = await Yuno.startPaymentRenderFlow(
    paymentMethodSelected: selectedPaymentMethod,
    with: delegate
)

        Task {
            formView = await paymentFlow?.formView(
                paymentMethodSelected: selectedPaymentMethod,
                with: delegate
            )
        }
    }
}

class PaymentDelegate: YunoPaymentDelegate {
    let checkoutSession: String
    let countryCode: String
    weak var viewController: UIViewController?

    init(checkoutSession: String, countryCode: String, viewController: UIViewController?) {
        self.checkoutSession = checkoutSession
        self.countryCode = countryCode
        self.viewController = viewController
    }

    func yunoCreatePayment(with token: String, information: [String: Any]) {
        PaymentService.createPayment(token: token) { [weak self] result in
            switch result {
            case .success:
                Task {
                    await self?.continuePaymentProcess()
                }
            case .failure(let error):
                print("Error creating payment: \(error)")
            }
        }
    }

    func yunoPaymentResult(_ result: Yuno.Result) {
        DispatchQueue.main.async {
            switch result {
            case .succeeded:
                NotificationCenter.default.post(name: .paymentSucceeded, object: nil)
            case .reject:
                NotificationCenter.default.post(name: .paymentRejected, object: nil)
            }
        }
    }

    private func continuePaymentProcess() async {
    }
}

Casos de uso comunes

Esta sección describe escenarios típicos en los que se puede utilizar el SDK de Yuno para gestionar diversos métodos de pago, proporcionando flexibilidad y facilidad de integración.

1. Pago con tarjeta de crédito

En este caso de uso, demostramos cómo procesar pagos utilizando nueva información de tarjeta de crédito, requiriendo que el usuario complete un formulario para capturar los detalles necesarios de la tarjeta.

let pagoTarjeta = MétodoPagoTarjetapaymentMethodType: "TARJETA")
let flujo = Yuno.startPaymentRender(metodoPagoSeleccionado: pagoTarjeta, con: delegado)

let form = await flow.formView(paymentMethodSelected: cardPayment, with: delegate)

2. Pago con método guardado

Este escenario demuestra el uso de un método de pago guardado, lo que permite a los usuarios pagar sin tener que volver a ingresar los detalles mediante el uso de un token almacenado.

let tarjetaguardada = TarjetaPagoGuardada(
   paymentMethodType"TARJETA",
   vaultedToken: "saved_token_123"
)
let flow = Yuno.startPaymentRender(paymentMethodSelected: savedCard, with: delegate)

let form = await flow.formView(paymentMethodSelected: savedCard, with: delegate)

3. Pago con autenticación 3DS

3D Secure (3DS) añade un paso de verificación adicional para mayor seguridad. El SDK de Yuno integra este proceso en tu flujo de pago a la perfección.

func yunoCreatePayment(with token: String, information: [String: Any]) {
    createPayment(token: token) { [weak self] success in
        if success {
            Task {
                let authView = await self?.paymentFlow?.continuePayment()
                if let authView = authView {
                    self?.show3DSView(authView)
                }
            }
        }
    }
}

Consideraciones importantes

Esta sección destaca los puntos clave para integrar el SDK de Yuno de manera efectiva, garantizando un proceso de pago seguro y sin problemas.

Prerrequisitos

  • Asegúrese de que el SDK esté inicializado antes de usarlo startPaymentRender
  • El delegado debe implementar todos los métodos requeridos de YunoPaymentDelegate
  • El objeto checkoutSession debe ser válido y activo

Gestión estatal

  • Compruebe siempre si formView() devoluciones nil antes de mostrar la vista
  • Manejar adecuadamente el caso donde continuePayment() devoluciones nil
  • Implementar estados de carga durante operaciones asincrónicas

Seguridad

  • Nunca guarde tokens de un solo uso: úselos inmediatamente
  • Valide siempre los resultados de pago en su backend
  • Implementar tiempos de espera adecuados para las operaciones de red

Actuación

  • Llamadas a formView() y continuePayment() son asincrónicos
  • Considere mostrar indicadores de carga durante estas operaciones
  • Reutiliza la instancia del flujo de pago cuando sea posible

Solución de problemas

Esta sección ofrece soluciones rápidas a problemas comunes surgidos durante la integración del SDK de Yuno, garantizando un proceso de pago más fluido.

Problemas comunes

  1. formView()siempre regresanil

    • Verificar que el método de pago seleccionado requiera un formulario
    • Asegúrese de que el SDK se inicialice correctamente
  2. El delegado no recibeyunoCreatePayment

    • Verificar que submitForm() se está llamando correctamente
    • Confirmar que el formulario tiene datos válidos
  3. continuePayment()No devuelve la vista cuando se espera

    • Algunos métodos de pago no requieren vistas adicionales
    • Comprueba la configuración del método de pago en tu panel de Yuno

Registros de depuración

Yuno.config.environment = .staging

Migración desde otros métodos

Si estás migrando desde startPayment() o startPaymentLite():

Yuno.startPayment()

let flow = Yuno.startPaymentRender(paymentMethodSelected: method, with: delegate)
let formulario = await flujo.formularioVista(metodoPagoSeleccionado: método, con: delegado)

El principal beneficio de utilizar el nuevo método es el control detallado que proporciona tanto sobre la interfaz de usuario como sobre el proceso de pago.

📘

Aplicación de demostración

Además de los ejemplos de código proporcionados, puedes acceder al repositorio de Yuno para una implementación completa de Yuno iOS SDKs.

Implementando YunoPaymentDelegate con concurrencia Swift 6

Swift 6 introduce requisitos de concurrencia más estrictos que afectan la forma en que se implementa el YunoPaymentDelegate Protocolo. Esta sección explica los desafíos y ofrece soluciones para diferentes escenarios de implementación.

📘

Comprensión de la concurrencia en Swift 6

La concurrencia es la capacidad de tu aplicación para gestionar múltiples tareas simultáneamente. Con Swift 6, las reglas de concurrencia se han vuelto más estrictas para mejorar la estabilidad de la aplicación y evitar fallos. Esto significa que tu código debe estar estructurado con mayor cuidado para garantizar la seguridad de los subprocesos y una gestión adecuada de las tareas.

El problema

Con Swift 6, los protocolos que heredan de Sendable Requieren que todas sus implementaciones sean seguras para subprocesos. Esto genera advertencias al implementar el delegado en clases marcadas como @MainActor.

Seguro para subprocesos significa que tu código puede llamarse de forma segura desde múltiples subprocesos sin provocar fallas o comportamientos inesperados. @MainActor garantiza que el código se ejecute en el hilo principal (hilo de UI).

Nuestra decisión de diseño

No marcamos los protocolos como @MainActor porque:

  • Obligaría a todas las implementaciones a ser MainActor-compatible
  • Reduciría la flexibilidad para los comerciantes que no utilizan MainActor
  • Cada implementación tiene diferentes necesidades de concurrencia

Responsabilidad del comerciante

Es responsabilidad del comerciante gestionar la concurrencia según su implementación. A continuación, se presentan tres enfoques diferentes que puede utilizar según sus necesidades específicas.

Opción 1: Propiedades inmutables

Este enfoque utiliza propiedades inmutables que son automáticamente seguras para subprocesos, lo que las hace ideales para configuraciones simples. Es ideal para aplicaciones sencillas con valores de configuración fijos que no cambian durante la ejecución.

@MainActor
class MyViewController: UIViewController, YunoPaymentDelegate {

    private let _countryCode = "CO"
    private let _language = "EN"

    nonisolated var countryCode: String { _countryCode }
    nonisolated var language: String? { _language }
    nonisolated var checkoutSession: String { _checkoutSession }

    nonisolated func yunoPaymentResult(_ result: Yuno.Result) {
        Task { @MainActor in
        }
    }
}

Opción 2: Propiedades mutables con MainActor.assumeIsolated

Este enfoque, ideal para aplicaciones en las que los valores de configuración pueden cambiar durante el tiempo de ejecución (como las preferencias del usuario), permite propiedades mutables y al mismo tiempo mantiene la seguridad de los subprocesos mediante el uso de MainActor.assumeIsolated.

@MainActor
class MyViewController: UIViewController, YunoPaymentDelegate {

    @Published var configLanguage: String = "EN"
    @Published var configCountryCode: String = "CO"

    nonisolated var language: String? {
        MainActor.assumeIsolated { configLanguage }
    }

    nonisolated var countryCode: String {
        MainActor.assumeIsolated { configCountryCode }
    }
}

Opción 3: Para noMainActor clases

Este enfoque es adecuado para clases de servicio que no requieren MainActor por lo que es ideal para servicios en segundo plano o clases utilitarias que no interactúan con la interfaz de usuario.

class MyService: YunoPaymentDelegate {

    let countryCode: String
    let language: String?
    let checkoutSession: String
    let viewController: UIViewController?

    init(countryCode: String, language: String?, checkoutSession: String, viewController: UIViewController?) {
        self.countryCode = countryCode
        self.language = language
        self.checkoutSession = checkoutSession
        self.viewController = viewController
    }

    func yunoPaymentResult(_ result: Yuno.Result) {
    }
}

⚠️ Consideraciones importantes

Al implementar la concurrencia en su delegado, tenga en cuenta estos puntos clave:

  • MainActor.assumeIsolated: Utilízalo sólo cuando garantices que se llama desde MainActor. Se trata de un mecanismo de seguridad que le dice a Swift "confía en mí, sé que esto se está ejecutando en el hilo principal".
  • nonisolated: Significa que se puede acceder a él desde cualquier subproceso, por lo que debe ser seguro para subprocesos. Utilízalo cuando tus propiedades o métodos no dependan del estado de la interfaz de usuario.
  • viewController: Permanece como @MainActor porque siempre se debe acceder desde el hilo principal. Los componentes de la interfaz de usuario siempre deben ejecutarse en el hilo principal para evitar fallos.