Skip to content

Latest commit

 

History

History
462 lines (328 loc) · 24.1 KB

docs.md

File metadata and controls

462 lines (328 loc) · 24.1 KB

Installation Guide

This guide details how to install the Payrails SDK into your iOS project using CocoaPods.

Prerequisites:

  • CocoaPods installed.
  • Your Xcode project targets iOS 14.0 or later.

Installation Steps:

  1. Add Payrails to your Podfile:
    If you don't have a Podfile in your project's root directory, run pod init in your terminal from that directory. Then, open the Podfile and add the following line within your target's dependencies:

    target 'YourAppTargetName' do
      use_frameworks! # Ensure you are using frameworks
    
      # Add the Payrails Checkout SDK
      pod 'Payrails/Checkout', '~> 1.0.0' # Or specify the version you need
    
      # ... other pods
    end

    Note: Using~> 1.0.0 will install the latest compatible version within the 1.0.x range. You can remove the version specifier ('Payrails/Checkout') to always get the absolute latest version, or specify an exact version.

  2. Install the Pod:
    Close Xcode. Open your terminal, navigate to your project's root directory (where the Podfile is located), and run:

    pod install
  3. Use the .xcworkspace:
    After the installation is complete, always open your project using the .xcworkspace file generated by CocoaPods, not the .xcodeproj file.

    open YourProjectName.xcworkspace
  4. Import the Module:
    You can now import the Payrails SDK module in your Swift files where needed:

Initializing the Payrails SDK

Before you can display any Payrails UI components (like the Card Payment Form or PayPal Button), you need to initialize a Payrails.Session. This session holds the configuration and state for the user's payment interaction.

Prerequisites:

  1. SDK Installation: Ensure the Payrails SDK is correctly installed in your project (see Installation Guide).
  2. Payrails.InitData: You must obtain an instance of Payrails.InitData.
    • This data is crucial and must be fetched from your backend. Your server will typically interact with the Payrails API, providing transaction details (like amount, currency, references, user info), to generate this InitData.
    • The SDK does not handle the network request to fetch this data. You are responsible for implementing this API call. The InitSettings and the API call shown in the example TestViewController are illustrative of how you might fetch this data; they are not part of the SDK itself.

Initialization Steps:

  1. ObtainPayrails.InitData: Fetch this data from your backend server. Let's assume you have it in a variable named fetchedInitData.

  2. DefinePayrails.Options (Optional): Configure SDK options, such as the environment (.prod or .sandbox).

    // Example: Configure for the production environment
    let options = Payrails.Options(env: .prod)
    // Or for development:
    // let options = Payrails.Options(env: .dev)
  3. CreatePayrails.Configuration: Combine the fetched InitData and any custom Options.

    // Assuming 'fetchedInitData' is the Payrails.InitData obtained from your backend
    let configuration = Payrails.Configuration(
        initData: fetchedInitData,
        option: options // Use the options defined above
    )
  4. CallPayrails.configure: Use the static configure function, passing the configuration. This is an asynchronous operation.

    // This function should be called within an async context (e.g., Task or async function)
    do {
        // This asynchronously configures and returns the session
        let payrailsSession = try await Payrails.configure(with: configuration)
    
        // **Important:** Store the 'payrailsSession' instance.
        // You will need it to create UI components later.
        self.payrails = payrailsSession // Store it in a property
    
        // Proceed to set up UI components (e.g., Card Form, PayPal Button)
        // Example: self.setupCardPaymentForm()
        // Example: self.setupPayPalButton()
    
        print("✅ Payrails SDK Initialized successfully. Execution ID: \(payrailsSession.executionId ?? "N/A")")
    
    } catch {
        // Handle initialization errors (e.g., invalid data, network issues during internal setup)
        print("❌ Failed to initialize Payrails SDK: \(error.localizedDescription)")
        // Update UI to show error state
    }
  5. Store the Session: Keep a reference to the returned Payrails.Session object (e.g., in a view controller property like var payrails: Payrails.Session?). This object is required to create and manage Payrails UI elements.

After successfully initializing the SDK and storing the payrailsSession, you can proceed to create and display payment components like Payrails.createCardPaymentForm(...) or Payrails.createPayPalButton(...).

