Create a Shopping App with Apple
2023-11-07 本文已影响0人
_浅墨_
支付逻辑
// Note: The code below was taken from the sample app from https://developer.apple.com/documentation/passkit/apple_pay/offering_apple_pay_in_your_app - shortened and adapted for this application
import Foundation
import PassKit
// Typealias so we don't always need to rewrite the type (Bool) -> Void
typealias PaymentCompletionHandler = (Bool) -> Void
class PaymentHandler: NSObject {
var paymentController: PKPaymentAuthorizationController?
var paymentSummaryItems = [PKPaymentSummaryItem]()
var paymentStatus = PKPaymentAuthorizationStatus.failure
var completionHandler: PaymentCompletionHandler?
static let supportedNetworks: [PKPaymentNetwork] = [
.visa,
.masterCard,
]
// This applePayStatus function is not used in this app. Use it to check for the ability to make payments using canMakePayments(), and check for available payment cards using canMakePayments(usingNetworks:). You can also display a custom PaymentButton according to the result. See https://developer.apple.com/documentation/passkit/apple_pay/offering_apple_pay_in_your_app under "Add the Apple Pay Button" section
class func applePayStatus() -> (canMakePayments: Bool, canSetupCards: Bool) {
return (PKPaymentAuthorizationController.canMakePayments(),
PKPaymentAuthorizationController.canMakePayments(usingNetworks: supportedNetworks))
}
// Define the shipping methods (this app only offers delivery) and the delivery dates
func shippingMethodCalculator() -> [PKShippingMethod] {
let today = Date()
let calendar = Calendar.current
let shippingStart = calendar.date(byAdding: .day, value: 5, to: today)
let shippingEnd = calendar.date(byAdding: .day, value: 10, to: today)
if let shippingEnd = shippingEnd, let shippingStart = shippingStart {
let startComponents = calendar.dateComponents([.calendar, .year, .month, .day], from: shippingStart)
let endComponents = calendar.dateComponents([.calendar, .year, .month, .day], from: shippingEnd)
let shippingDelivery = PKShippingMethod(label: "Delivery", amount: NSDecimalNumber(string: "0.00"))
shippingDelivery.dateComponentsRange = PKDateComponentsRange(start: startComponents, end: endComponents)
shippingDelivery.detail = "Sweaters sent to your address"
shippingDelivery.identifier = "DELIVERY"
return [shippingDelivery]
}
return []
}
func startPayment(products: [Product], total: Int, completion: @escaping PaymentCompletionHandler) {
completionHandler = completion
// Iterate over the products array, create a PKPaymentSummaryItem for each and append to the paymentSummaryItems array
products.forEach { product in
let item = PKPaymentSummaryItem(label: product.name, amount: NSDecimalNumber(string: "\(product.price).00"), type: .final)
paymentSummaryItems.append(item)
}
// Add a PKPaymentSummaryItem for the total to the paymentSummaryItems array
let total = PKPaymentSummaryItem(label: "Total", amount: NSDecimalNumber(string: "\(total).00"), type: .final)
paymentSummaryItems.append(total)
// Create a payment request and add all data to it
let paymentRequest = PKPaymentRequest()
paymentRequest.paymentSummaryItems = paymentSummaryItems // Set paymentSummaryItems to the paymentRequest
paymentRequest.merchantIdentifier = "merchant.io.designcode.sweatershopapp"
paymentRequest.merchantCapabilities = .capability3DS // A security protocol used to authenticate users
paymentRequest.countryCode = "US"
paymentRequest.currencyCode = "USD"
paymentRequest.supportedNetworks = PaymentHandler.supportedNetworks // Types of cards supported
paymentRequest.shippingType = .delivery
paymentRequest.shippingMethods = shippingMethodCalculator()
paymentRequest.requiredShippingContactFields = [.name, .postalAddress]
// Display the payment request in a sheet presentation
paymentController = PKPaymentAuthorizationController(paymentRequest: paymentRequest)
paymentController?.delegate = self
paymentController?.present(completion: { (presented: Bool) in
if presented {
debugPrint("Presented payment controller")
} else {
debugPrint("Failed to present payment controller")
if let completionHandler = self.completionHandler {
completionHandler(false)
}
}
})
}
}
// Set up PKPaymentAuthorizationControllerDelegate conformance
extension PaymentHandler: PKPaymentAuthorizationControllerDelegate {
// Handle success and errors related to the payment
func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
let errors = [Error]()
let status = PKPaymentAuthorizationStatus.success
self.paymentStatus = status
completion(PKPaymentAuthorizationResult(status: status, errors: errors))
}
func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) {
controller.dismiss {
// The payment sheet doesn't automatically dismiss once it has finished, so dismiss the payment sheet
DispatchQueue.main.async {
if self.paymentStatus == .success {
if let completionHandler = self.completionHandler {
completionHandler(true)
}
} else {
if let completionHandler = self.completionHandler {
completionHandler(false)
}
}
}
}
}
}
开始付款
当用户点击“使用Apple Pay结账”按钮时,他们将看到Apple Pay的付款表单。
首先,让我们处理 CartManager。在 CartManager类的顶部添加以下变量。我们创建了一个 PaymentHandler 实例,以及一个名为 paymentSuccess 的发布变量,它让我们知道付款是否成功。
// ./CartManager.swift
let paymentHandler = PaymentHandler()
@Published var paymentSuccess = false
在 CartManager 类底部,创建 pay 方法。
// ./CartManager.swift
func pay() {
paymentHandler.startPayment(products: products, total: total) { success in
self.paymentSuccess = success
self.products = []
self.total = 0
}
}
接下来处理UI。
// ./Views/CartView.swift
PaymentButton(action: cartManager.pay)
在 CartView 中,如果付款成功,我们将显示一条感谢用户购买的消息。否则,我们将显示检查用户购物车中产品数量。
// ./Views/CartView.swift
if cartManager.paymentSuccess {
Text("感谢您的购买!您很快就会在我们的舒适毛衣中感到温暖!您还将很快收到确认邮件。")
.padding()
} else {
// 如果 cartManager.products.count > 0 代码...
}
重置 CartView
一旦用户完成购买并返回到 ContentView,我们希望将 CartManager 中的 paymentSuccess 状态重置为 false。
// ./CartManager.swift
@Published var paymentSuccess = false // 删除 private(set) 部分
在 CartView 上的 ScrollView 中添加onDisappear 逻辑,以便用户可以进行另一次购买。
// ./Views/CartView.swift
.onDisappear {
if cartManager.paymentSuccess {
cartManager.paymentSuccess = false
}
}
测试整个App
效果图
您可以单击删除图标来从购物车中删除物品,产品列表和价格会立即更新。
当单击 “使用Apple Pay结账” 按钮时,我们会看到一个付款表单。一旦输入了所有必要的信息并付款,我们将听到一个“TING”的声音,表示成功支付了。
然后,Apple Pay表单将被关闭,我们将回到CartView,并收到一条感谢购买的消息。
当返回到ContentView并再次进入CartView时,将看到完成购买后购物车被清空。接下来,可以进行另一次购买。