Lite SDK (Enregistrement iOS)

Ce guide vous accompagne dans l'intégration du SDK Lite iOS de Yuno pour l'enregistrement dans votre projet.

Prérequis

Avant d'implémenter le SDK iOS de Yuno, assurez-vous que vous remplissez les conditions suivantes :

Étape 1 : Inclure la bibliothèque dans votre projet

Vous pouvez ajouter la bibliothèque en utilisant CocoaPods ou Swift Package Manager.

CocoaPods

Ajoutez le SDK Yuno à votre projet iOS en utilisant CocoaPods. Si vous n'avez pas de Podfile, suivez le guide CocoaPods pour en créer un. Ajoutez ensuite la ligne suivante à votre Podfile :

pod 'YunoSDK', '~> 1.1.22'

Puis exécutez l'installation :

installation du pod

Swift Package Manager

Ajoutez le SDK Yuno à l'aide du gestionnaire de paquets Swift. Ajoutez YunoSDK en tant que dépendance dans votre fichier Package.swift :

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

Étape 2 : Inscription d'une Nouvelle Méthode de Paiement

📘

Avant d'appeler Yuno.enrollPayment()assurez-vous d'avoir initialisé le SDK avec Yuno.initialize().

Le SDK iOS de Yuno offre une fonction d'inscription pour les méthodes de paiement. Pour afficher le flux d'inscription, implémentez le délégué et appelez la méthode d'inscription :

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() présente un UIViewController en plein écran modalement en utilisant le viewController fournie dans votre delegate. Cela ne fonctionne qu'avec UIKit. Dans SwiftUI, il suffit d'envelopper un UIViewController et le renvoie via viewController propriété. Le delegate doit exposer un contrôleur visible pour permettre au SDK de présenter l'interface utilisateur.

Paramètres

ParamètresDescription
customerSessionSe réfère à la session client du paiement en cours.
countryCodeCe paramètre détermine le pays pour lequel le processus de paiement est configuré. La liste complète des pays pris en charge et de leur code pays est disponible sur la page Couverture des pays.
languageDéfinit la langue à utiliser dans les formulaires de paiement. Vous pouvez choisir l'une des options linguistiques disponibles :
  • Es (Espagnol)
  • En (Anglais)
  • Po (Portugais)
  • Ph (Philippin)
  • In (Indonésien)
  • Ma (Malais)
  • Th (Thaïlandais)
  • zh-TW (chinois (traditionnel, taïwanais))
  • zh-CN (chinois (simplifié, Chine))
  • vi (vietnamien)
  • fr (français)
  • pl (polonais)
  • it (Italien)
  • de (allemand)
  • ru (russe)
  • tr (turc)
  • nl (néerlandais)
  • sv (suédois)
  • ko (coréen)
  • ja (japonais)
viewControllerCette propriété représente le UIViewController utilisé pour présenter le flux d'inscription. Même si la propriété reste facultative pour des raisons de compatibilité ascendante, vous devez fournir un contrôleur visible afin que le SDK puisse présenter correctement son interface utilisateur.
yunoEnrollmentResult(\_ result: Yuno.Result)Cette méthode est appelée lorsque le processus d'inscription est terminé et fournit le résultat de l'inscription en tant que paramètre de type Yuno.Result.

Le champ showPaymentStatus détermine si le statut du paiement doit être affiché. Passage true indique l'état du paiement, tandis que le passage de false le cache.

Paramètres

Le champ enrollPayment sont décrits ci-dessous :

ParamètresTypeDescription
delegateYunoEnrollmentDelegateL'objet délégué qui gère les rappels d'inscription.
showPaymentStatusBoolIndicateur booléen qui détermine s'il faut afficher les vues de statut pendant le processus d'inscription au paiement.

La méthode enrollPayment lance le processus d'inscription au paiement. Vous devez l'appeler en réponse aux interactions de l'utilisateur, par exemple en appuyant sur un bouton. La méthode utilise le fichier delegate pour gérer les événements liés à l'inscription et, sur la base du paramètre showPaymentStatusdécide d'afficher ou non des informations visuelles sur l'état de l'inscription.

Étape 3 : Statut d'inscription

❗️

Inscription aux liens profonds

Cette fonction n'est utilisée que si vous vous inscrivez à une méthode de paiement qui exécute des liens profonds. Si vous n'adhérez pas à une méthode de paiement qui exécute des liens profonds, vous pouvez ignorer l'étape 3.

Si vous utilisez un mode de paiement qui nécessite un lien profond pour revenir à votre application, utilisez la méthode décrite dans le bloc de code suivant pour obtenir le statut d'inscription dans votre AppDelegate. La url.scheme doit être la même que celle de la callback_url utilisé lors de la création du 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)
}
🚧

Exigences de Concurrence Swift 6

Si vous utilisez Swift 6, vous devrez implémenter le protocole YunoPaymentDelegate avec des considérations spécifiques sur la concurrence. Swift 6 introduit des exigences de sécurité des fils d'exécution plus strictes qui affectent la manière dont vous implémentez les délégués. Consultez la section  Implémentation de YunoPaymentDelegate avec la Concurrence Swift 6  pour les options d'implémentation détaillées et les meilleures pratiques.

Comprendre Yuno.Result

Lorsque le processus d'inscription est terminé, le SDK lance un appel :

func yunoEnrollmentResult(_ result: Yuno.Result)

Ce résultat peut refléter différents états finaux pour l'inscription. Le Yuno.Result énumération inclut :

énumération Résultat {
    cas succès
    cas échec
    cas rejet
    cas traitement
    cas internalError
 interne
    cas userCancell
 utilisateur
}

