Code Examples iOS SDK

Ready-to-use iOS code examples for common scenarios.

Example 1: Basic UIKit Payment

import UIKit
import YunoSDK

class PaymentViewController: UIViewController, YunoPaymentFullDelegate {
    
    @IBOutlet weak var payButton: UIButton!
    
    @IBAction func payButtonTapped() {
        startPayment()
    }
    
    func startPayment() {
        Task {
            let session = try await createSession(amount: 2500)
            
            await MainActor.run {
                let config = YunoConfig(
                    checkoutSession: session.id,
                    countryCode: "US"
                )
                Yuno.startPayment(with: config, delegate: self)
            }
        }
    }
    
    func createSession(amount: Int) async throws -> CheckoutSession {
        var request = URLRequest(url: URL(string: "https://api.example.com/checkout")!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try JSONSerialization.data(withJSONObject: [
            "amount": ["currency": "USD", "value": amount],
            "customer_id": "cus_123"
        ])
        
        let (data, _) = try await URLSession.shared.data(for: request)
        return try JSONDecoder().decode(CheckoutSession.self, from: data)
    }
    
    func yunoPaymentResult(_ result: PaymentResult) {
        if result.status == .succeeded {
            performSegue(withIdentifier: "showSuccess", sender: nil)
        } else {
            showAlert(title: "Error", message: result.error?.message ?? "Payment failed")
        }
    }
}

Example 2: SwiftUI Payment

import SwiftUI
import YunoSDK

struct CheckoutView: View {
    @State private var showSuccess = false
    @State private var errorMessage: String?
    
    var body: some View {
        VStack {
            Text("$25.00")
                .font(.largeTitle)
            
            Button("Pay Now") {
                Task { await processPayment() }
            }
            .buttonStyle(.borderedProminent)
        }
        .alert("Success!", isPresented: $showSuccess) {
            Button("OK") { }
        }
        .alert("Error", isPresented: .constant(errorMessage != nil)) {
            Button("OK") { errorMessage = nil }
        } message: {
            Text(errorMessage ?? "")
        }
    }
    
    func processPayment() async {
        do {
            let session = try await createCheckoutSession()
            
            await MainActor.run {
                let config = YunoConfig(
                    checkoutSession: session.id,
                    countryCode: "US"
                )
                Yuno.startPayment(with: config, delegate: self)
            }
        } catch {
            errorMessage = error.localizedDescription
        }
    }
    
    func createCheckoutSession() async throws -> CheckoutSession {
        // API call implementation
        fatalError("Implement API call")
    }
}

extension CheckoutView: YunoPaymentFullDelegate {
    func yunoPaymentResult(_ result: PaymentResult) {
        if result.status == .succeeded {
            showSuccess = true
        } else {
            errorMessage = result.error?.message
        }
    }
}

Example 3: Subscription Enrollment

class SubscriptionVC: UIViewController, YunoEnrollmentDelegate {
    
    func enrollCard() {
        Task {
            let session = try await createCustomerSession(customerId: "cus_123")
            
            await MainActor.run {
                let config = YunoConfig(
                    customerSession: session.id,
                    countryCode: "US"
                )
                Yuno.enrollPayment(with: config, delegate: self)
            }
        }
    }
    
    func yunoEnrollmentResult(_ result: EnrollmentResult) {
        if result.status == .succeeded {
            saveVaultedToken(result.vaultedToken)
            setupSubscription(vaultedToken: result.vaultedToken)
        }
    }
    
    func setupSubscription(vaultedToken: String) {
        Task {
            try await apiClient.post("/subscriptions", body: [
                "customer_id": "cus_123",
                "vaulted_token": vaultedToken,
                "plan": "premium_monthly"
            ])
            
            await MainActor.run {
                showAlert("Subscription activated!")
            }
        }
    }
}

Example 4: One-Click Payment

class FastCheckoutVC: UIViewController {
    var savedCards: [SavedCard] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        loadSavedCards()
    }
    
    func loadSavedCards() {
        Task {
            savedCards = try await apiClient.get("/customer/cards")
            tableView.reloadData()
        }
    }
    
