Seamless SDK (Pago iOS)
En esta página, encontrará todos los pasos para agregar, configurar y usar el Seamless iOS SDK para realizar pagos en su proyecto iOS.
SDK recomendadoRecomendamos 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.
Paso 1: Incluya la biblioteca en tu proyecto
Puede agregar la biblioteca usando CocoaPods o Swift Package Manager.
CocoaPods
Para añadir el SDK de Yuno a tu proyecto iOS, necesitas instalar el SDK de Yuno. Si no tienes un Podfile, sigue la guía de CocoaPods para crear uno. Después de crear el Podfile, integrarás el SDK de Yuno con Cocoapods añadiendo la siguiente línea a tu Podfile.
pod 'YunoSDK', '~> 1.19.0'Después, necesita ejecutar la instalación:
instalar podAdministrador de Paquetes Swift
Si estás usando el gestor de paquetes Swift, añade el SDK de Yuno como dependencia, tal y como se presenta en el siguiente bloque de código:
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
Para empezar a utilizar el sistema de pago Yuno iOS Seamless, primero debes obtener tu ID de aplicación Yuno y tu clave API pública. A continuación, importa e initialize tal y como se muestra en el siguiente fragmento de código:
import YunoSDK
Yuno.initialize(
apiKey: "PUBLIC_API_KEY",
config: YunoConfig(),
callback: { (value: Bool) in }
)
UISceneDelegateAsegúrese de que si su aplicación utiliza un
UISceneDelegateEl código de inicialización de Yuno se coloca dentro de suSceneDelegate.
La verificación sin interrupciones le permite configurar la apariencia del SDK. Es un paso opcional que se configura a través de la clase YunoConfig. Para configurar configuraciones, utiliza el siguiente bloque de código para configurar los elementos disponibles:
final class YunoConfig {
let cardFormType: CardFormType,
let appearance: Yuno.Appearance,
let saveCardEnabled: Bool,
let keepLoader: Bool
}Configura el SDK con las siguientes opciones:
| Parámetro | Descripción |
|---|---|
cardFormType | Este campo se puede utilizar para elegir los flujos Payment y Enrollment Card . Es una propiedad opcional. Utiliza la opción .oneStep por defecto. |
appearance | Este campo opcional define la apariencia de la caja. De forma predeterminada, utiliza los estilos de Yuno. |
saveCardEnabled | Este campo opcional le permite elegir si la casilla de verificación Guardar tarjeta se muestra en los flujos de tarjetas. Por defecto es falso. |
keepLoader | Este 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 manera predeterminada, está configurada como falsa. |
hideCardholderName | Este 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 APIPuedes recuperar tu Clave API desde la sección de Desarrolladores en el Panel de Control de Yuno.
Crear una sesión de checkout
Antes de comenzar el pago proceso, necesitas crear un checkout_session utilizando la función del endpoint Crear sesión de pago endpoint Esta sesión inicializa el pago flujo y se utilizará en el siguiente paso.
Controlar la autenticación frente a la captura mediante el envío
payment_method.detail.card.captureen la sesión de pago:false= solo autorizar,true= capturar inmediatamente.
Parámetros clave
| Parámetro | Requerido | Descripción |
|---|---|---|
amount | Sí | El objeto de importe de la transacción primaria que contiene currency (código ISO 4217) y value (importe numérico en esa moneda). |
workflow | Sí | Establece el valor en SDK_SEAMLESS para que el SDK pueda completar correctamente el pago . |
alternative_amount | No | Una representación monetaria alternativa del importe de la transacción con la misma estructura que amount (currency y value). Útil para escenarios multidivisa, como mostrar los precios a los clientes en su divisa preferida (por ejemplo, USD) mientras se procesa el pago en la divisa local (por ejemplo, COP). |
Paso 3: Inicia el pago de pago .
El proceso de pago y compra sin inconvenientes se inicia con un único método. startPaymentSeamlessLite. En el ViewController, donde se mostrará Yuno, llame al Yuno.startPaymentSeamlessLite() Método. Puedes utilizar el método con async/await o mediante devoluciones de llamadas:
func startPaymentSeamlessLite(
con parámetros SeamlessParams,
paymentSelected: PaymentMethodSelected,
showPaymentStatus: Bool = true
) async -> Resultadofunc startPaymentSeamlessLite(
con parámetros SeamlessParams,
paymentSelected: PaymentMethodSelected,
showPaymentStatus: Bool = true,
devolución de llamada: @escaping ((Resultado) -> Void)
)Para la versión integrada se requieren parámetros adicionales, entre ellos:
PaymentMethodSelected: El token almacenado 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 }
}SeamlessParams
class SeamlessParams {
var checkoutSession: String
var country_code: String
var language: String?
var viewController: UIViewController?
}Parámetros
La siguiente tabla describe cada parámetro de SeamlessParams:
| Parámetro | Descripción |
|---|---|
checkoutSession | Se refiere a la sesión de checkout del pago actual. |
country_code | Este 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. |
language | Define el idioma que se utilizará en los formularios de pago. Puede establecerlo en una de las opciones de idioma disponibles:
|
viewController | Esta 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. |
Requisitos de concurrencia de Swift 6Si está utilizando Swift 6, deberá implementar el
YunoPaymentDelegateProtocolo 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 ImplementandoYunoPaymentDelegatecon concurrencia Swift 6 Sección para opciones de implementación detalladas y mejores prácticas.
Paso 4: Gestiona pago (opcional)
Enlaces profundos y Mercado Pago Checkout ProEste 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, showStatusView: true)
}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(...). A continuación, el SDK lee el resultado del pago y, si showStatusView está configurado para true, muestra la pantalla de estado apropiada 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.
Estado de la transacción
Una vez completado el pago, el SDK puede devolver distintos estados de transacción. La lista de todos los estados posibles y sus descripciones se presentan en la siguiente tabla:
| Estado de la transacción | Descripción |
|---|---|
success | Indica que el proceso de transacción o pago se ha completado con éxito. |
fail | Este 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 que impidió que se completara correctamente. |
processing | Indica 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. |
reject | Este estado indica que la transacción ha sido rechazada. El rechazo puede ocurrir por varios motivos, como fondos insuficientes, actividad fraudulenta o solicitudes que violen reglas o políticas específicas. |
internalError | Significa que ocurrió un error inesperado dentro del sistema o la infraestructura que maneja el proceso de pago. Este estado sugiere un problema en el servidor o en el backend en lugar de un problema con la entrada o solicitud del usuario. |
userCancell | Este estado indica que el usuario ha cancelado o abortado voluntariamente la transacción o el proceso de pago. Se utiliza normalmente cuando el usuario tiene la opción de cancelar o abandonar 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
PENDINGhasta el tiempo de espera de PSP o la cancelación por parte del comerciante - ImportanteEl SDK no devolverá
rejectoprocessingen 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 comoCLOSED_BY_USER - pago en el backend: Restos
PENDINGy 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
EXPIREDde manera constante
Esto garantiza que los comerciantes reciban información precisa sobre el estado cuando un pago ha caducado.
El estado de la transacción se puede manejar de dos maneras cuando se utiliza el startPaymentSeamlessLite :
- Async/Await: Utilice el método async/await para un flujo más ágil. Este método devuelve un resultado de forma asíncrona, lo que facilita la lectura y gestión del código.
- Devolución de llamada: Puede manejar el estado de la transacción a través de una función de devolución de llamada, permitiendo la ejecución inmediata una vez que el resultado esté disponible.
Ambas opciones brindan flexibilidad dependiendo de su enfoque preferido para el código asincrónico.
enum Resultado {
caso rechazar, éxito, fallo, procesamiento, internalError, userCancell
}Características complementarias
Yuno iOS SDK proporciona servicios y configuraciones adicionales que puedes utilizar para mejorar la experiencia de los clientes. Utiliza las personalizaciones del SDK para cambiar la apariencia del SDK para que coincida con tu marca o para configurar el cargador.
- Cargador: Controla el uso del cargador mediante las opciones de configuración del SDK.
- Guardar tarjeta para pagos futuros: 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
cardFormTypeONE_STEPySTEP_BY_STEP.
- Personalizaciones del SDK: Cambia la apariencia del SDK para que coincida con tu marca.
Implementando YunoPaymentDelegate con concurrencia Swift 6
YunoPaymentDelegate con concurrencia Swift 6Swift 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 6La 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
MainActorcompatible - 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
MainActor.assumeIsolatedEste 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 los que no MainActor clases
MainActor clasesEste 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 desdeMainActor. 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@MainActorporque 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.
Actualizado hace 26 días