Vous pouvez utiliser un switch pour gérer chaque cas de résultat :

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'inclut pas de tokens ni de messages d'erreur. Vous n'obtiendrez qu'un statut de haut niveau pour vous aider à guider l'expérience de l'utilisateur.

Intégration du mode Rendu (inscription)

Le mode rendu offre une plus grande flexibilité de l'interface utilisateur pour l'inscription, vous permettant d'intégrer le flux d'inscription dans vos propres vues tout en utilisant les validations et la logique du SDK.

Fonction principale : startEnrollmentRenderFlow

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

Protocole YunoEnrollmentRenderFlow

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

func submitForm()

var needSubmit: Bool { get }
  • formView: Renvoie un AnyView avec le formulaire d'inscription (cartes/APM) si une UI est requise ; sinon nil.
  • submitForm: Déclenche les validations et procède à l'inscription si applicable.
  • needSubmit: Indique s'il faut afficher un bouton de soumission.

Flux d'Implémentation

Étape 1 : Créer une Instance de Flux d'inscription

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

Étape 2 : Obtenir et afficher le formulaire

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

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

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

Étape 3 : Gérer le Résultat de l'inscription

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

Fonctionnalités Complémentaires

Yuno iOS SDK fournit des services et des configurations supplémentaires que vous pouvez utiliser pour améliorer l'expérience des clients.

Option de Rendu

Lors de la présentation de l'inscription, vous pouvez également choisir l'une des options de rendu pour le formulaire de la carte. Les options suivantes sont disponibles :

  • ONE_STEP
  • STEP_BY_STEP

Pour modifier l'option de rendu, définissez l'option cardFormType égale l'une des options disponibles. Chaque option est présentée ci-dessous.

Loader

Contrôler l'utilisation du loader par le biais des options de configuration du SDK.

Personnalisations du SDK

Utilisez les Personnalisations du SDK pour modifier l'apparence du SDK afin qu'il corresponde à votre marque.

📘

Application Démo

En plus des exemples de code fournis, vous pouvez accéder au dépôt Yuno pour une implémentation complète des SDK iOS de Yuno.

Implémentation de YunoPaymentDelegate avec la Concurrence Swift 6

Swift 6 introduit des exigences de concurrence plus strictes qui affectent la manière dont vous implémentez le protocole YunoPaymentDelegate . Cette section explique les défis et fournit des solutions pour différents scénarios d'implémentation.

📘

Comprendre la Concurrence dans Swift 6

La concurrence est la capacité de votre application à gérer plusieurs tâches simultanément. Avec Swift 6, les règles de concurrence sont devenues plus rigoureuses afin d'améliorer la stabilité de l'application et de prévenir les plantages. Cela signifie que votre code doit être structuré plus soigneusement pour garantir la sécurité des fils d'exécution et une gestion appropriée des tâches.

Le Problème

Avec Swift 6, les protocoles qui héritent de Sendable exigent que toutes leurs implémentations soient sécurisées pour les fils d'exécution. Cela génère des avertissements lorsque l'on implémente le délégué dans des classes marquées avec @MainActor.

La sécurité des fils d'exécution signifie que votre code peut être appelé en toute sécurité à partir de plusieurs fils d'exécution sans provoquer de plantage ou de comportement inattendu. @MainActor assure l'exécution du code sur le fil d'exécution principal (fil d'exécution de l'interface utilisateur).

Notre Décision de Conception

Nous ne marquons pas les protocoles comme @MainActor car :

  • Cela obligerait toutes les implémentations à être MainActor compatible
  • Cela réduirait la flexibilité des commerçants qui n'utilisent pas MainActor
  • Chaque implémentation a des besoins de concurrence différents

Responsabilité du commerçant

Il incombe au commerçant de gérer la concurrence en fonction de son implémentation. Vous trouverez ci-dessous trois approches différentes que vous pouvez utiliser en fonction de vos besoins spécifiques.

Option 1 : Propriétés immuables

Cette approche utilise des propriétés immuables qui sont automatiquement sécurisées pour les fils d'exécution, les rendant idéales pour des configurations simples. Elle est la mieux adaptée aux applications simples avec des valeurs de configuration fixes qui ne changent pas pendant l'exécution.

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

Option 2 : Propriétés mutables avec MainActor.assumeIsolated

Cette approche, idéale pour les applications où les valeurs de configuration pourraient changer pendant l'exécution (comme les préférences utilisateur), permet des propriétés mutables tout en maintenant la sécurité des fils d'exécution grâce à l'utilisation 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 }
    }
}

Option 3 : Pour les non MainActor cours

Cette approche convient aux classes de service qui ne nécessitent pas MainActor isolement, ce qui le rend idéal pour les services d'arrière-plan ou les classes utilitaires qui n'interagissent pas avec l'interface utilisateur.

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

⚠️ Considérations Importantes

Lors de l'implémentation de la concurrence dans votre délégué, gardez ces points clés à l'esprit :

  • MainActor.assumeIsolated: À utiliser uniquement lorsque vous garantissez qu'il est appelé depuis MainActorIl s'agit d'un mécanisme de sécurité qui indique à Swift « fais-moi confiance, je sais que cela s'exécute sur le thread principal ».
  • nonisolated: Cela signifie qu'il est accessible depuis n'importe quel thread, il doit donc être thread-safe. Utilisez cette option lorsque vos propriétés ou méthodes ne dépendent pas de l'état de l'interface utilisateur.
  • viewController: Reste en @MainActor car il doit toujours être accédé depuis le fil d'exécution principal. Les composants de l'interface utilisateur doivent toujours s'exécuter sur le fil principal pour éviter les plantages.