Agent skills for iOS, iPadOS, Swift, SwiftUI, and modern Apple framework development.
71
89%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
Accept Apple Pay payments for physical goods and services, and add passes to the user's Wallet. Covers payment buttons, payment requests, authorization, Wallet passes, and merchant configuration. Targets Swift 6.3 / iOS 26+.
merchant.com.example.app)Always verify the device can make payments before showing Apple Pay UI.
import PassKit
func canMakePayments() -> Bool {
// Check device supports Apple Pay at all
guard PKPaymentAuthorizationController.canMakePayments() else {
return false
}
// Check user has cards for the networks you support
return PKPaymentAuthorizationController.canMakePayments(
usingNetworks: [.visa, .masterCard, .amex, .discover],
capabilities: .threeDSecure
)
}Use the built-in PayWithApplePayButton view in SwiftUI.
import SwiftUI
import PassKit
struct CheckoutView: View {
var body: some View {
PayWithApplePayButton(.buy) {
startPayment()
}
.payWithApplePayButtonStyle(.black)
.frame(height: 48)
.padding()
}
}Use PKPaymentButton for UIKit-based interfaces.
let button = PKPaymentButton(
paymentButtonType: .buy,
paymentButtonStyle: .black
)
button.cornerRadius = 12
button.addTarget(self, action: #selector(startPayment), for: .touchUpInside)Button types: .buy, .setUp, .inStore, .donate, .checkout, .book, .subscribe, .reload, .addMoney, .topUp, .order, .rent, .support, .contribute, .tip
Build a PKPaymentRequest with your merchant details and the items being purchased.
func createPaymentRequest() -> PKPaymentRequest {
let request = PKPaymentRequest()
request.merchantIdentifier = "merchant.com.example.app"
request.countryCode = "US"
request.currencyCode = "USD"
request.supportedNetworks = [.visa, .masterCard, .amex, .discover]
request.merchantCapabilities = .threeDSecure
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Widget", amount: 9.99),
PKPaymentSummaryItem(label: "Shipping", amount: 4.99),
PKPaymentSummaryItem(label: "My Store", amount: 14.98) // Total (last item)
]
return request
}The last item in paymentSummaryItems is treated as the total and its label appears as the merchant name on the payment sheet.
request.requiredShippingContactFields = [.postalAddress, .emailAddress, .name]
request.requiredBillingContactFields = [.postalAddress]
request.shippingMethods = [
PKShippingMethod(label: "Standard", amount: 4.99),
PKShippingMethod(label: "Express", amount: 9.99),
]
request.shippingMethods?[0].identifier = "standard"
request.shippingMethods?[0].detail = "5-7 business days"
request.shippingMethods?[1].identifier = "express"
request.shippingMethods?[1].detail = "1-2 business days"
request.shippingType = .shipping // .delivery, .storePickup, .servicePickup| Network | Constant |
|---|---|
| Visa | .visa |
| Mastercard | .masterCard |
| American Express | .amex |
| Discover | .discover |
| China UnionPay | .chinaUnionPay |
| JCB | .JCB |
| Maestro | .maestro |
| Electron | .electron |
| Interac | .interac |
Query available networks at runtime with PKPaymentRequest.availableNetworks().
Use PKPaymentAuthorizationController (works in both SwiftUI and UIKit, no view controller needed).
@MainActor
func startPayment() {
let request = createPaymentRequest()
let controller = PKPaymentAuthorizationController(paymentRequest: request)
controller.delegate = self
controller.present()
}Implement PKPaymentAuthorizationControllerDelegate to process the payment token.
extension CheckoutCoordinator: PKPaymentAuthorizationControllerDelegate {
func paymentAuthorizationController(
_ controller: PKPaymentAuthorizationController,
didAuthorizePayment payment: PKPayment,
handler completion: @escaping (PKPaymentAuthorizationResult) -> Void
) {
// Send payment.token.paymentData to your payment processor
Task {
do {
try await paymentService.process(payment.token)
completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
} catch {
completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
}
}
}
func paymentAuthorizationControllerDidFinish(
_ controller: PKPaymentAuthorizationController
) {
controller.dismiss()
}
}func paymentAuthorizationController(
_ controller: PKPaymentAuthorizationController,
didSelectShippingMethod shippingMethod: PKShippingMethod,
handler completion: @escaping (PKPaymentRequestShippingMethodUpdate) -> Void
) {
let updatedItems = recalculateItems(with: shippingMethod)
let update = PKPaymentRequestShippingMethodUpdate(paymentSummaryItems: updatedItems)
completion(update)
}Load a .pkpass file and present PKAddPassesViewController.
func addPassToWallet(data: Data) {
guard let pass = try? PKPass(data: data) else { return }
if let addController = PKAddPassesViewController(pass: pass) {
addController.delegate = self
present(addController, animated: true)
}
}import PassKit
import SwiftUI
struct AddPassButton: View {
let passData: Data
var body: some View {
Button("Add to Wallet") {
addPass()
}
}
func addPass() {
guard let pass = try? PKPass(data: passData) else { return }
let library = PKPassLibrary()
library.addPasses([pass]) { status in
switch status {
case .shouldReviewPasses:
// Present review UI
break
case .didAddPasses:
// Passes added successfully
break
case .didCancelAddPasses:
break
@unknown default:
break
}
}
}
}Use PKPassLibrary to inspect and manage passes the user already has.
let library = PKPassLibrary()
// Check if a specific pass is already in Wallet
let hasPass = library.containsPass(pass)
// Retrieve passes your app can access
let passes = library.passes()
// Check if pass library is available
guard PKPassLibrary.isPassLibraryAvailable() else { return }Apple Pay (PassKit) is for physical goods and services. StoreKit is for digital content, subscriptions, and in-app purchases. Using the wrong framework leads to App Review rejection.
// WRONG: Using StoreKit to sell a physical product
let product = try await Product.products(for: ["com.example.tshirt"])
// CORRECT: Use Apple Pay for physical goods
let request = PKPaymentRequest()
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "T-Shirt", amount: 29.99),
PKPaymentSummaryItem(label: "My Store", amount: 29.99)
]// WRONG: Merchant ID scattered across the codebase
let request1 = PKPaymentRequest()
request1.merchantIdentifier = "merchant.com.example.app"
// ...elsewhere:
let request2 = PKPaymentRequest()
request2.merchantIdentifier = "merchant.com.example.app" // easy to get out of sync
// CORRECT: Centralize configuration
enum PaymentConfig {
static let merchantIdentifier = "merchant.com.example.app"
static let countryCode = "US"
static let currencyCode = "USD"
static let supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard, .amex]
}The last item in paymentSummaryItems is the total row. If you omit it, the
payment sheet shows no merchant name or total.
// WRONG: No total item
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Widget", amount: 9.99)
]
// CORRECT: Last item is the total with your merchant name
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Widget", amount: 9.99),
PKPaymentSummaryItem(label: "My Store", amount: 9.99) // Total
]// WRONG: Show Apple Pay button without checking
PayWithApplePayButton(.buy) { startPayment() }
// CORRECT: Only show when available
if PKPaymentAuthorizationController.canMakePayments(
usingNetworks: PaymentConfig.supportedNetworks
) {
PayWithApplePayButton(.buy) { startPayment() }
} else {
// Show alternative checkout or setup button
Button("Set Up Apple Pay") { /* guide user */ }
}// WRONG: Dismissing inside didAuthorizePayment
func paymentAuthorizationController(
_ controller: PKPaymentAuthorizationController,
didAuthorizePayment payment: PKPayment,
handler completion: @escaping (PKPaymentAuthorizationResult) -> Void
) {
controller.dismiss() // Too early -- causes blank sheet
completion(.init(status: .success, errors: nil))
}
// CORRECT: Dismiss only in paymentAuthorizationControllerDidFinish
func paymentAuthorizationControllerDidFinish(
_ controller: PKPaymentAuthorizationController
) {
controller.dismiss()
}canMakePayments(usingNetworks:) checked before showing Apple Pay buttonpaymentSummaryItems is the total with merchant display namepaymentAuthorizationControllerDidFinish dismisses the controller.pkpass bundlesPKPassLibrary.isPassLibraryAvailable() checked before pass operationsPKPaymentButton or PayWithApplePayButtonskills
accessorysetupkit
references
activitykit
references
adattributionkit
references
alarmkit
references
app-clips
app-intents
references
app-store-optimization
app-store-review
apple-on-device-ai
appmigrationkit
references
audioaccessorykit
references
authentication
references
avkit
references
background-processing
references
browserenginekit
references
callkit
references
carplay
references
cloudkit
references
contacts-framework
references
core-bluetooth
references
core-data
core-motion
references
core-nfc
references
coreml
references
cryptokit
references
cryptotokenkit
references
debugging-instruments
device-integrity
references
dockkit
references
energykit
references
eventkit
references
financekit
references
focus-engine
gamekit
references
healthkit
references
homekit
references
ios-accessibility
ios-localization
ios-networking
ios-simulator
references
mapkit
metrickit
references
musickit
references
natural-language
references
paperkit
references
passkit
references
pdfkit
references
pencilkit
references
permissionkit
references
photokit
push-notifications
realitykit
references
relevancekit
references
scenekit
references
sensorkit
references
speech-recognition
spritekit
references
storekit
swift-api-design-guidelines
swift-architecture
swift-charts
references
swift-codable
swift-concurrency
swift-formatstyle
swift-language
swift-security
references
swift-testing
swiftdata
swiftlint
swiftui-animation
swiftui-gestures
references
swiftui-layout-components
swiftui-liquid-glass
references
swiftui-patterns
swiftui-performance
swiftui-uikit-interop
swiftui-webkit
tabletopkit
references
tipkit
references
vision-framework
weatherkit
references
widgetkit
references