Lite SDK (Enrollment iOS)

Este guia o orienta na integração do SDK Lite iOS da Yuno para registro em seu projeto.

Requisitos

Antes de implementar o SDK do Yuno para iOS, verifique se você atende a esses requisitos:

Etapa 1: Inclua a biblioteca em seu projeto

Você pode adicionar a biblioteca usando o CocoaPods ou o Swift Package Manager.

CocoaPods

Adicione o Yuno SDK ao seu projeto iOS usando o CocoaPods. Se você não tiver um Podfile, siga o guia do CocoaPods para criar um. Em seguida, adicione a seguinte linha ao seu Podfile:

pod 'YunoSDK', '~> 1.1.22'

Em seguida, execute a instalação:

instalação do pod

Gerenciador de pacotes Swift

Adicione o Yuno SDK usando o Swift Package Manager. Adicionar YunoSDK como uma dependência em seu arquivo Package.swift:

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

Etapa 2: Registre um novo método de pagamento

📘

Antes de ligar Yuno.enrollPayment()certifique-se de ter inicializado o SDK com Yuno.initialize().

O SDK iOS da Yuno fornece um recurso de registro para métodos de pagamento. Para exibir o fluxo de registro, implemente o delegado e chame o método de registro:

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() apresenta uma tela inteira UIViewController modalmente usando o viewController fornecido em seu delegate. Isso funciona apenas no UIKit. No SwiftUI, envolva um UIViewController e retorná-lo por meio do viewController propriedade. O delegate deve expor um controlador visível para permitir que o SDK apresente a interface do usuário.

Parâmetros

ParâmetroDescrição
customerSessionRefere-se à sessão do cliente do pagamento atual.
countryCodeEsse parâmetro determina o país para o qual o processo de pagamento está sendo configurado. A lista completa de países compatíveis e seu código de país está disponível na página Cobertura do país.
languageDefine o idioma a ser usado nos formulários de pagamento. Você pode defini-lo como uma das opções de idioma disponíveis:
  • es (espanhol)
  • en (inglês)
  • pt (português)
  • fil (filipino)
  • id (indonésio)
  • ms (malaio)
  • th (tailandês)
  • zh-TW (chinês (tradicional, Taiwan))
  • zh-CN (chinês (simplificado, China))
  • vi (vietnamita)
  • fr (francês)
  • pl (polonês)
  • it (italiano)
  • de (alemão)
  • ru (russo)
  • tr (turco)
  • nl (holandês)
  • sv (sueco)
  • ko (coreano)
  • ja (japonês)
viewControllerEssa propriedade representa o UIViewController usado para apresentar o fluxo de inscrição. Embora a propriedade continue sendo opcional para compatibilidade com versões anteriores, você deve fornecer um controlador visível para que o SDK possa apresentar sua interface do usuário corretamente.
yunoEnrollmentResult(\_ result: Yuno.Result)Esse método é chamado quando o processo de registro é concluído, fornecendo o resultado do registro como um parâmetro do tipo Yuno.Result.

O showPaymentStatus determina se o status do pagamento deve ser exibido. Passando true mostra o status do pagamento, enquanto a passagem de false oculta.

Parâmetros

O enrollPayment Os parâmetros do método são descritos abaixo:

ParâmetroTipoDescrição
delegateYunoEnrollmentDelegateO objeto delegado que lida com as chamadas de retorno de registro.
showPaymentStatusBoolUm marcador booleano que determina se as exibições de status devem ser mostradas durante o processo de registro de pagamento.

O método enrollPayment inicia o processo de registro de pagamento. Você deve chamá-lo em resposta às interações do usuário, como pressionar um botão. O método utiliza o delegate para gerenciar eventos de registro e, com base no parâmetro showPaymentStatusdecide se deve mostrar feedback visual sobre o status do registro.

Etapa 3: Status da inscrição

❗️

Registro de Deep Link

Esse recurso só é usado se você se inscrever em um método de pagamento que executa deep links. Se você não estiver inscrito em um método de pagamento que executa deep links, poderá ignorar a Etapa 3.

Se você usar um método de pagamento que exija um link direto para retornar ao seu aplicativo, use o método descrito no bloco de código a seguir para obter o status de inscrição em seu AppDelegate. O url.scheme deve ser o mesmo que o callback_url usado ao criar o 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 simultaneidade do Swift 6

Se estiver usando o Swift 6, você precisará implementar o YunoPaymentDelegate com considerações específicas de simultaneidade. O Swift 6 apresenta requisitos mais rigorosos de segurança de thread que afetam a forma como você implementa os delegados. Consulte a seção Implementação YunoPaymentDelegate com Swift 6 Concurrency para obter opções de implementação detalhadas e práticas recomendadas.

Compreensão Yuno.Result

Quando o processo de registro é concluído, o SDK chama:

func yunoEnrollmentResult(_ resultado: Yuno.Result)

Este resultado pode refletir diferentes estados finais para a inscrição. O Yuno.Result A enumeração inclui:

enum Resultado {
    caso sucesso
    caso falha
    caso rejeição
    caso processamento
    caso internalError
 interno
    caso userCancell

}

