Mobile SDK - iOS

This document will guide you on how to install PowerBoard iOS SDK and Integrate into your app.

Overview

The PowerBoard iOS MobileSDK seamlessly integrates with PowerBoard services to easily build a payments flow in your iOS app.

The SDK provides a customisable experience with pre-built UI widgets that handle and support various payment methods.

Once you have setup and initialised the MobileSDK in your application, you can use the MobileSDK widgets to access payment flows. These include interacting with below payment methods.

You can also complete 3DS challenges, capture addresses and tokenise card details.

  • Card Payments
    • Secure card tokenisation with validation
  • Apple Pay
    • Native Apple Pay integration
  • PayPal
    • PayPal payments and vault functionality
  • Afterpay
    • Buy now, pay later integration
  • Click to Pay
    • MasterCard, Visa and AMEX unified checkout solution
  • 3D Secure
    • Integrated 3DS authentication
  • Address Collection
    • Smart address autocomplete

Requirements

  • PowerBoard iOS SDK: GitHub Repository
  • PowerBoard Account
  • iOS Version: 16.2 and above
  • Xcode: Latest stable version recommended
  • Swift: 5.7.1 or later
  • Dependencies:
    • NetworkingLib (1.2.0)
    • Afterpay SDK (5.7.1)
    • PayPal iOS SDK (1.5.0)

Configuration

The sample app uses .xcconfig file to manage environment-specific settings. Each environment has a corresponding .xcconfig file containing key-value pairs used during the build process.

These values are injected into the app at buildtime. The files are PreProduction.xcconfig, and Production.xcconfig

📘

Note:

You only need to fill the *.xcconfig file for the environments you are actively working on.

For example, if you are working on PreProduction, you can omit the file for Production, as it is not required for your current build. In that case you only need to fill the PreProduction.xcconfig file.

Ensure the necessary configuration files are in filled before running the app to avoid missing variable errors.

*.xcconfig Files

Environments: The sample app supports three environments: PreProduction and Production. You'll need to provide values for each environment.

  • Location: Files are already created and are located in the ExampleApp/Configs/ directory of the project.
  • Structure: The *.xcconfig file should contain key-value pairs for each configuration setting.
  • Required Fields: The following fields are used in the config.properties file:
  • API_ACCESS_TOKEN: The PowerBoard API access token for the specified environment (e.g., PreProduction and Production). This token is used by the sample app to make direct calls to the Powerboard API for tasks like creating customers or managing transactions.
  • WIDGET_ACCESS_TOKEN: The PowerBoard Widget/UI access token for the specified environment. This token is used by the PowerBoard SDK to authenticate and authorise the use of the pre-built UI widgets for payment processing.
  • APPLE_PAY_GATEWAY_ID: Your PowerBoard service ID for the MPGS (Mastercard Payment Gateway Services) gateway. This ID is required to process card payments, handle 3D Secure (3DS) authentication, ApplePay and manage other card-related transactions.
  • PAY_PAL_GATEWAY_ID: Your PowerBoard service ID for the PayPal gateway. This ID is necessary to enable PayPal as a payment method within the sample app.
  • AFTERPAY_GATEWAY_ID: Your PowerBoard service ID for the Afterpay gateway. This ID is required to enable Afterpay as a payment method.
  • MASTERCARD_SERVICE_ID: Your PowerBoard service ID for the ClickToPay gateway. This ID is required to enable ClickToPay as a payment method.
  • INTEGRATED_3DS_GATEWAY_ID: Your PowerBoard service ID for the Integrated 3DS service. This ID is required to enable 3DS check.
  • MERCHANT_ID: Your ApplePay merchant ID. This ID is required to enable ApplePay test payments in sample app.

Example *.xcconfig:

// Authentication keys
API_ACCESS_TOKEN = your_api_access_token
WIDGET_ACCESS_TOKEN = your_widget_access_token 

// Gateway keys
APPLE_PAY_GATEWAY_ID = your_gateway_id_mpgs
PAY_PAL_GATEWAY_ID = your_gateway_id_pay_pal
INTEGRATED_3DS_GATEWAY_ID = your_integrated_3ds_gateway_id
MASTERCARD_SERVICE_ID = your_gateway_id_click_to_pay
AFTERPAY_GATEWAY_ID = your_gateway_id_after_pay
MERCHANT_ID = your_merchant_id

📘

Note:

Replace the placeholder values (e.g., your_api_access_token) with your actual keys and IDs.

Installation

Swift Package Manager

Add the SDK to your project using Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/CommBank-PowerBoard/powerboard-ios-mobile-sdk", from: "4.0.0")
]

Manual Integration

  • Clone the repository
  • Drag the Sources/MobileSDK folder into your Xcode project
  • Ensure all dependencies are properly linked

SDK Initialization

Basic Setup

Initialise the SDK in your app's main entry point:

import SwiftUI
import MobileSDK

@main
struct YourApp: App {
    
    init() {
        setupMobileSDK()
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
    
    private func setupMobileSDK() {
        let config = MobileSDKConfig(
            environment: .preProduction, // or .production, .staging
            theme: customTheme, // Optional custom theme
            enableTestMode: true // Only for non-production environments
        )
        
        MobileSDK.shared.configureMobileSDK(config: config)
    }
}

Environment Configuration

The SDK supports two environments:

public enum SDKEnvironment: String {
    case production     // api.powerboard.commbank.com.au
    case preProduction  // api.preproduction.powerboard.commbank.com.au
}

Configuration Options

public struct MobileSDKConfig {
    var environment: SDKEnvironment
    let theme: Theme?           // Custom theme (optional)
    let enableTestMode: Bool    // Test mode flag (forced false in production)
}

Payment Widgets

Card Details Widget

The CardDetailsWidget provides secure card tokenisation with comprehensive validation.

Basic Implementation

import SwiftUI
import MobileSDK

struct CardPaymentView: View {
    @State private var showAlert = false
    @State private var alertMessage = ""
    
    var body: some View {
        CardDetailsWidget(
            config: CardDetailsWidgetConfig(
                gatewayId: "your_gateway_id", // Optional
                accessToken: "your_widget_access_token",
                actionText: "Pay Now",
                showCardTitle: true,
                collectCardholderName: true,
                allowSaveCard: SaveCardConfig(
                    consentText: "Save this card for future payments",
                    privacyPolicyConfig: SaveCardConfig.PrivacyPolicyConfig(
                        privacyPolicyText: "Privacy Policy",
                        privacyPolicyURL: "https://your-privacy-policy.com"
                    )
                ),
                schemeSupport: SupportedSchemesConfig(
                    supportedSchemes: [.visa, .mastercard, .amex],
                    enableValidation: true
                )
            ),
            appearance: CardDetailsWidgetAppearance(), // Custom appearance
            completion: { result in
                switch result {
                case .success(let cardResult):
                    // Handle successful tokenization
                    let token = cardResult.token
                    let shouldSaveCard = cardResult.saveCard
                    handlePayment(token: token, saveCard: shouldSaveCard)
                    
                case .failure(let error):
                    // Handle error
                    alertMessage = error.customMessage
                    showAlert = true
                }
            }
        )
        .alert("Payment Error", isPresented: $showAlert) {
            Button("OK") { }
        } message: {
            Text(alertMessage)
        }
    }
    
    private func handlePayment(token: String, saveCard: Bool?) {
        // Process payment with token
    }
}

Configuration Options

public struct CardDetailsWidgetConfig {
    public let accessToken: String              // Required: Widget access token
    public let gatewayId: String?              // Required: Gateway ID
    public let actionText: String              // Button text (default: "Submit")
    public let showCardTitle: Bool             // Show "Card information" title
    public let collectCardholderName: Bool     // Collect cardholder name
    public let allowSaveCard: SaveCardConfig?  // Save card functionality
    public let schemeSupport: SupportedSchemesConfig // Supported card schemes
}

Supported Card Schemes

public enum CardScheme: String, CaseIterable {
    case visa = "visa"
    case mastercard = "mastercard"
    case amex = "american_express"
    case discover = "discover"
    case jcb = "jcb"
}

Apple Pay Widget

The ApplePayWidget provides native Apple Pay integration.

Implementation

import SwiftUI
import MobileSDK
import PassKit

struct ApplePayView: View {
    var body: some View {
        ApplePayWidget(
            appearance: ApplePayWidgetAppearance(),
            createPaymentRequest: { completion in
                // Create Apple Pay request
                let request = MobileSDK.createApplePayRequest(
                    amount: 99.99,
                    amountLabel: "Total",
                    countryCode: "AU",
                    currencyCode: "AUD",
                    merchantIdentifier: "merchant.your.app.id",
                    requireBillingAddress: true,
                    requireShippingAddress: false
                )
                
                let token = "your_wallet_token"
                completion(.success(ApplePayRequestResult(request: request, token: token)))
            },
            completion: { result in
                switch result {
                case .success(let chargeResponse):
                    // Handle successful payment
                    print("Payment successful: \(chargeResponse.status)")
                    
                case .failure(let error):
                    // Handle error
                    print("Payment failed: \(error.customMessage)")
                }
            }
        )
        .frame(height: 50)
    }
}

Apple Pay Helper

The PowerBoard iOS SDK provides a convenient helper for creating Apple Pay requests:

public static func createApplePayRequest(
    amount: Decimal,
    amountLabel: String,
    countryCode: String,
    currencyCode: String,
    merchantIdentifier: String,
    merchantCapabilities: PKMerchantCapability = [.capabilityCredit, .capabilityDebit, .capability3DS],
    supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard, .amex, .discover],
    requireBillingAddress: Bool = true,
    requireShippingAddress: Bool = false,
    shippingOptions: [PKShippingMethod]? = nil
) -> PKPaymentRequest