    func payWithSavedCard(_ card: SavedCard) {
        Task {
            let session = try await createCheckoutSession()
            
            await MainActor.run {
                let config = YunoConfig(
                    checkoutSession: session.id,
                    countryCode: "US",
                    vaultedToken: card.vaultedToken
                )
                Yuno.startPayment(with: config, delegate: self)
            }
        }
    }
}

extension FastCheckoutVC: YunoPaymentFullDelegate {
    func yunoPaymentResult(_ result: PaymentResult) {
        if result.status == .succeeded {
            navigateToOrderConfirmation()
        }
    }
}

Example 5: Custom Payment Method Selection

class CustomSelectionVC: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    var paymentMethods: [PaymentMethod] = []
    
    func loadPaymentMethods() async {
        do {
            let session = try await createCheckoutSession()
            paymentMethods = try await fetchPaymentMethods(session: session.id)
            tableView.reloadData()
        } catch {
            showError(error)
        }
    }
    
    func fetchPaymentMethods(session: String) async throws -> [PaymentMethod] {
        let url = URL(string: "https://api.y.uno/v1/checkout/sessions/\(session)/payment-methods")!
        var request = URLRequest(url: url)
        request.setValue("pk_test_your_key", forHTTPHeaderField: "X-Yuno-Api-Key")
        
        let (data, _) = try await URLSession.shared.data(for: request)
        let response = try JSONDecoder().decode(PaymentMethodsResponse.self, from: data)
        return response.paymentMethods
    }
    
    func didSelectPaymentMethod(_ method: PaymentMethod) {
        let config = YunoConfig(
            checkoutSession: currentSession.id,
            countryCode: "US"
        )
        
        Yuno.startPaymentLite(
            with: config,
            paymentType: method.type,
            delegate: self
        )
    }
}

Example 6: Render Mode Integration

class RenderModeVC: UIViewController, YunoPaymentRenderFlowProtocol {
    
    @IBOutlet weak var paymentContainerView: UIView!
    
    func startPayment() {
        Task {
            let session = try await createCheckoutSession()
            
            await MainActor.run {
                let config = YunoConfig(
                    checkoutSession: session.id,
                    countryCode: "US"
                )
                Yuno.startPaymentRenderFlow(with: config, delegate: self)
            }
        }
    }
    
    func formView() -> UIView? {
        return paymentContainerView
    }
    
    func submitForm() async {
        // Form submitted
    }
    
    func yunoPaymentResult(_ result: PaymentResult) {
        if result.status == .succeeded {
            navigateToSuccess()
        }
    }
}

Example 7: Error Handling with Retry

class PaymentWithRetryVC: UIViewController {
    var retryCount = 0
    let maxRetries = 3
    
    func attemptPayment() {
        Task {
            do {
                let session = try await createCheckoutSession()
                await startPayment(session: session)
            } catch {
                await handlePaymentError(error)
            }
        }
    }
    
    func handlePaymentError(_ error: Error) async {
        if retryCount < maxRetries {
            retryCount += 1
            try? await Task.sleep(nanoseconds: 2_000_000_000) // 2s delay
            attemptPayment()
        } else {
            await MainActor.run {
                showAlert("Payment failed after \(maxRetries) attempts")
            }
        }
    }
}

extension PaymentWithRetryVC: YunoPaymentFullDelegate {
    func yunoPaymentResult(_ result: PaymentResult) {
        if result.status == .succeeded {
            retryCount = 0
            navigateToSuccess()
        } else if result.status == .failed {
            Task { await handlePaymentError(result.error!) }
        }
    }
}

Example 8: Analytics Integration

import FirebaseAnalytics

class PaymentWithAnalyticsVC: UIViewController {
    
    func startPayment() {
        Analytics.logEvent("checkout_started", parameters: [
            "value": 25.00,
            "currency": "USD"
        ])
        
        Task {
            let session = try await createCheckoutSession()
            let config = YunoConfig(checkoutSession: session.id, countryCode: "US")
            Yuno.startPayment(with: config, delegate: self)
        }
    }
}