Card Payment Form (Payrails.CardPaymentForm)

The Payrails SDK provides a pre-built UI component, Payrails.CardPaymentForm, to securely collect card payment details from the user. It handles input validation, formatting, and interacts with the Payrails system for processing.

Prerequisites:

  • A configured Payrails.Session must be available. Ensure you have successfully called Payrails.configure(...) and stored the resulting session object before attempting to create a card form. See the Initializing the Payrails SDK section.

Creating the Card Payment Form

Use the static factory method Payrails.createCardPaymentForm(...) to get an instance of the form. This method requires an active Payrails.Session.

// Ensure you have a valid Payrails.Session stored, e.g., in self.payrails
guard let payrails = self.payrails else {
    print("Error: Payrails session not initialized.")
    return // Or handle the error appropriately
}

// 1. Create the form instance (examples):
// Simple creation with defaults
let paymentForm = Payrails.createCardPaymentForm()

/* Other creation examples:
// Creation with a custom button title
let paymentFormWithTitle = Payrails.createCardPaymentForm(buttonTitle: "Pay €10.00")

// Creation with custom configuration (styles, text - see configuration section below)
let customConfig = CardFormConfig(...) // Define your config
let paymentFormWithConfig = Payrails.createCardPaymentForm(config: customConfig, buttonTitle: "Complete Payment")
*/

// 2. **Essential Step:** Assign Delegate and Presenter
//    (See explanations below)
paymentForm.delegate = self // 'self' is typically your ViewController conforming to PayrailsCardPaymentFormDelegate
paymentForm.presenter = self // 'self' is typically your ViewController conforming to PaymentPresenter

// 3. Add the form to your view hierarchy (See "Adding the Form" section)
// view.addSubview(paymentForm) // Or add to a stack view, etc.
// ... setup constraints ...

Why Delegate and Presenter are Required:

After creating the paymentForm instance, you must assign objects to its delegate and presenter properties. These are crucial for the form to function correctly within your app:

  • delegate (Type: PayrailsCardPaymentFormDelegate):

    • Purpose: To receive feedback and results from the Payrails SDK. Your delegate object gets notified about important events during the payment lifecycle.
    • What it tells you:
      • When the user clicks the payment button (onPaymentButtonClicked).
      • Whether the payment authorization succeeded (onAuthorizeSuccess).
      • Whether the payment authorization failed (onAuthorizeFailed).
      • When an external challenge like 3D Secure is required (onThreeDSecureChallenge).
    • Who implements it: Typically, the View Controller that manages the CardPaymentForm.
    • Details: See the Handling Events (PayrailsCardPaymentFormDelegate) section for detailed implementation guidance.
    • Reference: Refer to Events Glossary to see available events.
  • presenter (Type: PaymentPresenter):

    • Purpose: To allow the Payrails SDK to request UI presentations from your application when needed. Certain payment flows (most notably 3D Secure authentication) require showing new view controllers modally (e.g., a web view loading the bank's challenge page).
    • What it allows the SDK to do: Call the presentPayment(_:) method on your presenter object, passing the specific UIViewController that the SDK needs to display. Your implementation of this method handles the actual presentation logic (e.g., self.present(viewController, animated: true)).
    • Who implements it: Typically, the View Controller that manages the CardPaymentForm, as it has the capability to present other view controllers within the app's navigation flow.
    • Details: See the Handling External UI Flows (PaymentPresenter) section for detailed implementation guidance.

In summary: The delegate enables your app to listen to the SDK's status updates and results, while the presenter empowers the SDK to request necessary UI actions (specifically, view controller presentations) from your app. Both properties must be assigned for the card form to handle the complete payment lifecycle, including potential challenges like 3D Secure.

Configuring the Form (CardFormConfig)

You can customize the appearance, labels, placeholders, and error messages of the card form by passing a CardFormConfig object during creation using Payrails.createCardPaymentForm(config: ...). If no config is provided, sensible defaults will be used.

The CardFormConfig struct allows you to specify:

  • showNameField (Bool): Set to true to include the "Name on Card" input field in the form. Defaults to false.
  • styles ([CardFieldType: CardFormStyle]?): A dictionary where keys are CardFieldType enum cases (e.g., .CARD_NUMBER, .EXPIRATION_DATE, .CVV, .CARDHOLDER_NAME) and values are CardFormStyle objects. This allows fine-grained control over the visual appearance of each field.
  • translations (CardTranslations?): An object containing customized text for labels, placeholders, and error messages used within the form.

1. Customizing Styles (CardFormStyle):

To change the look and feel of the input fields, provide a styles dictionary within your CardFormConfig. Each entry maps a specific field type (CardFieldType) to a CardFormStyle configuration.

A CardFormStyle object lets you define the appearance for different states of an input field using nested Style objects:

  • baseStyle: The default appearance when the field is idle.
  • focusStyle: Appearance when the user taps into the field and it gains focus.
  • completedStyle: Appearance when the field's input is considered complete (e.g., enough digits entered for a card number). Note: This doesn't guarantee validity.
  • invalidStyle: Appearance when the input fails validation (e.g., incorrect card number format, expired date).
  • labelStyle: Style applied to the text label associated with the field (e.g., "Card Number").
  • errorTextStyle: Style applied to the validation error message text displayed below the field when invalidStyle is active.

Each Style object allows setting properties like:
borderColor, borderWidth, backgroundColor, textColor, font, cornerRadius, padding, textAlignment, etc.

Example:

// Example: Customizing Card Number and CVV fields

// Define a custom style for the card number field
let customPadding = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15)
let customCardNumberStyle = CardFormStyle(
    baseStyle: Style(borderColor: .systemGray, padding: customPadding, borderWidth: 1.0, cornerRadius: 4),
    focusStyle: Style(borderColor: .blue, borderWidth: 2.0, backgroundColor: .systemGray6),
    invalidStyle: Style(borderColor: .red, borderWidth: 1.5),
    labelStyle: Style(textColor: .darkGray, font: .systemFont(ofSize: 14, weight: .medium))
)

