Lite SDK (Inscripción iOS)

Esta guía te guía a través de la integración del Lite iOS SDK de Yuno para la inscripción 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: Registra un nuevo método de pago

📘

Antes de llamar Yuno.enrollPayment()Asegúrese de haber inicializado el SDK con Yuno.initialize().

El SDK para iOS de Yuno proporciona una función de inscripción para los métodos de pago. Para mostrar el flujo de inscripción, implementa el delegado y llama al método de inscripción:

protocol YunoEnrollmentDelegate: AnyObject {
    var customerSession: String { get }
    var countryCode: String { get }
    var language: String? { get }
    var viewController: UIViewController? { get }

    func yunoEnrollmentResult(_ result: Yuno.Result)
}

class ViewController: YunoEnrollmentDelegate {

    func startEnrollment() {
        Yuno.enrollPayment(with: self, showPaymentStatus: Bool)
    }
}

Yuno.enrollPayment() presenta una pantalla completa UIViewController utilizando modalmente el viewController proporcionado en su delegateEsto solo funciona en UIKit. En SwiftUI, envuelva un UIViewController y devolverlo a través de viewController propiedad. La delegate debe exponer un controlador visible para permitir que el SDK presente la interfaz de usuario.

Parámetros

ParámetroDescripción
customerSessionSe refiere a la sesión de cliente 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 inscripción. Aunque la propiedad sigue siendo opcional para garantizar la compatibilidad con versiones anteriores, debes proporcionar un controlador visible para que el SDK pueda presentar su interfaz de usuario correctamente.
yunoEnrollmentResult(\_ result: Yuno.Result)Este método se llama cuando se completa el proceso de inscripción, proporcionando el resultado de la inscripción como un parámetro de tipo Yuno.Result.

El objeto showPaymentStatus determina si se debe mostrar el estado de pago. Pasando true muestra el estado del pago , mientras que pasando false lo oculta.

Parámetros

El objeto enrollPayment Los parámetros del método se describen a continuación:

ParámetroTipoDescripción
delegateYunoEnrollmentDelegateEl objeto delegado que gestiona las devoluciones de llamada de inscripción.
showPaymentStatusBoolUn indicador Boolean que determina si se muestran las vistas de estado durante el proceso de inscripción de pago.

El método enrollPayment inicia el proceso de inscripción al pago. Debes llamarlo en respuesta a interacciones del usuario, como pulsar un botón. El método utiliza el delegate para gestionar eventos de inscripción y, según el parámetro showPaymentStatusdecide si mostrar información visual sobre el estado de la inscripción.

Paso 3: Estado de inscripción

❗️

Inscripción de enlaces profundos

Esta función solo se utiliza si te registras en un método de pago que ejecuta enlaces profundos. Si no te estás inscribiendo en un método de pago que ejecuta enlaces profundos, puedes ignorar el Paso 3.

Si utilizas un pago que requiere un enlace profundo para volver a tu aplicación, utiliza el método descrito en el siguiente bloque de código para obtener el estado de inscripción en tu AppDelegate. La función url.scheme debe ser el mismo que el callback_url utilizado al crear el customer_session.

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

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.

Comprensión Yuno.Result

Cuando finaliza el proceso de inscripción, el SDK llama a:

func yunoEnrollmentResult(_ resultado: Yuno.Result)

Este resultado puede reflejar diferentes estados finales para la inscripción. El Yuno.Result La enumeración incluye:

enum Resultado {
    caso éxito
    caso fallo
    caso rechazo
    caso procesamiento
    caso internalError
 interno
    caso userCancell

}

Puede utilizar un conmutador para gestionar cada caso de resultado:

func yunoEnrollmentResult(_ result: Yuno.Result) {
    switch result {
    case .success:
        print("Enrollment successful")
    case .fail:
        print("Enrollment failed")
    case .processing:
        print("Enrollment still processing")
    case .reject:
        print("Enrollment rejected")
    case .userCancell:
        print("User canceled")
    case .internalError:
        print("Internal error")
    }
}
📘

Yuno.Result No incluye tokens ni mensajes de error. Solo recibirás un estado general para ayudarte a guiar la experiencia del usuario.

Integración del modo de renderizado (inscripción)

El modo de renderizado ofrece una flexibilidad de interfaz de usuario mejorada para la inscripción, lo que le permite integrar el flujo de inscripción dentro de sus propias vistas mientras utiliza las validaciones y la lógica del SDK.

Función principal: startEnrollmentRenderFlow

@MainActor static func startEnrollmentRenderFlow(
    con delegado YunoEnrollmentDelegate
) async -> algún YunoEnrollmentRenderFlowProtocolo

Protocolo de flujo de renderizado de inscripción de Yuno

func formView(
    with delegate: YunoEnrollmentDelegate
) async -> AnyView?

func submitForm()

var needSubmit: Bool { get }
  • vista de formulario: Devuelve un AnyView con el formulario de inscripción (tarjetas/APM) si se requiere UI; de lo contrario nil.
  • submitForm: Activa las validaciones y procede con la inscripción cuando procede.
  • needSubmit: Indica si debe mostrar un botón de envío.

Flujo de implementación

Paso 1: Crear una instancia de flujo de inscripción

let enrollmentFlow = await Yuno.startEnrollmentRenderFlow(with: self)

Paso 2: Obtener y mostrar el formulario

let formView = await enrollmentFlow.formView(with: self)

if let formView = formView {
    VStack {
        Text("Enroll Payment Method")
        formView

        if enrollmentFlow.needSubmit {
            Button("Enroll") {
                enrollmentFlow.submitForm()
            }
        }
    }
}

Paso 3: Gestionar el resultado de la inscripción

extension MyViewController: YunoEnrollmentDelegate {
    var customerSession: String { "your_customer_session" }
    var countryCode: String { "CO" }
    var language: String? { "es" }
    var viewController: UIViewController? { self }

    func yunoEnrollmentResult(_ result: Yuno.Result) {
        // Handle enrollment result
    }
}

Funciones complementarias

Yuno iOS SDK proporciona servicios y configuraciones adicionales que puede utilizar para mejorar la experiencia de los clientes.

Opción de renderizado

Al presentar la inscripción, también podrás elegir una de las opciones de renderizado del formulario de tarjeta. Tienes las siguientes opciones:

  • ONE_STEP
  • STEP_BY_STEP

Para cambiar la opción de renderizado, configure el cardFormType igual a una de las opciones disponibles. Cada opción se presenta a continuación.

Loader

Controla el uso del cargador mediante las opciones de configuración del SDK.

Personalizaciones del SDK

Utilice las personalizaciones del SDK  para cambiar su aspecto y adaptarlo a su marca.

📘

App Demo

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
            // Handle result
        }
    }
}

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 los que no MainActor 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) {
        // Handle 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.