PayPal Widget

The PayPalWidget supports PayPal payments with web-based authentication.

Implementation

struct PayPalView: View {
    @StateObject private var viewState = ViewState()
    
    var body: some View {
        PayPalWidget(
            viewState: viewState,
            appearance: PayPalWidgetAppearance(),
            loadingDelegate: self, // Optional loading delegate
            tokenRequest: { completion in
                // Initialize PayPal payment
                initializePayPalPayment(completion: completion)
            },
            completion: { result in
                switch result {
                case .success(let chargeResponse):
                    // Handle successful payment
                    handlePayPalSuccess(chargeResponse)
                    
                case .failure(let error):
                    // Handle error
                    handlePayPalError(error)
                }
            }
        )
        .frame(height: 48)
    }
    
    private func initializePayPalPayment(completion: @escaping (Result<WalletTokenResult, WalletTokenError>) -> Void) {
        // Create wallet charge request and get token
        // This typically involves calling your backend API
    }
}

extension PayPalView: WidgetLoadingDelegate {
    func loadingDidStart() {
        // Handle loading start
    }
    
    func loadingDidFinish() {
        // Handle loading finish
    }
}

Afterpay Widget

The AfterpayWidget integrates Afterpay's buy now, pay later service.

Implementation

import Afterpay

struct AfterpayView: View {
    var body: some View {
        AfterpayWidget(
            viewState: ViewState(),
            configuration: AfterpaySdkConfig(
                config: Configuration(
                    maximumAmount: "1000.00",
                    currency: "AUD"
                ),
                environment: .sandbox, // or .production
                options: CheckoutV3Options()
            ),
            appearance: AfterpayWidgetAppearance(
                colorScheme: .blackOnMint,
                type: .payNow
            ),
            tokenRequest: { completion in
                // Initialize Afterpay payment
                initializeAfterpayPayment(completion: completion)
            },
            selectAddress: { address, provideShippingOptions in
                // Handle address selection
                let shippingOptions = getShippingOptions(for: address)
                provideShippingOptions(shippingOptions)
            },
            selectShippingOption: { shippingOption, provideUpdate in
                // Handle shipping option selection
                let update = getShippingUpdate(for: shippingOption)
                provideUpdate(update)
            },
            completion: { result in
                switch result {
                case .success(let chargeResponse):
                    // Handle successful payment
                    handleAfterpaySuccess(chargeResponse)
                    
                case .failure(let error):
                    // Handle error
                    handleAfterpayError(error)
                }
            }
        )
    }
}

Address Widget

The AddressWidget provides smart address collection with autocomplete functionality.

Implementation

struct AddressCollectionView: View {
    var body: some View {
        AddressWidget(
            config: AddressWidgetConfig(
                address: nil // Pre-populate with existing address if available
            ),
            appearance: AddressWidgetAppearance(),
            completion: { address in
                // Handle collected address
                handleAddressCollection(address)
            }
        )
    }
    
    private func handleAddressCollection(_ address: Address) {
        print("Collected address: \(address)")
        // Process the collected address
    }
}

3D Secure Widget

The Integrated3DSWidget handles 3D Secure authentication.

Implementation

struct ThreeDSView: View {
    let token3DS: String
    
    var body: some View {
        Integrated3DSWidget(
            config: Integrated3DSWidgetConfig(token: token3DS),
            completion: { result in
                switch result {
                case .success(let threeDSResult):
                    // Handle successful 3DS authentication
                    handle3DSSuccess(threeDSResult)
                    
                case .failure(let error):
                    // Handle 3DS error
                    handle3DSError(error)
                }
            }
        )
    }
}

PayPal Data Collection

Collect device data using PayPalDataCollectorUtil:

import MobileSDK

class PayPalDataCollector {
    private let dataCollector: PayPalDataCollectorUtil
    
    init(clientId: String) {
        self.dataCollector = PayPalDataCollectorUtil(clientId: clientId)
    }
    
    func collectDeviceData() -> String? {
        do {
            let deviceData = try dataCollector.collectDeviceId()
            return deviceData
        } catch {
            print("Failed to collect device data: \(error)")
            return nil
        }
    }
}

Customisation & Theming

Global Theme System

The PowerBoard iOS SDK uses a comprehensive theming system based on the Theme structure:

public struct Theme {
    public var textField: TextFieldAppearance
    public var searchDropdown: SearchDropdownAppearance
    public var actionButton: ButtonAppearance
    public var expandSectionButton: ButtonAppearance
    public var toolbarButton: ButtonAppearance
    public var loader: OverlayLoaderAppearance
    public var toggle: ToggleAppearance
    public var linkText: TextAppearance
    public var toggleText: TextAppearance
    public var title: TextAppearance
}