// Define a custom style for the CVV field
let customCvvStyle = CardFormStyle(
    baseStyle: Style(cornerRadius: 8, backgroundColor: .systemTeal.withAlphaComponent(0.1)),
    labelStyle: Style(textColor: .blue),
    invalidStyle: Style(borderColor: .orange, borderWidth: 2)
)

// Create the styles dictionary mapping field types to their custom styles
let customStyles: [CardFieldType: CardFormStyle] = [
    .CARD_NUMBER: customCardNumberStyle,
    .CVV: customCvvStyle
    // Add entries for .EXPIRATION_DATE, .CARDHOLDER_NAME etc. if needed
]

// Create the CardFormConfig incorporating these styles
let cardFormConfig = CardFormConfig(styles: customStyles)

// Pass this config when creating the form
// let paymentForm = Payrails.createCardPaymentForm(config: cardFormConfig)

Merging: Custom styles are intelligently merged over the default styles provided by the SDK. You only need to specify the properties you want to change for each style state (baseStyle, focusStyle, etc.). Unspecified properties will retain their default values.

2. Customizing Text (CardTranslations):

To change the default text displayed in the form (labels, placeholders, error messages), create a CardTranslations object and assign it to the translations property of your CardFormConfig.

The CardTranslations object structure allows customization of:

  • placeholders: A CardTranslations.Placeholders object. Its values dictionary maps CardFieldType to custom placeholder strings (the grey text shown before input).
  • labels: A CardTranslations.Labels object. Its values dictionary maps CardFieldType to custom label strings (the text usually displayed above the field). It also includes properties for other form text like saveInstrument, storeInstrument, paymentInstallments.
  • error: A CardTranslations.ErrorMessages object. Its values dictionary maps CardFieldType to custom validation error message strings shown when input is invalid.

Example:

// Example: Customizing placeholders, labels, and error messages

let customPlaceholders = CardTranslations.Placeholders(
    values: [
        .CARD_NUMBER: "Enter your 16-digit card number",
        .CVV: "3 or 4 digits"
    ]
)

let customLabels = CardTranslations.Labels(
    values: [
        .CARD_NUMBER: "Credit/Debit Card Number",
        .CVV: "Security Code (CVV)"
    ],
    // You can also customize other labels like:
    saveInstrument: "Save this card securely for future payments"
)

