Skip to main content

iOS SDK

Overview

The iOS SDK enables secure collection and reveal of sensitive data in native iOS applications, supporting both SwiftUI and UIKit.

Download SDK

Requirements

  • iOS: 14.0+
  • Swift: 5.9+
  • Xcode: 14.0+

Installation

  1. Download and extract the SDK package (SwiftPackage-0.0.1.zip)
  2. Move the secure-connect-sdk-ios folder to your project root
  3. In Xcode: File → Add Packages → Add Local
  4. Select the folder containing Package.swift

Configuration

Initialize the SDK with your gateway URL:

import SecureConnectSDK

let config = SecureConnectConfig(gatewayUrl: "https://api.connect.financial")

SecureConnectSDK.shared.initialize(with: config, authToken: "your-auth-token") { result in
switch result {
case .success:
print("SDK initialized successfully")
case .failure(let error):
print("Initialization failed: \(error)")
}
}

Token Management

Update the authentication token without reinitializing:

SecureConnectSDK.shared.updateToken("new-auth-token")

SwiftUI Integration

Collecting Sensitive Data

import SwiftUI
import SecureConnectSDK

struct SSNCollectionView: View {
@State private var isValid = false
@State private var isSubmitting = false
@State private var errorMessage: String?

var body: some View {
VStack(spacing: 16) {
SecureTextField(
operation: .submitDocumentSSN,
placeholder: "Enter SSN",
onValidationChange: { valid in
isValid = valid
}
)
.frame(height: 44)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(isValid ? Color.gray : Color.red, lineWidth: 1)
)

if let error = errorMessage {
Text(error)
.foregroundColor(.red)
.font(.caption)
}

Button(action: submitSSN) {
if isSubmitting {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
} else {
Text("Submit")
}
}
.disabled(!isValid || isSubmitting)
.frame(maxWidth: .infinity)
.padding()
.background(isValid ? Color.blue : Color.gray)
.foregroundColor(.white)
.cornerRadius(8)
}
.padding()
}

private func submitSSN() {
isSubmitting = true
errorMessage = nil

SecureConnectSDK.shared.submit(
operation: .submitDocumentSSN,
customerId: "customer-uuid"
) { result in
isSubmitting = false
switch result {
case .success(let response):
print("Token: \(response.token)")
case .failure(let error):
errorMessage = error.localizedDescription
}
}
}
}

Revealing Card Data