Creating Custom Themes

// Create custom theme
let customTheme = Theme(
    textField: TextFieldAppearance(
        colors: TextFieldColors(
            background: .white,
            text: .black,
            border: .gray,
            focusedBorder: .blue,
            errorBorder: .red,
            placeholder: .lightGray
        ),
        dimensions: TextFieldDimensions(
            cornerRadius: 8.0,
            borderWidth: 1.0,
            padding: EdgeInsets(top: 12, leading: 16, bottom: 12, trailing: 16)
        ),
        fonts: TextFieldFonts(
            text: CustomFont(size: 16, weight: .regular),
            placeholder: CustomFont(size: 16, weight: .regular),
            title: CustomFont(size: 14, weight: .medium),
            error: CustomFont(size: 12, weight: .regular)
        )
    ),
    actionButton: ButtonAppearance(
        colors: ButtonColors(
            background: .blue,
            text: .white,
            border: .clear,
            disabledBackground: .gray,
            disabledText: .lightGray
        ),
        dimensions: ButtonDimensions(
            cornerRadius: 8.0,
            borderWidth: 0.0,
            padding: EdgeInsets(top: 16, leading: 24, bottom: 16, trailing: 24)
        ),
        fonts: ButtonFonts(
            title: CustomFont(size: 16, weight: .semibold)
        )
    )
)

// Apply theme during SDK initialization
let config = MobileSDKConfig(
    environment: .preProduction,
    theme: customTheme
)

Widget-Specific Appearances

Each widget supports individual appearance customisation:

Card Details Widget Appearance

let cardAppearance = CardDetailsWidgetAppearance(
    textField: TextFieldAppearance(/* custom text field styling */),
    actionButton: ButtonAppearance(/* custom button styling */),
    toolbarButton: ButtonAppearance(/* custom toolbar button styling */),
    toggle: ToggleAppearance(/* custom toggle styling */),
    linkText: TextAppearance(/* custom link text styling */),
    toggleText: TextAppearance(/* custom toggle text styling */),
    title: TextAppearance(/* custom title styling */),
    verticalSpacing: 16.0,
    horizontalSpacing: 12.0
)

Apple Pay Widget Appearance

let applePayAppearance = ApplePayWidgetAppearance(
    style: .black, // .black, .white, .whiteOutline
    type: .buy,    // .buy, .setUp, .inStore, .donate, .checkout, .book, .subscribe, .reload, .addMoney, .topUp, .order, .rent, .support, .contribute, .tip
    cornerRadius: 8.0
)

Error Handling

Error Types

The SDK defines specific error types for different scenarios:

Card Details Errors

public enum CardDetailsError: Error {
    case errorTokenisingCard(error: ErrorRes)
    case unknownError
    
    public var customMessage: String {
        switch self {
        case let .errorTokenisingCard(error): 
            return error.error?.message ?? "Error tokenising card"
        case .unknownError: 
            return "Unknown error occurred"
        }
    }
}

Apple Pay Errors

public enum ApplePayError: Error {
    case errorChargingWallet(error: ErrorRes)
    case unknownError
    case userCancelled
}

PayPal Errors

public enum ApplePayError: Error {
    case errorChargingWallet(error: ErrorRes)
    case unknownError
    case userCancelled
}

Troubleshooting

  1. SDK Initialisation Fails

    1. Problem: SDK not properly initialised
    2. Solution: Ensure MobileSDK.shared.configureMobileSDK(config:) is called before using widgets
    3. // Correct initialization
      @main
      struct App: App {
          init() {
              let config = MobileSDKConfig(environment: .preProduction)
              MobileSDK.shared.configureMobileSDK(config: config)
          }
      }
      
  2. Widget Not Displaying

    1. Problem: Widget appears blank or doesn't render

    2. Solutions:

      1. Check access token validity

      2. Verify network connectivity

      3. Ensure proper SwiftUI view hierarchy

      4. // Debug widget rendering
        CardDetailsWidget(config: config) { result in
            print("Widget result: \(result)")
        }
        .onAppear {
            print("Widget appeared")
        }
        .frame(minHeight: 300) // Ensure adequate space
        
        

Running the Sample App

  1. Clone the Repository: bash git clone https://github.com/CommBank-PowerBoard/powerboard-ios-mobile-sdk
  2. Open in Xcode: Open the ExampleApp/ExampleApp.xcodeproj file in Xcode.
  3. Select a Build Variant: In Xcode, select environment to run from the dropdown in the top Xcode top navigation bar and choose one of the following:
    1. ExampleApp PreProduction
    2. ExampleApp Production

Run the App: Click the "Run" button (gray play icon) in Xcode to build and run the sample app on a simulator or a connected device.