let customErrorValues: [CardFieldType: String] = [
    .CARD_NUMBER: "Invalid card number provided. Please double-check.",
    .EXPIRATION_DATE: "Expiry date must be in MM/YY format and in the future."
]
let customErrors = CardTranslations.ErrorMessages(values: customErrorValues)

// Create the main translations object
let translations = CardTranslations(
    placeholders: customPlaceholders,
    labels: customLabels,
    error: customErrors
)

// Create the CardFormConfig incorporating these translations
// Also showing the 'showNameField' option here for completeness
let cardFormConfig = CardFormConfig(
    showNameField: true, // Include the name field
    translations: translations
    // You can combine styles and translations in the same config:
    // styles: customStyles // Assuming customStyles is defined elsewhere
)

// Pass this config when creating the form
// let paymentForm = Payrails.createCardPaymentForm(config: cardFormConfig)

Merging: Similar to styles, custom translations are merged with the default translations provided by the SDK. You only need to provide overrides for the specific text elements you want to change. Untouched elements will use the SDK's default text.

PayPal Button (Payrails.PayPalButton)

The Payrails SDK offers a ready-to-use UI component, Payrails.PayPalButton, to seamlessly integrate PayPal as a payment method in your iOS application. This button handles the necessary interactions with the PayPal flow, simplifying the integration process for merchants.

Prerequisites:

  • A configured Payrails.Session must be available. Ensure you have initialized the Payrails SDK successfully and have a valid session object before creating a PayPal button. Refer to the Initializing the Payrails SDK section for details.

Creating the PayPal Button

To instantiate a Payrails.PayPalButton, use the static factory method Payrails.createPayPalButton(). This method requires an active Payrails.Session.

// Ensure you have a valid Payrails.Session stored, e.g., in self.payrails
guard let payrails = self.payrails else {
    print("Error: Payrails session not initialized.")
    return // Handle error appropriately
}

// 1. Create the PayPal Button instance:
let payPalButton = Payrails.createPayPalButton()

// 2. **Crucial Step:** Assign Delegate and Presenter
//    (Explanations below)
payPalButton.delegate = self // 'self' is typically your ViewController conforming to PayrailsPayPalButtonDelegate
payPalButton.presenter = self // 'self' is typically your ViewController conforming to PaymentPresenter

// 3. Customize the button (Optional):
payPalButton.setTitle("Pay with PayPal", for: .normal) // Set a custom title
payPalButton.isEnabled = true // Ensure the button is enabled

// 4. Add the button to your view hierarchy (See "Adding the Button" section)
// view.addSubview(payPalButton) // Or add to a stack view, etc.
// ... setup constraints ...

Why Delegate and Presenter are Required

Similar to the Card Payment Form, the Payrails.PayPalButton requires you to set its delegate and presenter properties for proper functionality. These are essential for handling events and UI presentations during the PayPal payment flow:

  • delegate (Type: PayrailsPayPalButtonDelegate):

    • Purpose: To receive notifications and results from the Payrails SDK specifically related to the PayPal payment process initiated by the button. Your delegate object will be informed about key events in the PayPal payment lifecycle.
    • What it tells you:
      • When the user taps the PayPal button (onPaymentButtonClicked).
      • Whether the PayPal payment authorization succeeded (onAuthorizeSuccess).
      • Whether the PayPal payment authorization failed (onAuthorizeFailed).
      • If the PayPal payment session expired or was cancelled by the user on the PayPal side (onPaymentSessionExpired).
    • Who implements it: Typically, the View Controller that is managing the Payrails.PayPalButton.
    • Details: See the Handling Events (PayrailsPayPalButtonDelegate) section for detailed implementation guidance.
    • Reference: Refer to Events Glossary to see available events.
  • presenter (Type: PaymentPresenter):

    • Purpose: To allow the Payrails SDK to request UI presentations from your application when necessary during the PayPal payment flow. This is how the SDK can present the PayPal payment authorization UI (typically a web view or modal sheet) to the user.
    • What it allows the SDK to do: Call the presentPayment(_:) method on your presenter object, passing the UIViewController that contains the PayPal authorization UI. Your implementation of this method is responsible for presenting this view controller within your app (e.g., using self.present(viewController, animated: true)).
    • Who implements it: Usually, the View Controller that manages the Payrails.PayPalButton, as it is responsible for presenting other view controllers in your app's UI flow.
    • Details: See the Handling External UI Flows (PaymentPresenter) section for detailed implementation guidance.