struct CardRevealView: View {
let cardId: String
@State private var isRevealed = false

var body: some View {
VStack(spacing: 16) {
// Card Number
SecureLabel(
operation: .revealCardPAN,
cardId: cardId,
serializer: .panWithDashes,
placeholder: "•••• •••• •••• ••••"
)
.frame(height: 44)
.frame(maxWidth: .infinity)
.background(Color(.systemGray6))
.cornerRadius(8)

HStack(spacing: 16) {
// Expiry Date
VStack(alignment: .leading) {
Text("Expiry")
.font(.caption)
.foregroundColor(.gray)
SecureLabel(
operation: .revealCardExpiry,
cardId: cardId,
serializer: .expiryShort,
placeholder: "••/••"
)
.frame(height: 44)
}

// CVV
VStack(alignment: .leading) {
Text("CVV")
.font(.caption)
.foregroundColor(.gray)
SecureLabel(
operation: .revealCardCVV,
cardId: cardId,
placeholder: "•••"
)
.frame(height: 44)
}
}

Button(action: toggleReveal) {
Text(isRevealed ? "Hide" : "Reveal Card Details")
}
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.padding()
}

private func toggleReveal() {
if isRevealed {
SecureConnectSDK.shared.hideAll()
} else {
SecureConnectSDK.shared.revealAll(cardId: cardId)
}
isRevealed.toggle()
}
}

Complete Card View Example

struct CardDetailsView: View {
let cardId: String
@State private var isRevealed = false

var body: some View {
VStack(spacing: 24) {
// Card visual representation
ZStack {
RoundedRectangle(cornerRadius: 16)
.fill(LinearGradient(
colors: [.blue, .purple],
startPoint: .topLeading,
endPoint: .bottomTrailing
))
.frame(height: 200)

VStack(alignment: .leading, spacing: 20) {
Spacer()

// Card Number
SecureLabel(
operation: .revealCardPAN,
cardId: cardId,
serializer: .panWithSpaces,
placeholder: "•••• •••• •••• ••••"
)
.font(.system(size: 22, weight: .medium, design: .monospaced))
.foregroundColor(.white)

HStack {
VStack(alignment: .leading) {
Text("VALID THRU")
.font(.caption2)
.foregroundColor(.white.opacity(0.7))
SecureLabel(
operation: .revealCardExpiry,
cardId: cardId,
serializer: .expiryShort,
placeholder: "••/••"
)
.foregroundColor(.white)
}

Spacer()

VStack(alignment: .leading) {
Text("CVV")
.font(.caption2)
.foregroundColor(.white.opacity(0.7))
SecureLabel(
operation: .revealCardCVV,
cardId: cardId,
placeholder: "•••"
)
.foregroundColor(.white)
}
}
}
.padding(24)
}

Button(action: toggleReveal) {
Label(
isRevealed ? "Hide Details" : "Show Details",
systemImage: isRevealed ? "eye.slash" : "eye"
)
}
.buttonStyle(.borderedProminent)
}
.padding()
}

private func toggleReveal() {
if isRevealed {
SecureConnectSDK.shared.hideAll()
} else {
SecureConnectSDK.shared.revealAll(cardId: cardId)
}
isRevealed.toggle()
}
}

UIKit Integration

Collecting Sensitive Data

import UIKit
import SecureConnectSDK

class SSNViewController: UIViewController {
private let secureTextField = SecureTextFieldUIKit()
private let submitButton = UIButton(type: .system)
private let errorLabel = UILabel()
private var isValid = false

override func viewDidLoad() {
super.viewDidLoad()
setupUI()
configureSecureField()
}

private func setupUI() {
view.backgroundColor = .systemBackground

// Configure secure text field
secureTextField.translatesAutoresizingMaskIntoConstraints = false
secureTextField.layer.borderWidth = 1
secureTextField.layer.borderColor = UIColor.systemGray4.cgColor
secureTextField.layer.cornerRadius = 8

// Configure error label
errorLabel.translatesAutoresizingMaskIntoConstraints = false
errorLabel.textColor = .systemRed
errorLabel.font = .preferredFont(forTextStyle: .caption1)
errorLabel.isHidden = true

// Configure submit button
submitButton.translatesAutoresizingMaskIntoConstraints = false
submitButton.setTitle("Submit", for: .normal)
submitButton.backgroundColor = .systemBlue
submitButton.setTitleColor(.white, for: .normal)
submitButton.layer.cornerRadius = 8
submitButton.addTarget(self, action: #selector(submitTapped), for: .touchUpInside)
submitButton.isEnabled = false

// Add subviews
view.addSubview(secureTextField)
view.addSubview(errorLabel)
view.addSubview(submitButton)

// Layout constraints
NSLayoutConstraint.activate([
secureTextField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
secureTextField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
secureTextField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
secureTextField.heightAnchor.constraint(equalToConstant: 44),

errorLabel.topAnchor.constraint(equalTo: secureTextField.bottomAnchor, constant: 4),
errorLabel.leadingAnchor.constraint(equalTo: secureTextField.leadingAnchor),

submitButton.topAnchor.constraint(equalTo: errorLabel.bottomAnchor, constant: 16),
submitButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
submitButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
submitButton.heightAnchor.constraint(equalToConstant: 44)
])
}

private func configureSecureField() {
secureTextField.configure(
operation: .submitDocumentSSN,
placeholder: "Enter SSN"
)

secureTextField.onValidationChange = { [weak self] isValid in
self?.isValid = isValid
self?.submitButton.isEnabled = isValid
self?.submitButton.backgroundColor = isValid ? .systemBlue : .systemGray
self?.secureTextField.layer.borderColor = isValid ? UIColor.systemGray4.cgColor : UIColor.systemRed.cgColor
self?.errorLabel.isHidden = isValid
self?.errorLabel.text = isValid ? nil : "Invalid SSN format"
}
}

@objc private func submitTapped() {
submitButton.isEnabled = false

SecureConnectSDK.shared.submit(
operation: .submitDocumentSSN,
customerId: "customer-uuid"
) { [weak self] result in
DispatchQueue.main.async {
self?.submitButton.isEnabled = self?.isValid ?? false

switch result {
case .success(let response):
print("Token: \(response.token)")
case .failure(let error):
self?.showError(error.localizedDescription)
}
}
}
}

private func showError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
}

Revealing Card Data

class CardRevealViewController: UIViewController {
private let panLabel = SecureLabelUIKit()
private let cvvLabel = SecureLabelUIKit()
private let expiryLabel = SecureLabelUIKit()
private let revealButton = UIButton(type: .system)

private let cardId: String
private var isRevealed = false

init(cardId: String) {
self.cardId = cardId
super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
super.viewDidLoad()
setupUI()
configureSecureLabels()
}

private func configureSecureLabels() {
panLabel.configure(
operation: .revealCardPAN,
cardId: cardId,
serializer: .panWithDashes,
placeholder: "•••• •••• •••• ••••"
)

cvvLabel.configure(
operation: .revealCardCVV,
cardId: cardId,
placeholder: "•••"
)

expiryLabel.configure(
operation: .revealCardExpiry,
cardId: cardId,
serializer: .expiryShort,
placeholder: "••/••"
)
}

@objc private func revealTapped() {
if isRevealed {
SecureConnectSDK.shared.hideAll()
revealButton.setTitle("Reveal", for: .normal)
} else {
SecureConnectSDK.shared.revealAll(cardId: cardId)
revealButton.setTitle("Hide", for: .normal)
}
isRevealed.toggle()
}
}

Async/Await Support

The iOS SDK supports modern async/await patterns:

// Submit document
func submitDocument() async throws {
let response = try await SecureConnectSDK.shared.submit(
operation: .submitDocumentSSN,
customerId: "customer-uuid"
)
print("Token: \(response.token)")
}

// Reveal card details
func revealCardDetails() async throws {
try await SecureConnectSDK.shared.reveal(
operation: .revealCardPAN,
cardId: "card-uuid",
serializer: .panWithDashes
)
}

// Usage in SwiftUI
struct AsyncSubmitView: View {
@State private var isLoading = false

var body: some View {
Button("Submit") {
Task {
isLoading = true
do {
try await submitDocument()
} catch {
print("Error: \(error)")
}
isLoading = false
}
}
.disabled(isLoading)
}
}

Serializers (Formatting)

The SDK supports serializers for formatting revealed data:

SerializerOutput FormatExample
.panWithDashesXXXX-XXXX-XXXX-XXXX4111-1111-1111-1111
.panWithSpacesXXXX XXXX XXXX XXXX4111 1111 1111 1111
.expiryShortMM/YY12/25
.expiryFullMM/YYYY12/2025

Supported Operations

Collect Operations

OperationDescription
.submitDocumentIDSubmit government-issued ID
.submitDocumentSSNSubmit Social Security Number
.submitDocumentDriversLicenseSubmit driver's license
.submitDocumentPassportSubmit passport

Reveal Operations

OperationDescription
.revealDocumentIDReveal government-issued ID
.revealDocumentSSNReveal Social Security Number
.revealDocumentDriversLicenseReveal driver's license
.revealDocumentPassportReveal passport
.revealCardPANReveal card number
.revealCardCVVReveal card CVV
.revealCardExpiryReveal card expiry date
.revealCardDataReveal all card data at once