Learn how to diagnose and fix common issues with the Apple Pay iOS SDK component.
The Apple Pay iOS SDK throws specific exceptions for different error scenarios:
Exception | Error code | Description | Prevention |
---|---|---|---|
ApplePayPaymentRequestApiNotSupportedException | SDK0602 | Apple Pay is not supported on this device or iOS version. | Check device compatibility and iOS version before initialisation. |
ApplePaySessionCancelledException | SDK0615 | The Apple Pay session was cancelled by the user. | Handle gracefully as this is expected user behaviour. |
ApplePayMerchantValidationFailedException | SDK0616 | The Apple Pay merchant validation failed. | Verify your merchant configuration and certificates. |
ApplePayCustomApiProcessingFailedException | SDK0617 | Custom API processing failed during Apple Pay payment. | Check network connectivity and API configuration. |
ApplePayValidationException | SDK0501 | The payment request validation failed. | Validate all required fields before submission. |
ApplePayPaymentFailedException | SDK0303 | The Apple Pay payment processing failed. | Implement retry logic and proper error handling. |
ApplePayMerchantIdentifierRequiredException | Custom | The merchant identifier is missing from the configuration. | Ensure merchant identifier is properly configured. |
ApplePayPaymentRequestNotInitializedException | Custom | The payment request was not properly initialised. | Validate payment request before starting payment flow. |
ApplePayHttpRequestFailedException | Custom | HTTP request failed during payment processing. | Check network connectivity and server availability. |
ApplePayBlobDecryptionFailedException | Custom | Failed to decrypt Apple Pay payment token. | Verify merchant certificates and configuration. |
ApplePayDisbursementRequestNotSupportedException | Custom | Disbursement requests are not supported on this iOS version. | Check iOS version (requires iOS 17.0+) before using disbursements. |
let config = ApplePayButtonComponentConfig()
config.onError = { error in
// Log error for debugging
print("Apple Pay Error: \(error)")
print("Error Code: \(error.userInfo["errorCode"] ?? "Unknown")")
print("Error Message: \(error.localizedDescription)")
// Handle specific error types
switch type(of: error) {
case is ApplePayPaymentRequestApiNotSupportedException.Type:
showUserMessage("Apple Pay is not available on this device. Please use an alternative payment method.")
showAlternativePaymentMethods()
case is ApplePayMerchantValidationFailedException.Type:
showUserMessage("Payment system temporarily unavailable. Please try again in a few moments.")
logCriticalError("Merchant validation failed", error: error)
case is ApplePaySessionCancelledException.Type:
// User cancelled - don't show error
trackEvent("apple_pay_cancelled")
case is ApplePayPaymentFailedException.Type:
showUserMessage("Payment failed. Please check your payment information and try again.")
offerRetryOption()
case is ApplePayValidationException.Type:
showUserMessage("Please check your payment details and try again.")
highlightValidationErrors()
default:
showUserMessage("An unexpected error occurred. Please try again or contact support.")
logUnknownError(error)
}
}
config.onCancel = { error in
print("Apple Pay cancelled by user")
trackEvent("apple_pay_cancelled")
// Handle graceful cancellation
}
func showUserMessage(_ message: String) {
DispatchQueue.main.async {
// Show user-friendly error message in your UI
let alert = UIAlertController(title: "Payment Error", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
// Present alert to user
}
}
func logCriticalError(_ context: String, error: Error) {
// Send to error monitoring service
// Example: Crashlytics.record(error: error)
}
The symptoms of this are:
- The button element is hidden or not rendered.
- There's an empty container where the button should appear.
- No Apple Pay option is visible to customers.
// Step 1: Check Apple Pay availability
print("Checking Apple Pay availability...")
// Check if PassKit is available
import PassKit
if !PKPaymentAuthorizationController.canMakePayments() {
print("Error: Apple Pay cannot make payments - no setup or unsupported device")
return
}
// Step 2: Check specific networks
let supportedNetworks: [PaymentNetwork] = [.visa, .masterCard, .amex, .discover]
let paymentService = ApplePayPaymentService()
if !paymentService.canMakePayments(usingNetworks: supportedNetworks) {
print("Warning: Apple Pay available but no supported cards configured")
}
// Step 3: Verify merchant configuration
guard let merchantId = checkoutConfig.session.allowedFundingTypes.wallets?.applePay?.merchantId else {
print("Error: Merchant ID is missing")
return
}
if !merchantId.hasPrefix("merchant.") {
print("Error: Invalid merchant ID format: \(merchantId)")
return
}
// Step 4: Check iOS version for advanced features
if #available(iOS 17.0, *) {
print("iOS 17.0+ features available (disbursements)")
} else {
print("Limited to basic Apple Pay features")
}
print("All Apple Pay requirements met")
// Solution: Graceful fallback
func initializeApplePay() {
if checkApplePayAvailability() {
renderApplePayButton()
} else {
renderAlternativePaymentMethods()
}
}
func checkApplePayAvailability() -> Bool {
return PKPaymentAuthorizationController.canMakePayments() &&
hasValidMerchantId() &&
isIOSVersionSupported()
}
func renderApplePayButton() {
do {
let applePayComponent = try ApplePayButtonComponent(
config: checkoutConfig,
componentConfig: applePayConfig
)
// Mount the component to your view
let buttonView = try applePayComponent.render()
containerView.addSubview(buttonView)
// Setup constraints
buttonView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
buttonView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
buttonView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
buttonView.topAnchor.constraint(equalTo: containerView.topAnchor),
buttonView.heightAnchor.constraint(equalToConstant: 44)
])
} catch {
print("Failed to initialize Apple Pay: \(error)")
renderAlternativePaymentMethods()
}
}
func renderAlternativePaymentMethods() {
// Show alternative payment options
let creditCardButton = UIButton(type: .system)
creditCardButton.setTitle("Pay with Credit Card", for: .normal)
// Add to your view hierarchy
}
The symptoms of this are:
- An error occurs during the Apple Pay session initialisation.
- "Merchant validation failed" error messages are displayed.
- The payment sheet doesn't appear after button tap.
// Check merchant ID configuration
struct MerchantDiagnostics {
let merchantId: String?
let bundleId: String
let deviceModel: String
let iOSVersion: String
}
let diagnostics = MerchantDiagnostics(
merchantId: checkoutConfig.session.allowedFundingTypes.wallets?.applePay?.merchantId,
bundleId: Bundle.main.bundleIdentifier ?? "Unknown",
deviceModel: UIDevice.current.model,
iOSVersion: UIDevice.current.systemVersion
)
print("Merchant Validation Diagnostics: \(diagnostics)")
// Test payment request creation
func testPaymentRequestCreation() {
guard let merchantId = diagnostics.merchantId else {
print("Error: Merchant ID is nil")
return
}
let paymentRequest = ApplePayPaymentRequest(
merchantIdentifier: merchantId,
countryCode: "US",
currencyCode: "USD",
supportedNetworks: [.visa, .masterCard],
merchantCapabilities: [.supports3DS, .supportsEMV],
total: ApplePayPaymentSummaryItem(
amount: Decimal(string: "10.00") ?? 0,
type: .final,
label: "Test Payment"
)
)
// Validate the payment request
if ApplePayValidationService.validatePaymentRequest(paymentRequest) {
print("Payment request validation passed")
} else {
print("Payment request validation failed")
}
}
// Checklist for Apple Developer Console
struct MerchantSetupChecklist {
let merchantIdCreated: Bool = true // Created in Apple Developer Console
let merchantIdFormat: String = "merchant.com.yourcompany.store" // Correct format
let certificateGenerated: Bool = true // Payment processing certificate created
let certificateInstalled: Bool = true // Certificate installed on server
let bundleIdRegistered: Bool = true // Bundle ID registered for merchant ID
let entitlementsConfigured: Bool = true // Apple Pay entitlements in app
}
func validateMerchantSetup() -> Bool {
// Check entitlements
guard let entitlements = Bundle.main.entitlements else {
print("Error: Cannot read app entitlements")
return false
}
if let applePayMerchantIds = entitlements["com.apple.developer.in-app-payments"] as? [String] {
print("Apple Pay merchant IDs configured: \(applePayMerchantIds)")
return !applePayMerchantIds.isEmpty
} else {
print("Error: Apple Pay entitlements not configured")
return false
}
}
func validateConfigurationBeforePayment() -> Bool {
// Validate merchant ID
guard let merchantId = checkoutConfig.session.allowedFundingTypes.wallets?.applePay?.merchantId,
!merchantId.isEmpty else {
print("Error: Merchant ID is missing or empty")
return false
}
guard merchantId.hasPrefix("merchant.") else {
print("Error: Invalid merchant ID format: \(merchantId)")
return false
}
// Validate entitlements
if !validateMerchantSetup() {
return false
}
// Check Apple Pay availability
if !PKPaymentAuthorizationController.canMakePayments() {
print("Error: Apple Pay not available on device")
return false
}
return true
}
// Use before starting payment
func startApplePayPayment() {
guard validateConfigurationBeforePayment() else {
showConfigurationError()
return
}
// Proceed with payment
let paymentRequest = createPaymentRequest()
applePayService.startPayment(with: paymentRequest)
}
func startPaymentWithRetry(maxRetries: Int = 3) {
Task {
for attempt in 1...maxRetries {
do {
let result = try await processPayment()
// Success - exit retry loop
handlePaymentSuccess(result)
return
} catch let error as ApplePayMerchantValidationFailedException {
print("Merchant validation attempt \(attempt) failed: \(error)")
if attempt == maxRetries {
handlePaymentFailure(error)
return
}
// Wait before retrying (exponential backoff)
let delay = TimeInterval(pow(2.0, Double(attempt)))
try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
}
}
}
}
The symptoms of this are:
- The Apple Pay sheet appears but payment fails.
- The customer sees a generic error message.
- The transaction doesn't complete successfully.
// Enhanced payment authorisation with detailed logging
config.onPreAuthorisation = { result in
print("Payment Authorisation Started:")
print("- Payment Token: \(result.data.token.paymentData != nil ? "Present" : "Missing")")
print("- Billing Contact: \(result.data.billingContact != nil ? "Present" : "Missing")")
print("- Shipping Contact: \(result.data.shippingContact != nil ? "Present" : "Missing")")
print("- Payment Method: \(result.data.paymentMethod)")
// Return transaction initialisation data
return BaseTransactionResponse() // Your transaction init logic here
}
config.onPostAuthorisation = { result in
print("Payment Authorisation Completed:")
print("- Transaction State: \(result.state)")
print("- Transaction ID: \(result.transactionId ?? "None")")
if let errorReason = result.errorReason {
print("- Error Reason: \(errorReason)")
}
// Handle success/failure
switch result.state {
case "Authorised", "Captured":
handlePaymentSuccess(result)
default:
handlePaymentFailure(result)
}
}
func validatePaymentData(_ payment: PKPayment) throws {
// Validate payment token
guard payment.token.paymentData.count > 0 else {
throw ApplePayValidationException("Payment token is missing or invalid")
}
guard !payment.token.transactionIdentifier.isEmpty else {
throw ApplePayValidationException("Transaction identifier is missing")
}
// Validate contact information if required
if let billingContact = payment.billingContact {
guard billingContact.postalAddress != nil else {
throw ApplePayValidationException("Billing address is required but missing")
}
}
// Validate payment method
guard payment.paymentMethod.network != nil else {
throw ApplePayValidationException("Payment network information is missing")
}
}
func processPaymentWithValidation(_ payment: PKPayment) async throws -> BaseTransactionResponse {
// Validate payment data
try validatePaymentData(payment)
// Create transaction request
let transactionRequest = createTransactionRequest(from: payment)
// Process with Unity Service
return try await unityService.transactionAsync(transactionRequest)
}
func processPaymentWithNetworkRetry(_ payment: PKPayment) async throws -> BaseTransactionResponse {
let maxRetries = 2
var lastError: Error?
for attempt in 1...maxRetries {
do {
return try await processPayment(payment)
} catch let error as ApplePayHttpRequestFailedException {
print("Payment attempt \(attempt) failed with HTTP error: \(error)")
lastError = error
// Check if retryable
if isRetryableHttpError(error) && attempt < maxRetries {
let delay = TimeInterval(attempt) // Progressive delay
try await Task.sleep(nanoseconds: UInt64(delay * 1_000_000_000))
continue
}
throw error
} catch {
print("Payment attempt \(attempt) failed: \(error)")
throw error
}
}
throw lastError ?? ApplePayPaymentFailedException()
}
func isRetryableHttpError(_ error: ApplePayHttpRequestFailedException) -> Bool {
let retryableStatusCodes = [408, 429, 500, 502, 503, 504]
return retryableStatusCodes.contains(error.statusCode ?? 0)
}
The symptoms of this are:
- Payment requests fail before reaching Apple Pay.
- Validation exception messages are displayed.
- The payment flow doesn't start.
func diagnoseValidationIssues() {
let paymentRequest = ApplePayPaymentRequest(
merchantIdentifier: "merchant.com.example.store",
countryCode: "US",
currencyCode: "USD",
supportedNetworks: [.visa, .masterCard],
merchantCapabilities: [.supports3DS],
total: ApplePayPaymentSummaryItem(
amount: Decimal(string: "10.00") ?? 0,
type: .final,
label: "Test Payment"
)
)
// Test individual validation steps
print("=== Payment Request Validation ===")
// Basic fields validation
print("Merchant ID: \(paymentRequest.merchantIdentifier.isEmpty ? "❌ Empty" : "✅ Valid")")
print("Country Code: \(ApplePayValidator.isValidCountryCode(paymentRequest.countryCode) ? "✅ Valid" : "❌ Invalid")")
print("Currency Code: \(ApplePayValidator.isValidCurrencyCode(paymentRequest.currencyCode) ? "✅ Valid" : "❌ Invalid")")
print("Total Amount: \(paymentRequest.total?.amount.isNegative == false ? "✅ Valid" : "❌ Negative or nil")")
// Networks and capabilities
print("Supported Networks: \(paymentRequest.supportedNetworks.isEmpty ? "❌ Empty" : "✅ Valid")")
print("Merchant Capabilities: \(paymentRequest.merchantCapabilities.isEmpty ? "❌ Empty" : "✅ Valid")")
// Run full validation
if ApplePayValidationService.validatePaymentRequest(paymentRequest) {
print("✅ Overall validation: PASSED")
} else {
print("❌ Overall validation: FAILED")
}
}
struct PaymentRequestValidator {
static func createValidatedPaymentRequest(
merchantId: String,
amount: String,
currency: String = "USD",
country: String = "US",
description: String = "Purchase"
) throws -> ApplePayPaymentRequest {
// Validate merchant ID
guard !merchantId.isEmpty && merchantId.hasPrefix("merchant.") else {
throw ApplePayValidationException("Invalid merchant ID format")
}
// Validate amount
guard let decimalAmount = Decimal(string: amount), !decimalAmount.isNegative else {
throw ApplePayValidationException("Invalid payment amount")
}
// Validate currency
guard ApplePayValidator.isValidCurrencyCode(currency) else {
throw ApplePayValidationException("Invalid currency code: \(currency)")
}
// Validate country
guard ApplePayValidator.isValidCountryCode(country) else {
throw ApplePayValidationException("Invalid country code: \(country)")
}
return ApplePayPaymentRequest(
merchantIdentifier: merchantId,
countryCode: country,
currencyCode: currency,
supportedNetworks: [.visa, .masterCard, .amex],
merchantCapabilities: [.supports3DS, .supportsEMV],
total: ApplePayPaymentSummaryItem(
amount: decimalAmount,
type: .final,
label: description
)
)
}
}
// Usage
do {
let paymentRequest = try PaymentRequestValidator.createValidatedPaymentRequest(
merchantId: "merchant.com.example.store",
amount: "29.99",
description: "Product Purchase"
)
applePayService.startPayment(with: paymentRequest)
} catch {
handleValidationError(error)
}
func validatePaymentRequestFields(
merchantId: String?,
amount: String?,
currency: String?,
country: String?
) -> [ValidationError] {
var errors: [ValidationError] = []
// Merchant ID validation
if let merchantId = merchantId {
if merchantId.isEmpty {
errors.append(ValidationError(field: "merchantId", message: "Merchant ID cannot be empty"))
} else if !merchantId.hasPrefix("merchant.") {
errors.append(ValidationError(field: "merchantId", message: "Merchant ID must start with 'merchant.'"))
}
} else {
errors.append(ValidationError(field: "merchantId", message: "Merchant ID is required"))
}
// Amount validation
if let amount = amount {
if amount.isEmpty {
errors.append(ValidationError(field: "amount", message: "Amount cannot be empty"))
} else if Decimal(string: amount) == nil {
errors.append(ValidationError(field: "amount", message: "Invalid amount format"))
} else if let decimal = Decimal(string: amount), decimal.isNegative {
errors.append(ValidationError(field: "amount", message: "Amount cannot be negative"))
}
} else {
errors.append(ValidationError(field: "amount", message: "Amount is required"))
}
// Currency validation
if let currency = currency {
if !ApplePayValidator.isValidCurrencyCode(currency) {
errors.append(ValidationError(field: "currency", message: "Invalid currency code"))
}
} else {
errors.append(ValidationError(field: "currency", message: "Currency is required"))
}
// Country validation
if let country = country {
if !ApplePayValidator.isValidCountryCode(country) {
errors.append(ValidationError(field: "country", message: "Invalid country code"))
}
} else {
errors.append(ValidationError(field: "country", message: "Country is required"))
}
return errors
}
struct ValidationError {
let field: String
let message: String
}
To get more detailed information about errors, use this debugging setup:
// Enable comprehensive logging
extension ApplePayButtonComponent {
func enableDebugMode() {
print("Apple Pay Debug Mode Enabled")
logEnvironmentInfo()
}
private func logEnvironmentInfo() {
print("=== Apple Pay Environment ===")
print("Device Model: \(UIDevice.current.model)")
print("iOS Version: \(UIDevice.current.systemVersion)")
print("Bundle ID: \(Bundle.main.bundleIdentifier ?? "Unknown")")
print("Apple Pay Available: \(PKPaymentAuthorizationController.canMakePayments())")
// Check supported networks
let networks: [PKPaymentNetwork] = [.visa, .masterCard, .amex, .discover]
print("Supported Networks Available: \(PKPaymentAuthorizationController.canMakePayments(usingNetworks: networks))")
// Check entitlements
if let entitlements = Bundle.main.entitlements,
let merchantIds = entitlements["com.apple.developer.in-app-payments"] as? [String] {
print("Merchant IDs in Entitlements: \(merchantIds)")
} else {
print("Apple Pay entitlements not found")
}
}
}
// Debug helper class
class ApplePayDebugger {
static func logPaymentRequest(_ request: ApplePayPaymentRequest) {
print("=== Payment Request Debug ===")
print("Merchant ID: \(request.merchantIdentifier)")
print("Country: \(request.countryCode)")
print("Currency: \(request.currencyCode)")
print("Total: \(request.total?.amount ?? 0) \(request.currencyCode)")
print("Networks: \(request.supportedNetworks)")
print("Capabilities: \(request.merchantCapabilities)")
if let lineItems = request.lineItems {
print("Line Items:")
for item in lineItems {
print(" - \(item.label): \(item.amount)")
}
}
}
static func logPaymentResult(_ result: ApplePayPaymentResult) {
print("=== Payment Result Debug ===")
print("Payment Method: \(result.data.paymentMethod)")
print("Token Present: \(result.data.token.paymentData.count > 0)")
print("Transaction ID: \(result.data.token.transactionIdentifier)")
if let billingContact = result.data.billingContact {
print("Billing Contact Present: Yes")
print("Billing Country: \(billingContact.postalAddress?.country ?? "Unknown")")
} else {
print("Billing Contact Present: No")
}
if let shippingContact = result.data.shippingContact {
print("Shipping Contact Present: Yes")
print("Shipping Country: \(shippingContact.postalAddress?.country ?? "Unknown")")
} else {
print("Shipping Contact Present: No")
}
}
}
// Usage in your implementation
let applePayComponent = try ApplePayButtonComponent(config: checkoutConfig, componentConfig: applePayConfig)
applePayComponent.enableDebugMode()
// In your payment flow
ApplePayDebugger.logPaymentRequest(paymentRequest)
// Pre-flight checks before initialising Apple Pay
func performPreflightChecks() async -> Bool {
let checks: [(String, () async -> Bool, String)] = [
("Apple Pay Support", {
PKPaymentAuthorizationController.canMakePayments()
}, "Apple Pay is not supported on this device"),
("Payment Networks", {
let networks: [PKPaymentNetwork] = [.visa, .masterCard, .amex]
return PKPaymentAuthorizationController.canMakePayments(usingNetworks: networks)
}, "No supported payment networks available"),
("Merchant Configuration", {
return self.validateMerchantConfiguration()
}, "Merchant configuration is invalid"),
("iOS Version", {
if #available(iOS 11.0, *) {
return true
} else {
return false
}
}, "iOS 11.0 or later required"),
("Network Connectivity", {
return await self.checkNetworkConnectivity()
}, "Network connection required")
]
var allPassed = true
print("=== Apple Pay Pre-flight Checks ===")
for (name, test, failureMessage) in checks {
let passed = await test()
print("\(passed ? "✅" : "❌") \(name): \(passed ? "PASSED" : failureMessage)")
if !passed {
allPassed = false
}
}
return allPassed
}
private func validateMerchantConfiguration() -> Bool {
guard let merchantId = checkoutConfig.session.allowedFundingTypes.wallets?.applePay?.merchantId,
!merchantId.isEmpty,
merchantId.hasPrefix("merchant.") else {
return false
}
// Check entitlements
guard let entitlements = Bundle.main.entitlements,
let merchantIds = entitlements["com.apple.developer.in-app-payments"] as? [String],
merchantIds.contains(merchantId) else {
return false
}
return true
}
private func checkNetworkConnectivity() async -> Bool {
// Simple connectivity check
guard let url = URL(string: "https://apple.com") else { return false }
do {
let (_, response) = try await URLSession.shared.data(from: url)
return (response as? HTTPURLResponse)?.statusCode == 200
} catch {
return false
}
}
// Use before initialisation
func initializeApplePay() async {
let preflightPassed = await performPreflightChecks()
if preflightPassed {
// Safe to initialize Apple Pay
do {
let applePayComponent = try ApplePayButtonComponent(
config: checkoutConfig,
componentConfig: applePayConfig
)
showApplePayButton(applePayComponent)
} catch {
showFallbackPaymentOptions()
}
} else {
// Show alternative payment methods
showFallbackPaymentOptions()
}
}
// Error monitoring setup
class ApplePayErrorMonitor {
static func captureError(_ error: Error, context: [String: Any] = [:]) {
var errorData: [String: Any] = [
"error_message": error.localizedDescription,
"error_type": String(describing: type(of: error)),
"device_model": UIDevice.current.model,
"ios_version": UIDevice.current.systemVersion,
"bundle_id": Bundle.main.bundleIdentifier ?? "Unknown",
"timestamp": ISO8601DateFormatter().string(from: Date())
]
// Add context
errorData.merge(context) { _, new in new }
// Add error-specific data
if let sdkError = error as? BaseSdkException {
errorData["error_code"] = sdkError.userInfo["errorCode"]
errorData["sdk_error"] = true
}
// Send to your error tracking service
print("📊 Error captured: \(errorData)")
// Example: Crashlytics.record(error: error, userInfo: errorData)
}
static func trackApplePayEvent(_ eventType: String, data: [String: Any] = [:]) {
var eventData = data
eventData["event_type"] = eventType
eventData["timestamp"] = ISO8601DateFormatter().string(from: Date())
eventData["component"] = "ApplePay"
print("📈 Event tracked: \(eventData)")
// Send to your analytics service
}
}
// Integration with Apple Pay component
let config = ApplePayButtonComponentConfig()
config.onError = { error in
ApplePayErrorMonitor.captureError(error, context: [
"flow_step": "payment_authorization",
"merchant_id": merchantId
])
}
config.onPostAuthorisation = { result in
ApplePayErrorMonitor.trackApplePayEvent("payment_completed", data: [
"transaction_state": result.state,
"transaction_id": result.transactionId ?? "none"
])
}
config.onCancel = { error in
ApplePayErrorMonitor.trackApplePayEvent("payment_cancelled", data: [
"cancellation_reason": error.localizedDescription
])
}
// Check iOS version for feature availability
func checkiOSFeatureAvailability() {
print("=== iOS Feature Availability ===")
if #available(iOS 11.0, *) {
print("✅ Basic Apple Pay (iOS 11.0+)")
} else {
print("❌ Apple Pay requires iOS 11.0 or later")
return
}
if #available(iOS 15.0, *) {
print("✅ Coupon codes (iOS 15.0+)")
} else {
print("⚠️ Coupon codes not available (requires iOS 15.0+)")
}
if #available(iOS 16.0, *) {
print("✅ Multi-merchant payments (iOS 16.0+)")
} else {
print("⚠️ Multi-merchant payments not available (requires iOS 16.0+)")
}
if #available(iOS 17.0, *) {
print("✅ Disbursements (iOS 17.0+)")
} else {
print("⚠️ Disbursements not available (requires iOS 17.0+)")
}
}
func checkDeviceLimitations() {
print("=== Device limitations ===")
// Check if device supports Apple Pay
if PKPaymentAuthorizationController.canMakePayments() {
print("✅ Device supports Apple Pay")
} else {
print("❌ Device does not support Apple Pay")
return
}
// Check available payment networks
let allNetworks: [PKPaymentNetwork] = [.visa, .masterCard, .amex, .discover, .maestro, .chinaUnionPay]
let availableNetworks = allNetworks.filter { network in
PKPaymentAuthorizationController.canMakePayments(usingNetworks: [network])
}
print("Available payment networks: \(availableNetworks)")
if availableNetworks.isEmpty {
print("⚠️ No payment cards configured in Wallet")
}
}