In essence: The delegate allows your application to react to PayPal payment events and outcomes, while the presenter empowers the SDK to initiate necessary UI actions (specifically, presenting view controllers for PayPal authorization) within your app's context. Both delegate and presenter must be set for the PayPal button to function correctly and handle the complete PayPal payment flow.

Customizing the PayPal Button

The Payrails.PayPalButton offers limited customization options directly. You can primarily customize:

  • Title: Set the text displayed on the button using the setTitle(_:for:) method. For example: payPalButton.setTitle("Checkout with PayPal", for: .normal).
  • Enabled State: Control whether the button is interactive using the isEnabled property. Set to true to enable user interaction and false to disable it.

For more advanced styling or visual customization, you might need to subclass Payrails.PayPalButton (if it's designed to be subclassable - check the SDK code) or wrap it within a container view to apply further styling. However, for most common use cases, setting the title and enabled state should be sufficient.

Adding the Button to Your UI

Payrails.PayPalButton is a UIView subclass, so you can add it to your view hierarchy like any other UIKit view. Common approaches include:

  • Adding as a subview directly to your UIViewController's main view: view.addSubview(payPalButton)
  • Adding to a UIStackView: This is often recommended for layout flexibility, especially if you have multiple payment options or form elements. As seen in the TestViewController example, adding to a UIStackView simplifies arrangement and spacing.
  • Using Auto Layout constraints: After adding the button to your view hierarchy, you will need to set up Auto Layout constraints to define its position and size within its parent view.

Refer to standard UIKit documentation and tutorials for guidance on adding subviews and setting up Auto Layout constraints.

Example Usage in a View Controller

import UIKit
import Payrails

class MyViewController: UIViewController, PayrailsPayPalButtonDelegate, PaymentPresenter {

    private var payPalButton: Payrails.PayPalButton?
    private var payrailsSession: Payrails.Session? // Assume this is configured and set

    override func viewDidLoad() {
        super.viewDidLoad()
        setupPayPal()
    }

    private func setupPayPal() {
        guard let payrailsSession = self.payrailsSession else {
            print("Error: Payrails session is not available.")
            return
        }

        let button = Payrails.createPayPalButton()
        button.delegate = self
        button.presenter = self
        button.setTitle("Pay with PayPal", for: .normal)
        button.isEnabled = true
        self.payPalButton = button

        view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
            // ... other constraints for width, height, etc. ...
        ])
    }

    // MARK: - PayrailsPayPalButtonDelegate Methods

    func onPaymentButtonClicked(_ button: Payrails.PayPalButton) {
        print("PayPal button tapped!")
        // Handle button tap event (optional - delegate methods are called during payment execution)
    }

    func onAuthorizeSuccess(_ button: Payrails.PayPalButton) {
        print("PayPal payment authorized successfully!")
        // Payment success handling logic
    }

    func onAuthorizeFailed(_ button: Payrails.PayPalButton) {
        print("PayPal payment authorization failed.")
        // Payment failure handling logic
    }

    func onPaymentSessionExpired(_ button: Payrails.PayPalButton) {
        print("PayPal session expired or cancelled by user.")
        // Handle session expiration (e.g., user cancellation)
    }

    // MARK: - PaymentPresenter Method

    func presentPayment(_ viewController: UIViewController) {
        DispatchQueue.main.async {
            self.present(viewController, animated: true)
        }
    }

    var encryptedCardData: String? { // Implementation required by PaymentPresenter - not used for PayPal, can be a stub
        get { return nil }
        set { }
    }
}

This section provides a comprehensive guide to using the Payrails.PayPalButton in your iOS application. Remember to consult the Handling Events (PayrailsPayPalButtonDelegate) and Handling External UI Flows (PaymentPresenter) sections for details on implementing the delegate and presenter protocols.