extension PaymentWithAnalyticsVC: YunoPaymentFullDelegate {
    func yunoPaymentResult(_ result: PaymentResult) {
        switch result.status {
        case .succeeded:
            Analytics.logEvent(AnalyticsEventPurchase, parameters: [
                "transaction_id": result.paymentId,
                "value": 25.00,
                "currency": "USD"
            ])
            navigateToSuccess()
            
        case .failed:
            Analytics.logEvent("payment_failed", parameters: [
                "error": result.error?.code ?? "unknown"
            ])
            showError(result.error?.message)
            
        default:
            break
        }
    }
}

Example 9: Custom Styling

class StyledPaymentVC: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureYunoAppearance()
    }
    
    func configureYunoAppearance() {
        var appearance = Yuno.Appearance()
        
        appearance.primaryColor = UIColor(red: 0.2, green: 0.4, blue: 0.8, alpha: 1.0)
        appearance.backgroundColor = .systemBackground
        appearance.textColor = .label
        appearance.errorColor = .systemRed
        appearance.fontFamily = "SF Pro Display"
        appearance.fontSize = 16
        appearance.cornerRadius = 12
        
        Yuno.setAppearance(appearance)
    }
    
    func startPayment() {
        // Payment flow uses custom appearance
    }
}

Example 10: Multi-Platform ViewModel

import Combine

class PaymentViewModel: ObservableObject {
    @Published var paymentState: PaymentState = .idle
    @Published var errorMessage: String?
    
    enum PaymentState {
        case idle, processing, succeeded, failed
    }
    
    func processPayment(amount: Int) async {
        await MainActor.run {
            paymentState = .processing
        }
        
        do {
            let session = try await createCheckoutSession(amount: amount)
            await startYunoPayment(session: session)
        } catch {
            await MainActor.run {
                paymentState = .failed
                errorMessage = error.localizedDescription
            }
        }
    }
    
    private func startYunoPayment(session: CheckoutSession) async {
        await MainActor.run {
            let config = YunoConfig(checkoutSession: session.id, countryCode: "US")
            Yuno.startPayment(with: config, delegate: self)
        }
    }
}

extension PaymentViewModel: YunoPaymentFullDelegate {
    func yunoPaymentResult(_ result: PaymentResult) {
        Task { @MainActor in
            if result.status == .succeeded {
                paymentState = .succeeded
            } else {
                paymentState = .failed
                errorMessage = result.error?.message
            }
        }
    }
}

// Usage in SwiftUI
struct PaymentView: View {
    @StateObject private var viewModel = PaymentViewModel()
    
    var body: some View {
        VStack {
            switch viewModel.paymentState {
            case .idle:
                Button("Pay $25") {
                    Task { await viewModel.processPayment(amount: 2500) }
                }
            case .processing:
                ProgressView()
            case .succeeded:
                Text("Payment successful!")
            case .failed:
                Text("Error: \(viewModel.errorMessage ?? "")")
            }
        }
    }
}

Backend API Helper

class YunoAPIClient {
    static let shared = YunoAPIClient()
    
    func createCheckoutSession(amount: Money, customerId: String) async throws -> CheckoutSession {
        var request = URLRequest(url: URL(string: "https://api.example.com/checkout")!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        let body: [String: Any] = [
            "amount": ["currency": amount.currency, "value": amount.value],
            "customer_id": customerId,
            "country": "US"
        ]
        
        request.httpBody = try JSONSerialization.data(withJSONObject: body)
        
        let (data, _) = try await URLSession.shared.data(for: request)
        return try JSONDecoder().decode(CheckoutSession.self, from: data)
    }
    
    func createCustomerSession(customerId: String) async throws -> CustomerSession {
        var request = URLRequest(url: URL(string: "https://api.example.com/customer/session")!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try JSONSerialization.data(withJSONObject: [
            "customer_id": customerId
        ])
        
        let (data, _) = try await URLSession.shared.data(for: request)
        return try JSONDecoder().decode(CustomerSession.self, from: data)
    }
}