Integrating Apple Pay into your SwiftUI app provides a seamless and secure payment option for your users. This guide will walk you through the steps of adding Apple Pay support to your application, from setting up your environment to handling transactions.
Why Integrate Apple Pay?
- Convenience: Users can make purchases with a single touch or glance.
- Security: Apple Pay uses tokenization to protect users’ financial information.
- Increased Conversion: Simplified checkout process can lead to higher conversion rates.
Prerequisites
Before you begin, make sure you have the following:
- An active Apple Developer account.
- A configured Merchant ID in your Apple Developer account.
- An iOS device capable of Apple Pay.
- Xcode 13 or later.
Step 1: Setting Up Your Project
First, create a new Xcode project or open an existing one. Ensure your project is configured to support Apple Pay.
1.1 Enable Apple Pay Capability
- Open your project in Xcode.
- Select your project in the Project Navigator.
- Select your target.
- Go to Signing & Capabilities.
- Click the + Capability button.
- Search for and double-click Apple Pay.
1.2 Add Your Merchant ID
In the Apple Pay capability settings, add your Merchant ID that you registered in the Apple Developer account.
Replace 'https://i.imgur.com/YOUR_IMAGE_URL.png'
with a valid image link that demonstrates adding the Merchant ID.
Step 2: Implementing Apple Pay in SwiftUI
Now, let’s create the necessary SwiftUI components and logic to initiate Apple Pay.
2.1 Create the PaymentRequest Struct
Define a struct that generates a PKPaymentRequest
, which outlines the details of the payment.
import PassKit
struct PaymentRequest {
func createPaymentRequest() -> PKPaymentRequest {
let request = PKPaymentRequest()
request.merchantIdentifier = "YOUR_MERCHANT_ID"
request.countryCode = "US"
request.currencyCode = "USD"
request.supportedNetworks = [.visa, .masterCard, .amex]
request.merchantCapabilities = .capability3DS
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Product Name", amount: NSDecimalNumber(string: "10.00")),
PKPaymentSummaryItem(label: "Shipping", amount: NSDecimalNumber(string: "2.00")),
PKPaymentSummaryItem(label: "Tax", amount: NSDecimalNumber(string: "0.80")),
PKPaymentSummaryItem(label: "Total", amount: NSDecimalNumber(string: "12.80"))
]
return request
}
}
Replace "YOUR_MERCHANT_ID"
with your actual Merchant ID.
2.2 Create the ApplePayButton View
Create a SwiftUI view that presents the Apple Pay button and handles the payment process.
import SwiftUI
import PassKit
struct ApplePayButton: View {
@State private var isPaymentAuthorized = false
@State private var paymentStatus: PKPaymentAuthorizationStatus = .pending
var body: some View {
Representable()
.frame(height: 44)
.onChange(of: isPaymentAuthorized) { newValue in
if newValue {
// Handle successful payment
print("Payment Authorized")
} else {
// Handle payment failure
print("Payment Failed")
}
}
}
struct Representable: UIViewRepresentable {
func makeUIView(context: Context) -> PKPaymentButton {
return PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .automatic)
}
func updateUIView(_ uiView: PKPaymentButton, context: Context) {
// Update the view if needed
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
class Coordinator: NSObject, PKPaymentAuthorizationViewControllerDelegate {
var parent: Representable
init(_ parent: Representable) {
self.parent = parent
super.init()
}
func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
// Perform some server-side action, like charging the card
let errors = [Error]()
if errors.isEmpty {
completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
} else {
completion(PKPaymentAuthorizationResult(status: .failure, errors: errors))
}
}
func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
controller.dismiss(animated: true, completion: nil)
}
}
}
This view incorporates UIViewRepresentable
to utilize PKPaymentButton
from UIKit. It also includes a coordinator to handle the delegation methods for the payment authorization process.
2.3 Integrating the ApplePayButton into Your SwiftUI View
Integrate the ApplePayButton
into your SwiftUI view:
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("Ready to buy something?")
ApplePayButton()
.padding()
}
}
}
Step 3: Simulating Apple Pay in the Simulator or Testing on a Real Device
You can test your Apple Pay integration in the iOS Simulator or on a real device. To test in the simulator, you’ll need to add a test card in the Wallet app via Xcode.
3.1 Adding a Test Card
- In Xcode, navigate to Debug -> Simulate Payment Card.
- Choose a card type. This adds a test card to the Wallet in the simulator.
3.2 Testing on a Real Device
For testing on a real device, make sure you have a card added to the Wallet and that the device is signed in to your Apple ID.
Step 4: Handling Payment Authorization
Inside the Coordinator
class, the paymentAuthorizationViewController
delegate method is crucial for handling payment authorization. This is where you should:
- Process the payment token from the
payment
object. - Communicate with your server to finalize the transaction.
- Call the
completion
handler with a.success
or.failure
status.
Step 5: Finalizing the Transaction
After the user authorizes the payment and you’ve processed the payment with your backend, finalize the transaction by:
- Displaying a success or failure message to the user.
- Updating your app’s data to reflect the completed purchase.
Example Code: Full SwiftUI Implementation
import SwiftUI
import PassKit
struct ContentView: View {
var body: some View {
VStack {
Text("Ready to buy something?")
ApplePayButton()
.padding()
}
}
}
struct ApplePayButton: View {
@State private var isPaymentAuthorized = false
@State private var paymentStatus: PKPaymentAuthorizationStatus = .pending
var body: some View {
Representable(isPaymentAuthorized: $isPaymentAuthorized, paymentStatus: $paymentStatus)
.frame(height: 44)
.onChange(of: isPaymentAuthorized) { newValue in
if newValue {
// Handle successful payment
print("Payment Authorized")
} else {
// Handle payment failure
print("Payment Failed")
}
}
}
struct Representable: UIViewRepresentable {
@Binding var isPaymentAuthorized: Bool
@Binding var paymentStatus: PKPaymentAuthorizationStatus
func makeUIView(context: Context) -> PKPaymentButton {
return PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .automatic)
}
func updateUIView(_ uiView: PKPaymentButton, context: Context) {
// Update the view if needed
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
class Coordinator: NSObject, PKPaymentAuthorizationViewControllerDelegate {
var parent: Representable
init(_ parent: Representable) {
self.parent = parent
super.init()
}
func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
// Perform some server-side action, like charging the card
// Example: Mock successful payment after 3 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
let errors: [Error] = [] // No errors for successful transaction
if errors.isEmpty {
parent.paymentStatus = .success
completion(PKPaymentAuthorizationResult(status: .success, errors: nil))
parent.isPaymentAuthorized = true // Payment was authorized
} else {
parent.paymentStatus = .failure
completion(PKPaymentAuthorizationResult(status: .failure, errors: errors))
parent.isPaymentAuthorized = false // Payment failed
}
}
}
func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
controller.dismiss(animated: true, completion: nil)
}
}
}
This comprehensive example integrates the ApplePayButton
into a SwiftUI ContentView
. The button’s state is managed using @State
and @Binding
properties, and it demonstrates how to handle payment authorization and completion using the PKPaymentAuthorizationViewControllerDelegate
protocol.
Conclusion
Integrating Apple Pay into your SwiftUI application streamlines the purchasing process, improves user experience, and enhances transaction security. By following the steps outlined in this guide, you can enable Apple Pay in your app and provide your users with a seamless payment solution.