You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发App实现Wallet支付卡添加:已获权限,如何正确调用添加界面?

Implementing PKAddPaymentPassRequestController for Wallet Card Provisioning

Hey there! Since you’ve already secured the com.apple.developer.payment-pass-provisioning entitlement and updated your provisioning profile, let’s dive into the concrete steps to get the Wallet card addition flow working smoothly.

Key Implementation Steps

1. Double-Check Prerequisites

Before writing code, quickly confirm these to avoid avoidable headaches:

  • Open your Xcode project, go to Signing & Capabilities, ensure the Wallet capability is enabled, and Payment Pass Provisioning is checked.
  • Verify your entitlements file includes com.apple.developer.payment-pass-provisioning (Xcode usually adds this automatically when enabling the capability, but it’s worth a quick check).

2. Core Flow Code

The workflow centers on creating a PKAddPaymentPassRequest, initializing the controller, and handling callbacks. Here’s a practical implementation:

Step 2.1: Fetch Encrypted Card Data from Your Backend

Apple strictly requires sensitive card data to be encrypted by your backend (never generate this client-side!). You’ll need three key pieces of data from your server:

  • encryptedPassData: The encrypted payment pass payload
  • activationData: Optional activation data for the card
  • ephemeralPublicKey: The public key used to encrypt the pass data

Step 2.2: Initialize the Request & Controller

import PassKit

class CardProvisioningManager: NSObject, PKAddPaymentPassViewControllerDelegate {
    func startCardProvisioning() {
        // First, check if the device supports adding payment passes
        guard PKAddPaymentPassViewController.canAddPaymentPass() else {
            // Show user-friendly error: Device doesn't support Apple Pay/Wallet provisioning
            print("Device cannot add payment passes")
            return
        }

        // Fetch encrypted data from your backend (replace with your actual API call)
        fetchEncryptedCardData { [weak self] result in
            guard let self = self else { return }
            switch result {
            case .success(let cardData):
                // Create the provisioning request
                let request = PKAddPaymentPassRequest()
                request.encryptedPassData = cardData.encryptedPassData
                request.activationData = cardData.activationData
                request.ephemeralPublicKey = cardData.ephemeralPublicKey

                // Initialize the Wallet add card controller
                guard let addCardController = PKAddPaymentPassViewController(request: request, delegate: self) else {
                    print("Failed to initialize PKAddPaymentPassViewController")
                    return
                }

                // Present the controller (must run on main thread for UI operations)
                DispatchQueue.main.async {
                    // Replace with your actual presenting view controller
                    UIApplication.shared.keyWindow?.rootViewController?.present(addCardController, animated: true)
                }

            case .failure(let error):
                print("Failed to fetch encrypted card data: \(error.localizedDescription)")
            }
        }
    }

    // MARK: - PKAddPaymentPassViewControllerDelegate
    func addPaymentPassViewController(_ controller: PKAddPaymentPassViewController, didFinishAdding pass: PKPaymentPass?, error: Error?) {
        controller.dismiss(animated: true) {
            if let error = error {
                // Handle failure: Show user error message (e.g., "Card addition failed, please retry")
                print("Failed to add card: \(error.localizedDescription)")
            } else if let pass = pass {
                // Handle success: Confirm card was added to Wallet (e.g., show a success alert)
                print("Successfully added card: \(pass.primaryAccountIdentifier)")
            }
        }
    }

    // Optional: Use this method if you need to generate the request dynamically (instead of pre-fetching)
    func addPaymentPassViewController(_ controller: PKAddPaymentPassViewController, generateRequestWithCertificateChain certificates: [Data], nonce: Data, nonceSignature: Data, completionHandler: @escaping (PKAddPaymentPassRequest?) -> Void) {
        // Call your backend to generate encrypted pass data using the provided certificates/nonce
        fetchDynamicEncryptedCardData(certificates: certificates, nonce: nonce, nonceSignature: nonceSignature) { request in
            completionHandler(request)
        }
    }

    // Helper method to simulate backend API call (replace with your real network logic)
    private func fetchEncryptedCardData(completion: @escaping (Result<(encryptedPassData: Data, activationData: Data?, ephemeralPublicKey: Data), Error>) -> Void) {
        // In production, this would be a network request to your server
        let dummyEncryptedData = Data()
        let dummyEphemeralKey = Data()
        completion(.success((dummyEncryptedData, nil, dummyEphemeralKey)))
    }

    private func fetchDynamicEncryptedCardData(certificates: [Data], nonce: Data, nonceSignature: Data, completion: @escaping (PKAddPaymentPassRequest?) -> Void) {
        // Implement your dynamic request generation logic here
        completion(nil)
    }
}

3. Critical Notes & Troubleshooting

  • Test on Real Devices Only: The Wallet card provisioning flow doesn’t work on simulators—always use a physical iOS device that supports Apple Pay.
  • Backend Encryption Compliance: Your server must use Apple’s root certificates and your payment network’s encryption keys to generate encryptedPassData. Follow Apple’s Payment Pass Kit documentation closely for encryption specifications.
  • Main Thread for UI: Always present the PKAddPaymentPassViewController on the main thread—all iOS UI operations require this.
  • Entitlement Fixes: If the controller fails to initialize, download a fresh provisioning profile from the Apple Developer Portal, restart Xcode, and clean your project build folder.

内容的提问来源于stack exchange,提问作者S P Balu Kommuri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:06:55