This guide helps you migrate your code from version 1.x or 2.0.0-beta1 to 2.0.0-beta2.
Version 2.0 of the SDK transitions from delgate-based flows to completion handler-based flows. This change simplifies the integration and provides better compatibility with modern async/await patterns.
This SDK uses CoreSDKError
as its unified error type across all operations. All errors returned by the SDK, whether from card payments, PayPal flows, or networking operations, are instances of CoreSDKError
.
This allows for consistent error handling across different payment methods and operations.
In v2.0, cancellations (e.g., 3DS cancellations, PayPal web flow cancellations) are now returned as errors rather than as separate delegate methods.
- The
CoreSDKError
is now equatable, enabling direct comparison of errors:
// Now possible in 2.0.0-beta2
if error == CardError.threeDSecureCanceledError {
// Handle 3DS Cancellation
}
// Instead of checking properties individually before and helper function in 2.0.0-beta1
- Public Access to Domain-Specific Error Enums:
Previously internal error enums like
CardError
andNetworkingError
are now public, along with their static properties that returnCoreSDKError
instances. This provides better discoverability and type safety when working with specific error cases.
public enum CardError {
public static let threeDSecureCanceledError: CoreSDKError
public static let encodingError: CoreSDKError
//...other error constants
}
public enum NetworkingError {
public static let urlSessionError: CoreSDKError
public static let serverResponseError: (String) -> CoreSDKError
//...other error constants
}
- Error Handling Examples
Using Completion Handlers
// Completion handlers return CoreSDKError, so no casting is needed in completion blocks
cardClient.vault(request) { result, error in
if let error {
// You can now use the public error enums directly
switch error {
case CardError.threeDSecureCanceledError:
// Handle 3DS cancellation
case NetworkingError.urlSessionError:
// Handle netowrk error
default:
// Handle other errors
}
return
}
if let result {
// Handle success
}
}
Using Async/Await
do {
let result = cardClient.vault(request)
// handle success
} catch let error as CoreSDKError {
// Make sure to cast to CoreSDKError when using try-catch
switch error {
case CardError.threeDSecureCanceledError:
// Handle 3DS cancellation
case NetworkingError.urlSessionError:
// Handle netowrk error
default:
// Handle other errors
}
} catch {
// Handle unexpected errors
}
// Alternative approach using if-else
do {
let result = try await cardClient.vault(request)
// Handle success
} catch let error as CoreSDKError {
if error == CardError.threeDSecureCanceledError {
// Handle 3DS Cancellation
} else {
// Handle other CoreSDKErrors
}
} catch {
// Handle unexpected errors
}
}
- Take advantage of
Equatable
for simpler error comparisons - Use the public error enum properties for better code clarity and type safety
- The helper methods
CardError.isThreeDSecureCanceled(Error)
,PayPalError.isCheckoutCanceled(Error)
,PayPalError.isVaultCanceled(Error)
are still available and are particularly useful if you only need to handle specific cases like cancellation and want to avoid casting to CoreSDKError in catch blocks:
// If you only care about handling cancellation, this might be simpler:
do {
let result = try await cardClient.vault(request)
// Handle success
} catch {
if CardError.isThreeDSecureCanceled(error) {
// Handle cancellation
} else {
// Handle other errors
}
}
// Old Delgate-based
class MyViewController: CardDelegate {
func setupPayment() {
let cardClient = CardClient(config: config)
cardClient.delegate = self
cardClient.approveOrder(request: cardRequest)
}
func card(_ cardClient: CardClient, didFinishWithResult result: CardResult) {
// Handle success
}
func card(_ cardClient: CardClient, didFinishWithError error: Error) {
// Handle error
}
func cardDidCancel(_ cardClient: CardClient) {
// Handle cancellation
}
}
// New (Completion-based)
class MyViewController {
func setupPayment() {
let cardClient = CardClient(config: config)
cardClient.approveOrder(request: cardRequest) { [weak self] result, error in
if let error = error {
// handle errors
return
}
if let result = result {
// handle success
}
}
}
}
// Old (Delegate-based)
class MyViewController: PayPalWebCheckoutDelegate {
func startPayPalFlow() {
let payPalClient = PayPalWebCheckoutClient(config: config)
payPalClient.delegate = self
payPalClient.approveOrder(request: paypalRequest)
}
func payPal(_ payPalClient: PayPalWebCheckoutClient, didFinishWithResult result: PayPalWebCheckoutResult) {
// Handle success
}
func payPal(_ payPalClient: PayPalWebCheckoutClient, didFinishWithError error: Error) {
// Handle error
}
func payPalDidCancel(_ payPalClient: PayPalCheckoutClient) {
// Handle cancellation
}
}
// New (Completion-based)
class MyViewController {
func setupPayment() {
let payPalClient = PayPalWebCheckoutClient(config: config)
payPalClient.start(request: paypalRequest) { [weak self] result, error in
if let error = error {
// handle errors
return
}
if let result = result {
// handle success
}
}
}
}
The SDK now provides async/await support, offering a more concise way to handle asynchronous operations.
class MyViewController {
func setupPayment() async {
let cardClient = CardClient(config: config)
do {
let result = try await cardClient.approveOrder(request: cardRequest)
// payment successful
handleSuccess(result)
} catch {
handleError(error)
}
}
}
- Note about using async/await functions: Our async/await functions utilize
withCheckedContinuation
There were crashes reported in use ofwithCheckedContinuation
with Xcode 16 beta 5+ with earlier iOS 18 beta versions. Also there were reported issues with MacCatalyst apps usingwithCheckedContinuation
built with Xcode 16 and running on MacOS 14-. The fix for MacCatalyst apps was released with Xcode 16.2 beta. swiftlang/swift#76218 (comment)
class MyViewController {
func startPayPalFlow() async {
let payPalClient = PayPalWebCheckoutClient(config: config)
do {
let result = try await payPalClient.start(request: paypalRequest)
// Payment successful
handleSuccess(result)
} catch {
handleError()
}
}
}
- Update your dependency manager (CocoaPods or SPM) to the latest SDK version
// Remove delegate protocol conformance
- class MyViewController: CardDelegate {
+ class MyViewController {
// Remove delegate property assignment
-cardClient.delegate = self
// Remove delegate methods
- func card(_ cardClient: CardClient, didFinishWithResult result: CardResult) {
- func card(_ cardClient: CardClient, didFinishWithError error: Error) {
- func cardDidCancel(_ cardClient: CardClient ) {
Option 1: Using completion handlers
func processPayment() {
showLoadingIndicator()
cardClient.approveOrder(request: cardRequest) { [weak self] result, error in
guard let self = self else { return }
removeLoadingIndicator()
if let error = error {
handleError()
return
}
if let result = result {
handleSuccess(result)
}
}
}
Option 2: Using async/await
func processPayment() async {
showLoadingIndicator()
defer { removeLoadingIndicator() }
do {
let result = try await cardClient.approveOrder(request: cardRequest)
handleSuccess(result)
} catch {
handleError()
}
}