Você pode usar um switch para tratar 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 não inclui tokens ou mensagens de erro. Você obterá apenas um status de alto nível para ajudá-lo a orientar a experiência do usuário.

Integração do modo de renderização (registro)

O modo de renderização oferece maior flexibilidade de interface do usuário para o registro, permitindo que você integre o fluxo de registro em suas próprias exibições enquanto usa as validações e a lógica do SDK.

Função principal: startEnrollmentRenderFlow

@MainActor static func startEnrollmentRenderFlow(
    com delegate: YunoEnrollmentDelegate
) async -> some YunoEnrollmentRenderFlowProtocol

YunoEnrollmentRenderFlowProtocol

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

func submitForm()

var needSubmit: Bool { get }
  • formView: Retorna um AnyView com o formulário de registro (cartões/APMs) se a UI for necessária; caso contrário nil.
  • submitForm: Aciona validações e prossegue com o registro quando aplicável.
  • needSubmit: Indica se você deve renderizar um botão de envio.

Fluxo de implementação

Etapa 1: criar instância de fluxo de registro

let enrollmentFlow = aguardar Yuno.startEnrollmentRenderFlow(com: self)

Etapa 2: Obter e exibir o formulário

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

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

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

Etapa 3: Manipular o resultado do registro

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

Recursos complementares

O Yuno iOS SDK oferece serviços e configurações adicionais que você pode usar para melhorar a experiência dos clientes.

Opção de renderização

Ao apresentar o registro, você também pode escolher uma das opções de renderização para o formulário do cartão. Você tem as seguintes opções:

  • ONE_STEP
  • STEP_BY_STEP

Para alterar a opção de renderização, defina a opção cardFormType igual a uma das opções disponíveis. Cada opção é apresentada a seguir.

Carregador

Controle o uso do carregador por meio das opções de configuração do SDK.

Personalizações do SDK

Use as personalizações do SDK para alterar a aparência do SDK de acordo com sua marca.

📘

Aplicativo de demonstração

Além dos exemplos de código fornecidos, você pode acessar o repositório Yuno para obter uma implementação completa dos SDKs do Yuno para iOS.

Implementação YunoPaymentDelegate com Swift 6 Concurrency

O Swift 6 apresenta requisitos de simultaneidade mais rígidos que afetam a forma como você implementa o YunoPaymentDelegate protocolo. Esta seção explica os desafios e oferece soluções para diferentes cenários de implementação.

📘

Entendendo a simultaneidade no Swift 6

A simultaneidade é a capacidade do seu aplicativo de gerenciar várias tarefas simultaneamente. Com o Swift 6, as regras de simultaneidade se tornaram mais rigorosas para aumentar a estabilidade do aplicativo e evitar falhas. Isso significa que seu código deve ser estruturado com mais cuidado para garantir a segurança dos threads e o gerenciamento adequado das tarefas.

O problema

Com o Swift 6, os protocolos que herdam do Sendable exigem que todas as suas implementações sejam thread-safe. Isso gera avisos ao implementar o delegado em classes marcadas como @MainActor.

Thread-safe significa que seu código pode ser chamado com segurança de vários threads sem causar falhas ou comportamento inesperado. @MainActor garante que o código seja executado no thread principal (thread da interface do usuário).

Nossa decisão de design

Não marcamos protocolos como @MainActor porque:

  • Isso forçaria todas as implementações a serem MainActor compatível
  • Isso reduziria a flexibilidade para os comerciantes que não usam MainActor
  • Cada implementação tem necessidades de simultaneidade diferentes

Responsabilidade do comerciante

É responsabilidade do comerciante lidar com a simultaneidade de acordo com sua implementação. Abaixo estão três abordagens diferentes que você pode usar, dependendo de suas necessidades específicas.

Opção 1: Propriedades imutáveis

Essa abordagem usa propriedades imutáveis que são automaticamente thread-safe, o que as torna ideais para configurações simples. Ela é mais adequada para aplicativos simples com valores de configuração fixos que não mudam durante o tempo de execução.

@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
        }
    }
}

Opção 2: Propriedades mutáveis com MainActor.assumeIsolated

Essa abordagem, melhor para aplicativos em que os valores de configuração podem ser alterados durante o tempo de execução (como as preferências do usuário), permite propriedades mutáveis e, ao mesmo tempo, mantém a segurança do thread usando 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 }
    }
}

Opção 3: Para não MainActor aulas

Essa abordagem é adequada para classes de serviço que não requerem MainActor o que o torna melhor para serviços em segundo plano ou classes utilitárias que não interagem com a interface do usuário.

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

⚠️ Considerações importantes

Ao implementar a simultaneidade em seu delegado, tenha em mente estes pontos-chave:

  • MainActor.assumeIsolated: Use apenas quando você garantir que ele seja chamado de MainActor. Esse é um mecanismo de segurança que diz ao Swift "confie em mim, eu sei que isso está sendo executado no thread principal".
  • nonisolated: Significa que pode ser acessado de qualquer thread, portanto, deve ser thread-safe. Use-o quando suas propriedades ou métodos não dependerem do estado da interface do usuário.
  • viewController: Permanece como @MainActor porque ele deve ser sempre acessado pelo thread principal. Os componentes da interface do usuário devem sempre ser executados no thread principal para evitar falhas.