# 在应用内付款期间保存付款详情 在移动应用中保存付款过程中的付款详情。 > #### Accounts v2 API 支持 > > Payment Sheet 不支持 *客户配置的账户* (Account configurations represent role-based functionality that you can enable for accounts, such as merchant, customer, or recipient),仅支持 `Customer` 对象。 # iOS > This is a iOS for when platform is ios and mobile-ui is payment-sheet. View the full page at https://docs.stripe.com/payments/mobile/save-during-payment?platform=ios&mobile-ui=payment-sheet. 用 [Payment Intents API](https://docs.stripe.com/api/payment_intents.md) 保存购物时输入的付款详情。有几个用例: - 对客户的网上订单扣款并存储支付信息,用于以后的购物。 - 发起一系列经常性付款中的第一笔付款。 - 收取押金并存储详情,便于以后收取完整金额。 > #### 有卡交易 > > 有卡交易(例如通过 Stripe Terminal 支付)使用不同的流程来保存支付方式。有关详情,请查看 [Terminal 文档](https://docs.stripe.com/terminal/features/saving-payment-details/save-after-payment.md)。 ## 合规 在保存客户的支付详情以备将来使用时,您有责任遵守所有适用的法律、法规和网络规则,比如在结账流程中向客户显示其支付方式以便未来购买,或在客户未主动使用您的网站或应用程序时向他们收费。在保存或向客户的支付方式收费之前,请确保您: - 在您的网站或应用中添加说明您计划如何保存支付方式详情的条款,例如: - 客户协议允许您代表他们针对指定交易发起支付或一系列支付。 - 预期的付款时间和频率(例如,收款是计划的分期付款、订阅付款还是计划外充值)。 - 如何确定付款金额。 - 如果支付方式是用于支付订阅服务,那即同意您的取消政策。 - 仅出于条款中所述的目的,使用保存的支付方式。 - 为此特定用途收集客户的明确同意。例如,可以添加一个“保存我的支付方式以备将来使用”的复选框。 - 记录客户对您的条款的书面同意。 ## 设置 Stripe [服务器端] [客户端] 首先,您需要一个 Stripe 账户。[立即注册](https://dashboard.stripe.com/register)。 ### 服务器端 该集成要求您的服务器上的端点与 Stripe API 通信。用我们的官方库从您的应用程序访问 Stripe API: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ### 客户端 [Stripe iOS SDK](https://github.com/stripe/stripe-ios) 是开源的,[有完整的文档](https://stripe.dev/stripe-ios/index.html),并且与支持 iOS 13 或更高版本操作系统的应用程序兼容。 #### Swift Package Manager 要安装 SDK,按这些步骤进行: 1. 在 Xcode 中,选择**文件** > **添加工具包依赖…**并输入 `https://github.com/stripe/stripe-ios-spm` 作为仓库 URL。 1. 从我们的[发布页面](https://github.com/stripe/stripe-ios/releases)选择最新的版本号。 1. 将 **StripePaymentSheet** 产品添加到[您的目标应用程序](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app)。 #### CocoaPods 1. 如果您还没有[CocoaPods](https://guides.cocoapods.org/using/getting-started.html),请安装其最新版本。 1. 如果您目前没有 [Podfile](https://guides.cocoapods.org/syntax/podfile.html),请运行以下命令创建一个: ```bash pod init ``` 1. 将这一行代码添加到您的 `Podfile`: ```podfile pod 'StripePaymentSheet' ``` 1. 运行以下命令: ```bash pod install ``` 1. 今后,一定记得用 `.xcworkspace` 文件来打开您在 Xcode 中的项目,不要使用 `.xcodeproj` 文件。 1. 将来,要更新到 SDK 的最新版本,运行: ```bash pod update StripePaymentSheet ``` #### Carthage 1. 如果您还没有[Carthage](https://github.com/Carthage/Carthage#installing-carthage),请安装其最新版本。 1. 将这一行代码添加到您的 `Cartfile`。 ```cartfile github "stripe/stripe-ios" ``` 1. 按照 [Carthage 安装说明](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos)进行。确保嵌入[这里](https://github.com/stripe/stripe-ios/tree/master/StripePaymentSheet/README.md#manual-linking)所列的所有必要框架。 1. 将来,要更新到 SDK 的最新版本,运行以下命令即可: ```bash carthage update stripe-ios --platform ios ``` #### 手动框架 1. 前往我们的 [GitHub 发布页面](https://github.com/stripe/stripe-ios/releases/latest),下载并解压缩 **Stripe.xcframework.zip**。 1. 将 **StripePaymentSheet.xcframework** 拖拽到您的 Xcode 项目中 **General**(常规)设置的 **Embedded Binaries**(嵌入式二进制文件)部分。一定要选择 **Copy items if needed**(需要时复制项目)。 1. 为[这里](https://github.com/stripe/stripe-ios/tree/master/StripePaymentSheet/README.md#manual-linking)所列的所有必要框架重复第 2 步。 1. 将来,要更新到 SDK 的最新版本,重复第 1-3 步。 > 有关最新 SDK 发布及过往版本的详细信息,请查看 GitHub 上的[发布](https://github.com/stripe/stripe-ios/releases)页面。要想在新版本发布时接收通知,请[查看仓库的发布](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository)。 ## 启用支付方式 银行卡付款默认启用。查看您的[支付方式设置](https://dashboard.stripe.com/settings/payment_methods),启用您想支持的更多支付方式。 ## 添加端点 [服务器端] > #### 注意 > > 要在创建 PaymentIntent 之前显示 PaymentSheet,请参阅[收集支付详情后再创建 Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=payment)。 该集成使用三个 Stripe API 对象: 1. [PaymentIntent](https://docs.stripe.com/api/payment_intents.md):Stripe 用它来表示您从客户收款的意图,跟踪您的扣款尝试及整个过程中付款状态的变化情况。 1. (可选) [客户配置的 Account](https://docs.stripe.com/api/v2/core/accounts/object.md#v2_account_object-applied_configurations) 或 [Customer](https://docs.stripe.com/api/customers.md) 对象:若要设置用于后续支付的支付方式,必须将其关联至客户。当客户在您的业务平台创建账户时,新建一个对象来代表该客户。如果客户以访客身份进行支付,您可在支付前创建一个 `Account` 对象或 `Customer` 对象,并在后续将其与您内部系统中的客户账户记录相关联。 1. (可选) [CustomerSession](https://docs.stripe.com/api/customer_sessions.md):用于表示客户的对象信息属于敏感数据,无法从应用端直接获取。`CustomerSession` 会为 SDK 提供针对 `Account` 或 `Customer` 对象的临时、受限访问权限,并提供额外的配置选项。请查看完整的 [配置选项](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components) 列表。 出于安全原因,您的应用无法创建这些对象。相反,在服务器上会添加一个端点,其功能如下: 1. 检索 `Account` 或 `Customer`,或者创建一个新的对象。 1. 为 `Account` 或 `Customer` 创建 [CustomerSession](https://docs.stripe.com/api/customer_sessions.md)。 1. 创建一个 `PaymentIntent`,其中包含 [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount)、[currency](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-currency)、 [setup_future_usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage), 以及 [customer_account](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer_account) 或 [customer](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer)。 1. 将 `PaymentIntent` 的 *客户端私钥* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer))、`CustomerSession` 的 `client_secret`、`Account` 或 `Customer` 的 ID 以及您的 [可发布密钥](https://dashboard.stripe.com/apikeys) 返回给您的应用。 > 移动端 Payment Element 仅支持拥有卡和美国银行账户的 `setup_future_usage`。 在结账过程中显示给客户的支付方式也包含在 PaymentIntent 中。您可以让 Stripe 从管理平台设置中提取支付方式,也可以手动列出它们。无论选择哪种方式,都要知道在 PaymentIntent 中传递的货币会过滤显示给客户的支付方式。例如,如果您在 PaymentIntent 中传递 `eur`,并且在管理平台中启用了 OXXO,则不会向客户显示 OXXO,因为 OXXO 不支持 `eur` 支付。 除非您的集成需要基于代码的选项来提供支付方式,否则 Stripe 建议使用自动选项。这是因为 Stripe 会评估货币、支付方式限制和其他参数,以确定支持的支付方式列表。优先显示可提高转化率且与货币和客户所在地最相关的支付方式。 #### 从管理平台管理支付方式 您可以从[管理平台](https://dashboard.stripe.com/settings/payment_methods)管理支付方式。Stripe 根据交易金额、货币和支付流程等因素处理符合条件的支付方式的退货。PaymentIntent 是用您在管理平台中配置的支付方式创建的。如不想使用管理平台或想手动指定支付方式,可通过 `payment_method_types` 属性将其列出。 #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "setup_future_usage"="off_session" \ -d "automatic_payment_methods[enabled]"=true \ ``` #### 手动列出支付方式 #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "setup_future_usage"="off_session" \ -d "payment_method_types[]"="card" \ ``` > 每个支付方式都要支持在 PaymentIntent 中传递的货币,且您的公司必须要位于各支付方式支持的某个国家/地区。查看[支付方式集成选项](https://docs.stripe.com/payments/payment-methods/integration-options.md)页面,查看具体支持哪些。 ## 收集付款详情 [客户端] 要在结账屏幕上显示移动版 Payment Element,请执行以下操作: - 显示客户正在购买的产品以及总金额 - 用 [Address Element](https://docs.stripe.com/elements/address-element.md?platform=ios) 从客户那里收集所需的配送信息 - 添加结账按钮以显示 Stripe 的 UI #### UIKit #### Accounts v2 在您应用的结账页面中,从您上一步创建的端点获取 PaymentIntent 的客户端私钥、`CustomerSession` 的客户端私钥、客户配置的 `Account` ID 以及可发布的密钥。使用 `STPAPIClient.shared` 设置您的可发布密钥,并初始化 [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html)。 #### iOS (Swift) ```swift import UIKit@_spi(CustomerSessionBetaAccess) import StripePaymentSheet class CheckoutViewController: UIViewController { @IBOutlet weak var checkoutButton: UIButton! var paymentSheet: PaymentSheet? let backendCheckoutUrl = URL(string: "Your back-end endpoint/payment-sheet")! // Your back-end endpoint override func viewDidLoad() { super.viewDidLoad() checkoutButton.addTarget(self, action: #selector(didTapCheckoutButton), for: .touchUpInside) checkoutButton.isEnabled = false // MARK: Fetch the PaymentIntent client secret, CustomerSession client secret, customer-configured Account ID, and publishable key var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerAccountId = json["customerAccount"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey// MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customerAccount = .init(id: customerAccountId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. configuration.allowsDelayedPaymentMethods = true self.paymentSheet = PaymentSheet(paymentIntentClientSecret:paymentIntentClientSecret, configuration: configuration) DispatchQueue.main.async { self.checkoutButton.isEnabled = true } }) task.resume() } } ``` #### Customers v1 在您应用的结账页面中,从您上一步创建的端点获取 PaymentIntent 的客户端私钥、`CustomerSession` 客户端私钥、`Customer` ID 以及可发布密钥。使用 `STPAPIClient.shared` 设置您的可发布密钥,并初始化 [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html)。 #### iOS (Swift) ```swift import UIKit@_spi(CustomerSessionBetaAccess) import StripePaymentSheet class CheckoutViewController: UIViewController { @IBOutlet weak var checkoutButton: UIButton! var paymentSheet: PaymentSheet? let backendCheckoutUrl = URL(string: "Your backend endpoint/payment-sheet")! // Your backend endpoint override func viewDidLoad() { super.viewDidLoad() checkoutButton.addTarget(self, action: #selector(didTapCheckoutButton), for: .touchUpInside) checkoutButton.isEnabled = false // MARK: Fetch the PaymentIntent client secret, CustomerSession client secret, Customer ID, and publishable key var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey// MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. configuration.allowsDelayedPaymentMethods = true self.paymentSheet = PaymentSheet(paymentIntentClientSecret:paymentIntentClientSecret, configuration: configuration) DispatchQueue.main.async { self.checkoutButton.isEnabled = true } }) task.resume() } } ``` 当客户点击**结账**按钮时,调用 `present` 以显示 PaymentSheet。在客户完成支付后,Stripe 会关闭 PaymentSheet,并使用 [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html) 调用完成块。 #### iOS (Swift) ```swift @objc func didTapCheckoutButton() { // MARK: Start the checkout process paymentSheet?.present(from: self) { paymentResult in // MARK: Handle the payment result switch paymentResult { case .completed: print("Your order is confirmed") case .canceled: print("Canceled!") case .failed(let error): print("Payment failed: \(error)") } } } ``` #### SwiftUI #### Accounts v2 为您的结账界面创建一个 `ObservableObject` 模块。此模型发布 [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html) 和 [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html)。 ```swift import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your back-end endpoint/payment-sheet")! // Your back-end endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? } ``` 从您在上一步中创建的端点获取 PaymentIntent 客户端私钥、`CustomerSession` 客户端私钥、客户配置的 `Account` ID 以及可发布密钥。使用 `STPAPIClient.shared` 设置您的可发布密钥,并初始化 [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html)。 ```swift @_spi(CustomerSessionBetaAccess) import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your back-end endpoint/payment-sheet")! // Your back-end endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? func preparePaymentSheet() { // MARK: Fetch thePaymentIntent and customer information from the back end var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerAccountId = json["customerAccount"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, letpaymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey// MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customerAccount = .init(id: customerAccountId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. configuration.allowsDelayedPaymentMethods = true DispatchQueue.main.async { self.paymentSheet = PaymentSheet(paymentIntentClientSecret:paymentIntentClientSecret, configuration: configuration) } }) task.resume() } } struct CheckoutView: View { @ObservedObject var model = CheckoutViewModel() var body: some View { VStack { if model.paymentSheet != nil { Text("Ready to pay.") } else { Text("Loading…") } }.onAppear { model.preparePaymentSheet() } } } ``` 向您的 `View` 添加 [PaymentSheet.PaymentButton](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/PaymentButton.html)。该行为类似于 SwiftUI `Button`,它允许您通过添加 `View` 来进行定制。点击该按钮时,会显示 PaymentSheet。在完成支付后,Stripe 会关闭 PaymentSheet,并使用 [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html) 对象调用 `onCompletion` 处理程序。 ```swift @_spi(CustomerSessionBetaAccess) import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your back-end endpoint/payment-sheet")! // Your back-end endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? func preparePaymentSheet() { // MARK: Fetch the PaymentIntent and customer information from the back end var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerAccountId = json["customerAccount"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey // MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customerAccount = .init(id: customerAccountId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business can handle payment methods // that complete payment after a delay, like SEPA Debit and Sofort. configuration.allowsDelayedPaymentMethods = true DispatchQueue.main.async { self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) } }) task.resume() } func onPaymentCompletion(result: PaymentSheetResult) { self.paymentResult = result } } struct CheckoutView: View { @ObservedObject var model = CheckoutViewModel() var body: some View { VStack {if let paymentSheet = model.paymentSheet { PaymentSheet.PaymentButton( paymentSheet: paymentSheet, onCompletion: model.onPaymentCompletion ) { Text("Buy") } } else { Text("Loading…") }if let result = model.paymentResult { switch result { case .completed: Text("Payment complete") case .failed(let error): Text("Payment failed: \(error.localizedDescription)") case .canceled: Text("Payment canceled.") } } }.onAppear { model.preparePaymentSheet() } } } ``` #### Customers v1 为您的结账界面创建一个 `ObservableObject` 模块。此模型发布 [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html) 和 [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html)。 ```swift import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your back-end endpoint/payment-sheet")! // Your back-end endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? } ``` 从您在上一步中创建的端点获取 PaymentIntent 客户端私钥、CustomerSession 客户端私钥、`Customer` ID 以及可发布密钥。使用 `STPAPIClient.shared` 设置您的可发布密钥,并初始化 [PaymentSheet](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet.html)。 ```swift @_spi(CustomerSessionBetaAccess) import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your back-end endpoint/payment-sheet")! // Your back-end endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? func preparePaymentSheet() { // MARK: Fetch thePaymentIntent and Customer information from the back end var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, letpaymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey// MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. configuration.allowsDelayedPaymentMethods = true DispatchQueue.main.async { self.paymentSheet = PaymentSheet(paymentIntentClientSecret:paymentIntentClientSecret, configuration: configuration) } }) task.resume() } } struct CheckoutView: View { @ObservedObject var model = CheckoutViewModel() var body: some View { VStack { if model.paymentSheet != nil { Text("Ready to pay.") } else { Text("Loading…") } }.onAppear { model.preparePaymentSheet() } } } ``` 向您的 `View` 添加 [PaymentSheet.PaymentButton](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/PaymentButton.html)。该行为类似于 SwiftUI `Button`,它允许您通过添加 `View` 来进行定制。点击该按钮时,会显示 PaymentSheet。在完成支付后,Stripe 会关闭 PaymentSheet,并使用 [PaymentSheetResult](https://stripe.dev/stripe-ios/stripe-paymentsheet/Enums/PaymentSheetResult.html) 对象调用 `onCompletion` 处理程序。 ```swift @_spi(CustomerSessionBetaAccess) import StripePaymentSheet import SwiftUI class CheckoutViewModel: ObservableObject { let backendCheckoutUrl = URL(string: "Your back-end endpoint/payment-sheet")! // Your back-end endpoint @Published var paymentSheet: PaymentSheet? @Published var paymentResult: PaymentSheetResult? func preparePaymentSheet() { // MARK: Fetch the PaymentIntent and Customer information from the back end var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerSessionClientSecret = json["customerSessionClientSecret"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let publishableKey = json["publishableKey"] as? String, let self = self else { // Handle error return } STPAPIClient.shared.publishableKey = publishableKey // MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret) // Set `allowsDelayedPaymentMethods` to true if your business can handle payment methods // that complete payment after a delay, like SEPA Debit and Sofort. configuration.allowsDelayedPaymentMethods = true DispatchQueue.main.async { self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) } }) task.resume() } func onPaymentCompletion(result: PaymentSheetResult) { self.paymentResult = result } } struct CheckoutView: View { @ObservedObject var model = CheckoutViewModel() var body: some View { VStack {if let paymentSheet = model.paymentSheet { PaymentSheet.PaymentButton( paymentSheet: paymentSheet, onCompletion: model.onPaymentCompletion ) { Text("Buy") } } else { Text("Loading…") }if let result = model.paymentResult { switch result { case .completed: Text("Payment complete") case .failed(let error): Text("Payment failed: \(error.localizedDescription)") case .canceled: Text("Payment canceled.") } } }.onAppear { model.preparePaymentSheet() } } } ``` 如果 `PaymentSheetResult` 为 `.completed`,请通知客户(例如,通过显示订单确认页面)。 将 `allowsDelayedPaymentMethods` 设置为 true,以允许[延迟通知型](https://docs.stripe.com/payments/payment-methods.md#payment-notification)支付方式,例如美国银行账户。对于这些支付方式,只有当 `PaymentSheet` 完成后才能知道最终的付款状态是成功还是失败。如果您支持这些类型的支付方式,请告知客户他们的订单已被确认,并且仅在付款成功时履行订单(例如,为他们安排发货)。 ## 设置返回URL [客户端] 客户可能会离开您的应用来验证(例如,去 Safari 或他们的网银应用)。若允许他们在验证后自动返回到您的应用,[配置一个自定义页面内跳转协议 (URL Scheme)](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app),并设置您的应用程序代理将 URL 转发到 SDK。Stripe 不支持[通用链接](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content)。 #### SceneDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { guard let url = URLContexts.first?.url else { return } let stripeHandled = StripeAPI.handleURLCallback(with: url) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } ``` #### AppDelegate #### Swift ```swift // This method handles opening custom URL schemes (for example, "your-app://stripe-redirect") func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { let stripeHandled = StripeAPI.handleURLCallback(with: url) if (stripeHandled) { return true } else { // This was not a Stripe url – handle the URL normally as you would } return false } ``` #### SwiftUI #### Swift ```swift @main struct MyApp: App { var body: some Scene { WindowGroup { Text("Hello, world!").onOpenURL { incomingURL in let stripeHandled = StripeAPI.handleURLCallback(with: incomingURL) if (!stripeHandled) { // This was not a Stripe url – handle the URL normally as you would } } } } } ``` 此外,将您的 [PaymentSheet.Configuration](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html) 对象上的 [returnURL](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV9returnURLSSSgvp) 设置到您的应用的 URL。 ```swift var configuration = PaymentSheet.Configuration() configuration.returnURL = "your-app://stripe-redirect" ``` ## 处理付款后事件 [服务器端] 付款完成时,Stripe 会发送一个 [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) 事件。使用 [管理平台 Webhook 工具](https://dashboard.stripe.com/webhooks)、或按照 [Webhook 指南](https://docs.stripe.com/webhooks/quickstart.md)来接收这些事件并运行操作,例如,向客户发送订单确认邮件、在数据库中记录订单,或启动配送流程。 侦听这些事件,而不是等待客户端回调。在客户端,客户可能会在执行回调之前关闭浏览器窗口或退出应用程序,并且恶意客户端可能会操纵响应。设置您的集成来侦听异步事件,这样才能用单一集成用用接受[不同类型的支付方式](https://stripe.com/payments/payment-methods-guide)。 除了处理 `payment_intent.succeeded` 事件外,建议在使用 Payment Element 收款时也处理其他的这些事件: | 事件 | 描述 | 操作 | | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.succeeded) | 客户成功完成付款时发送。 | 向客户发送订单确认通知,并*履行* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected)他们的订单。 | | [payment_intent.processing](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.processing) | 当客户成功发起付款但并未完成时发送。当客户发起银行借记时,通常会发送此事件。之后将会出现 `payment_intent.succeeded` 或 `payment_intent.payment_failed` 事件。 | 向客户发送订单确认,告知他们的付款正等待处理。对于数字商品,您可能想先履行订单,然后再等付款完成。 | | [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.payment_failed) | 在客户尝试付款但付款失败时发送。 | 如果一笔付款从 `processing` 变为 `payment_failed`,则让客户再尝试一次。 | ## 以后对保存的 Payment Method 扣款 [服务器端] > #### 合规 > > 保存客户的支付详情时,您有责任遵守所有适用的法律、法规和卡组织规则。向您的最终客户呈现之前用过的支付方式以供未来购物使用时,确保您所列出的支付方式已从客户那里收集保存支付方式详情以供将来具体使用的同意书。对于绑定到客户的支付方式,要区分哪些可以哪些不可以作为保存的支付方式供未来购物使用,请使用 [allow_redisplay](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-allow_redisplay) 参数。 要查找可用于扣款的支付方式,请列出与客户关联的支付方式。此示例列出了银行卡,但您可以列出任何受支持的[类型](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-type)。 > #### 使用 Accounts v2 API 表示客户 > > Accounts v2 API 通常面向 Connect 用户开放,并对其他 Stripe 用户开放公开预览。如果您参与了 Accounts v2 预览,您需要在代码中[指定预览版本](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning)。 > > 如需申请 Accounts v2 预览版的访问权限, > > 在大多数应用场景下,我们建议[将您的客户建模为客户配置的 Account 对象](https://docs.stripe.com/accounts-v2/use-accounts-as-customers.md),而不是使用 [Customer](https://docs.stripe.com/api/customers.md) 对象。 #### Accounts v2 ```curl curl -G https://api.stripe.com/v1/payment_methods \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d type=card ``` #### Customers v1 ```curl curl -G https://api.stripe.com/v1/payment_methods \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" \ -d type=card ``` 当您准备在*离线会话* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information)期间向客户扣款时,请使用 `Customer` 或客户配置的 `Account` 的 ID,以及 `PaymentMethod` 的 ID,配合支付金额和币种来创建 `PaymentIntent`。同时设置其他几个参数以完成离线会话支付: - 将 [off_session](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-off_session) 设置为 true,表示客户当前不在您的结账流程中,因此无法响应任何身份验证请求。如果在结账流程中,合作方(如发卡行或银行)要求进行身份验证,Stripe 会使用之前*会话内* (A payment is described as on-session if it occurs while the customer is actively in your checkout flow and able to authenticate the payment method)交易中的客户信息来申请豁免。若不符合豁免条件,`PaymentIntent` 可能会抛出错误。 - 将 [confirm](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-confirm) 设置为 true,以便在创建 `PaymentIntent` 时立即触发确认。 - 将 [payment_method](https://docs.stripe.com/api.md#create_payment_intent-payment_method) 设置为 `PaymentMethod` 的 ID。 - 根据您在集成中如何代表客户,请将 [customer_account](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer_account) 设为客户配置型 `Account` 的 ID,或将 [customer](https://docs.stripe.com/api.md#create_payment_intent-customer) 设为 `Customer` 的 ID。 #### 账户 v2 ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]=true" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d payment_method={{PAYMENT_METHOD_ID}} \ --data-urlencode "return_url=https://example.com/order/123/complete" \ -d off_session=true \ -d confirm=true ``` #### 客户 v1 ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]=true" \ -d "customer={{CUSTOMER_ID}}" \ -d payment_method={{PAYMENT_METHOD_ID}} \ --data-urlencode "return_url=https://example.com/order/123/complete" \ -d off_session=true \ -d confirm=true ``` ## 测试整合情况 #### 银行卡 | 支付方式 | 场景 | 如何测试 | | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | | 信用卡 | 银行卡设置成功,不要求*验证* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase)。 | 填写我们的信用卡表单,卡号是 `4242 4242 4242 4242`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | | 信用卡 | 该卡在初始设置时需要身份验证,在后续付款时会直接成功。 | 填写我们的信用卡表单,卡号是 `4000 0025 0000 3155`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | | 信用卡 | 该卡在初始设置时需要身份验证,在后续付款时也需要身份验证。 | 填写我们的信用卡表单,卡号是 `4000 0027 6000 3184`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | | 信用卡 | 设置过程中卡被拒绝了。 | 填写我们的信用卡表单,卡号是 `4000 0000 0000 9995`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | ## Optional: 启用 Apple Pay > 如果您的结账界面有专门的 **Apple Pay 按钮**,则按照 [Apple Pay 指南](https://docs.stripe.com/apple-pay.md#present-payment-sheet)中的说明并使用 `ApplePayContext` 从您的 Apple Pay 按钮收款。您可以用 `PaymentSheet` 来处理其他支付方式类型。 ### 注册 Apple Merchant ID 可通过在 Apple 开发人员网站[注册新的标识符](https://developer.apple.com/account/resources/identifiers/add/merchant)来获取 Apple 商家 ID。 在表单中填写描述和标识符。描述内容仅供您自己记录之用,之后可随时更改。Stripe 建议用您的应用的名称作为标识符(例如,`merchant.com.{{YOUR_APP_NAME}}`)。 ### 创建新的 Apple Pay 证书 为您的应用创建证书,以加密支付数据。 转到管理平台中的 [iOS 证书设置](https://dashboard.stripe.com/settings/ios_certificates),点击**添加新应用程序**,然后按照说明进行操作。 下载证书签名请求 (CSR) 文件,来从 Apple 获取安全证书,以便使用 Apple Pay。 必须用一个 CSR 文件发布具体的一个证书。如果您切换您的 Apple Merchant ID,则必须前往管理平台的 [iOS 证书设置](https://dashboard.stripe.com/settings/ios_certificates)中获取一个新的 CSR 和证书。 ### 集成 Xcode 将 Apple Pay 功能添加到您的应用程序。在 Xcode 中,打开您的项目设置,点击**签名和功能**选项卡,然后添加 **Apple Pay** 功能。此时,系统可能会提示您登入您的开发人员账户。选择您之前创建的商家 ID,您的应用程序就可以接受 Apple Pay 了。 ![](https://b.stripecdn.com/docs-statics-srv/assets/xcode.a701d4c1922d19985e9c614a6f105bf1.png) 在 Xcode 中启用 Apple Pay 功能 ### 添加 Apple Pay #### 一次性付款 要将 Apple Pay 添加到 PaymentSheet,用您的 Apple 商家 ID 和[国家/地区代码](https://dashboard.stripe.com/settings/account)初始化 `PaymentSheet.Configuration` 之后设置 [applePay](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV8applePayAC05ApplefD0VSgvp)。 #### iOS (Swift) ```swift var configuration = PaymentSheet.Configuration() configuration.applePay = .init( merchantId: "merchant.com.your_app_name", merchantCountryCode: "US" ) ``` #### 经常性付款 要将 Apple Pay 添加到 PaymentSheet,用您的 Apple 商家 ID 和[国家/地区代码](https://dashboard.stripe.com/settings/account)初始化 `PaymentSheet.Configuration` 之后设置 [applePay](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:6Stripe12PaymentSheetC13ConfigurationV8applePayAC05ApplefD0VSgvp)。 对于经常性付款,根据 [Apple 的指南](https://developer.apple.com/design/human-interface-guidelines/apple-pay#Supporting-subscriptions),您还必须在 `PKPaymentRequest` 上设置额外的属性。在 [ApplePayConfiguration.paymentRequestHandlers](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/paymentrequesthandler) 中添加一个处理程序,以配置 [PKPaymentRequest.paymentSummaryItems](https://developer.apple.com/documentation/passkit/pkpaymentrequest/1619231-paymentsummaryitems),指定您期望收取的金额(例如,“每月 9.95 美元”)。 还可以通过在 `PKPaymentRequest` 上设置 `recurringPaymentRequest` 或 `automaticReloadPaymentRequest` 属性来采用[商家令牌](https://developer.apple.com/apple-pay/merchant-tokens/)。 要了解有关如何通过 Apple Pay 使用经常性付款的更多信息,请参阅 [Apple 的 PassKit 文档](https://developer.apple.com/documentation/passkit/pkpaymentrequest)。 #### iOS (Swift) ```swift let customHandlers = PaymentSheet.ApplePayConfiguration.Handlers( paymentRequestHandler: { request in // PKRecurringPaymentSummaryItem is available on iOS 15 or later if #available(iOS 15.0, *) { let billing = PKRecurringPaymentSummaryItem(label: "My Subscription", amount: NSDecimalNumber(string: "59.99")) // Payment starts today billing.startDate = Date() // Payment ends in one year billing.endDate = Date().addingTimeInterval(60 * 60 * 24 * 365) // Pay once a month. billing.intervalUnit = .month billing.intervalCount = 1 // recurringPaymentRequest is only available on iOS 16 or later if #available(iOS 16.0, *) { request.recurringPaymentRequest = PKRecurringPaymentRequest(paymentDescription: "Recurring", regularBilling: billing, managementURL: URL(string: "https://my-backend.example.com/customer-portal")!) request.recurringPaymentRequest?.billingAgreement = "You'll be billed $59.99 every month for the next 12 months. To cancel at any time, go to Account and click 'Cancel Membership.'" } request.paymentSummaryItems = [billing] request.currencyCode = "USD" } else { // On older iOS versions, set alternative summary items. request.paymentSummaryItems = [PKPaymentSummaryItem(label: "Monthly plan starting July 1, 2022", amount: NSDecimalNumber(string: "59.99"), type: .final)] } return request } ) var configuration = PaymentSheet.Configuration() configuration.applePay = .init(merchantId: "merchant.com.your_app_name", merchantCountryCode: "US", customHandlers: customHandlers) ``` ### 订单跟踪 要在 iOS 16 或更高版本中添加[订单跟踪](https://developer.apple.com/design/human-interface-guidelines/technologies/wallet/designing-order-tracking)信息,请在您的 `PaymentSheet.ApplePayConfiguration.Handlers` 中配置一个 [authorizationResultHandler](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/authorizationresulthandler)。Stripe 会在支付完成后调用您的实施的程序,但该操作在 iOS 关闭 Apple Pay 表单之前进行。 在您的 `authorizationResultHandler` 实现中,从服务器获取已完成订单的订单详情。将这些详情添加到提供的 [PKPaymentAuthorizationResult](https://developer.apple.com/documentation/passkit/pkpaymentauthorizationresult) 中,并返回修改后的结果。 要了解有关订单跟踪的更多信息,请参阅 [Apple 钱包订单文档](https://developer.apple.com/documentation/walletorders)。 #### iOS (Swift) ```swift let customHandlers = PaymentSheet.ApplePayConfiguration.Handlers( authorizationResultHandler: { result in do { // Fetch the order details from your service let myOrderDetails = try await MyAPIClient.shared.fetchOrderDetails(orderID: orderID) result.orderDetails = PKPaymentOrderDetails( orderTypeIdentifier: myOrderDetails.orderTypeIdentifier, // "com.myapp.order" orderIdentifier: myOrderDetails.orderIdentifier, // "ABC123-AAAA-1111" webServiceURL: myOrderDetails.webServiceURL, // "https://my-backend.example.com/apple-order-tracking-backend" authenticationToken: myOrderDetails.authenticationToken) // "abc123" // Return your modified PKPaymentAuthorizationResult return result } catch { return PKPaymentAuthorizationResult(status: .failure, errors: [error]) } } ) var configuration = PaymentSheet.Configuration() configuration.applePay = .init(merchantId: "merchant.com.your_app_name", merchantCountryCode: "US", customHandlers: customHandlers) ``` ## 启用银行卡扫描 若要在 iOS 上启用卡片扫描支持,请在应用程序的 `Info.plist` 中设置 `NSCameraUsageDescription`(**隐私 - 相机使用说明**),并提供访问相机的原因(例如,“用于扫描卡片”)。 ## Optional: 自定义表单 所有自定义操作均通过 [PaymentSheet.Configuration](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html) 对象来配置。 ### 外观 使用 [Appearance API](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=ios) 自定义颜色、字体等,使其与应用程序的视觉风格相匹配。 ### 支付方式布局 使用 [paymentMethodLayout](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/configuration-swift.struct/paymentmethodlayout) 配置表单中支付方式的布局。可以水平、垂直显示,也可以让 Stripe 自动优化布局。 ![](https://b.stripecdn.com/docs-statics-srv/assets/ios-mpe-payment-method-layouts.9d0513e2fcec5660378ba1824d952054.png) #### Swift ```swift var configuration = PaymentSheet.Configuration() configuration.paymentMethodLayout = .automatic ``` ### 收集用户地址 用 [Address Element](https://docs.stripe.com/elements/address-element.md?platform=ios) 收集客户的本地和国际收货地址或账单地址。 ### 商家显示名称 通过设置 [merchantDisplayName](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:18StripePaymentSheet0bC0C13ConfigurationV19merchantDisplayNameSSvp) 来指定一个向客户显示的商家名称。默认情况下,使用的是您的应用的名称。 #### Swift ```swift var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "My app, Inc." ``` ### 暗色模式 `PaymentSheet` 自动适应用户的系统范围内的外观设置(明暗模式)。如果您的应用不支持暗色模式,可将 [style](https://stripe.dev/stripe-ios/stripe-paymentsheet/Classes/PaymentSheet/Configuration.html#/s:18StripePaymentSheet0bC0C13ConfigurationV5styleAC18UserInterfaceStyleOvp) 设置到 `alwaysLight` 或 `alwaysDark` 模式。 ```swift var configuration = PaymentSheet.Configuration() configuration.style = .alwaysLight ``` ### 默认账单详情 要为支付表单中收集的账单详情设置默认值,请配置 `defaultBillingDetails` 属性。`paymentSheet` 会用您提供的值预先填充其字段。 ```swift var configuration = PaymentSheet.Configuration() configuration.defaultBillingDetails.address.country = "US" configuration.defaultBillingDetails.email = "foo@bar.com" ``` ### 收集账单详情 用 `billingDetailsCollectionConfiguration` 来指定您希望如何在支付表单中收集账单详情。 可以收集客户的姓名、邮件地址、电话号码和地址。 如果您只想通过支付方式获得所需的账单详情,请将 `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` 设置为 true。在这种情况下,`PaymentSheet.Configuration.defaultBillingDetails` 被设置为支付方式的 [billing details](https://docs.stripe.com/api/payment_methods/object.md?lang=node#payment_method_object-billing_details)。 如果您希望收集支付方式非必需的额外账单详情,请将 `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` 设置为 false。在这种情况下,通过 `PaymentSheet` 收集的账单详情被设置为支付方式的账单详情。 ```swift var configuration = PaymentSheet.Configuration() configuration.defaultBillingDetails.email = "foo@bar.com" configuration.billingDetailsCollectionConfiguration.name = .always configuration.billingDetailsCollectionConfiguration.email = .never configuration.billingDetailsCollectionConfiguration.address = .full configuration.billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod = true ``` > 请咨询律师,了解与收集信息有关的法律。仅在需要收集号码来完成交易时,才收集手机号码。 ## Optional: 在您的用户界面完成付款 您可以在出示支付表单时仅收集支付方式详情,然后再在您的应用的用户界面上调用 `confirm` 方法来完成付款。如果您使用自定义购买按钮,或在收集了付款详情后需要额外的步骤,这会非常有用。 ![](https://b.stripecdn.com/docs-statics-srv/assets/ios-multi-step.cd631ea4f1cd8cf3f39b6b9e1e92b6c5.png) 在您的应用程序的用户界面内完成付款 #### UIKit 以下步骤将引导您在您的应用程序的用户界面内完成付款。前往 [GitHub](https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet%20Example/PaymentSheet%20Example/ExampleCustomCheckoutViewController.swift) 查看我们的示例集成。 1. 首先,初始化 [PaymentSheet.FlowController](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller),而非 `PaymentSheet`,并用它的 `paymentOption` 属性更新您的用户界面。该属性包含表示客户最初选择的默认支付方式的图片和标签。 ```swift PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) { [weak self] result in switch result { case .failure(let error): print(error) case .success(let paymentSheetFlowController): self?.paymentSheetFlowController = paymentSheetFlowController // Update your UI using paymentSheetFlowController.paymentOption } } ``` 1. 然后,调用 `presentPaymentOptions` 来收集付款详情。完成后,用 `paymentOption` 属性再次更新您的用户界面。 ```swift paymentSheetFlowController.presentPaymentOptions(from: self) { // Update your UI using paymentSheetFlowController.paymentOption } ``` 1. 最后,调用 `confirm`。 ```swift paymentSheetFlowController.confirm(from: self) { paymentResult in // MARK: Handle the payment result switch paymentResult { case .completed: print("Payment complete!") case .canceled: print("Canceled!") case .failed(let error): print(error) } } ``` #### SwiftUI 以下步骤将引导您在您的应用程序的用户界面内完成付款。前往 [GitHub](https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet%20Example/PaymentSheet%20Example/ExampleSwiftUICustomPaymentFlow.swift) 查看我们的示例集成。 1. 首先,初始化 [PaymentSheet.FlowController](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller),而非 `PaymentSheet`。它的 `paymentOption` 属性包含表示客户当前选择的支付方式的图片和标签,可在您的用户界面内使用。 ```swift PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) { [weak self] result in switch result { case .failure(let error): print(error) case .success(let paymentSheetFlowController): self?.paymentSheetFlowController = paymentSheetFlowController // Use the paymentSheetFlowController.paymentOption properties in your UI myPaymentMethodLabel = paymentSheetFlowController.paymentOption?.label ?? "Select a payment method" myPaymentMethodImage = paymentSheetFlowController.paymentOption?.image ?? UIImage(systemName: "square.and.pencil")! } } ``` 1. 用 [PaymentSheet.FlowController.PaymentOptionsButton](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller/paymentoptionsbutton) 包裹表示付款详情收集表单的按钮。当 `PaymentSheet.FlowController` 调用 `onSheetDismissed` 函数时,`PaymentSheet.FlowController` 实例的 `paymentOption` 会反映当前选择的支付方式。 ```swift PaymentSheet.FlowController.PaymentOptionsButton( paymentSheetFlowController: paymentSheetFlowController, onSheetDismissed: { myPaymentMethodLabel = paymentSheetFlowController.paymentOption?.label ?? "Select a payment method" myPaymentMethodImage = paymentSheetFlowController.paymentOption?.image ?? UIImage(systemName: "square.and.pencil")! }, content: { /* An example button */ HStack { Text(myPaymentMethodLabel) Image(uiImage: myPaymentMethodImage) } } ) ``` 1. 用 [PaymentSheet.FlowController.PaymentOptionsButton](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/flowcontroller/paymentoptionsbutton) 包裹付款确认按钮。 ```swift PaymentSheet.FlowController.ConfirmButton( paymentSheetFlowController: paymentSheetFlowController, onCompletion: { result in // MARK: Handle the payment result switch result { case .completed: print("Payment complete!") case .canceled: print("Canceled!") case .failed(let error): print(error) } }, content: { /* An example button */ Text("Pay") } ) ``` 将 `allowsDelayedPaymentMethods` 设置为 true,以允许[延迟通知型](https://docs.stripe.com/payments/payment-methods.md#payment-notification)支付方式,例如美国银行账户。对于这些支付方式,只有当 `PaymentSheet` 完成后才能知道最终的付款状态是成功还是失败。如果您支持这些类型的支付方式,请告知客户他们的订单已被确认,并且仅在付款成功时履行订单(例如,为他们安排发货)。 # Android > This is a Android for when platform is android and mobile-ui is payment-sheet. View the full page at https://docs.stripe.com/payments/mobile/save-during-payment?platform=android&mobile-ui=payment-sheet. 用 [Payment Intents API](https://docs.stripe.com/api/payment_intents.md) 保存购物时输入的付款详情。有几个用例: - 对客户的网上订单扣款并存储支付信息,用于以后的购物。 - 发起一系列经常性付款中的第一笔付款。 - 收取押金并存储详情,便于以后收取完整金额。 > #### 有卡交易 > > 有卡交易(例如通过 Stripe Terminal 支付)使用不同的流程来保存支付方式。有关详情,请查看 [Terminal 文档](https://docs.stripe.com/terminal/features/saving-payment-details/save-after-payment.md)。 ## 合规 在保存客户的支付详情以备将来使用时,您有责任遵守所有适用的法律、法规和网络规则,比如在结账流程中向客户显示其支付方式以便未来购买,或在客户未主动使用您的网站或应用程序时向他们收费。在保存或向客户的支付方式收费之前,请确保您: - 在您的网站或应用中添加说明您计划如何保存支付方式详情的条款,例如: - 客户协议允许您代表他们针对指定交易发起支付或一系列支付。 - 预期的付款时间和频率(例如,收款是计划的分期付款、订阅付款还是计划外充值)。 - 如何确定付款金额。 - 如果支付方式是用于支付订阅服务,那即同意您的取消政策。 - 仅出于条款中所述的目的,使用保存的支付方式。 - 为此特定用途收集客户的明确同意。例如,可以添加一个“保存我的支付方式以备将来使用”的复选框。 - 记录客户对您的条款的书面同意。 ## 设置 Stripe [服务器端] [客户端] 首先,您需要一个 Stripe 账户。[立即注册](https://dashboard.stripe.com/register)。 ### 服务器端 该集成要求您的服务器上的端点与 Stripe API 通信。用官方库从您的服务器访问 Stripe API: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ### 客户端 [Stripe Android SDK](https://github.com/stripe/stripe-android) 是开源的,且[有完整的文档](https://stripe.dev/stripe-android/)。 安装 SDK 时,将 `stripe-android` 添加到您的 [app/build.gradle](https://developer.android.com/studio/build/dependencies) 文件的 `dependencies` 块中: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Stripe Android SDK implementation("com.stripe:stripe-android:23.9.0") // Include the financial connections SDK to support US bank account as a payment method implementation("com.stripe:financial-connections:23.9.0") } ``` > 有关最新 SDK 发布及过往版本的详细信息,请查看 GitHub 上的[发布](https://github.com/stripe/stripe-android/releases)页面。要想在新版本发布时接收通知,请[查看仓库的发布情况](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository)。 ## 启用支付方式 银行卡付款默认启用。查看您的[支付方式设置](https://dashboard.stripe.com/settings/payment_methods),启用您想支持的更多支付方式。 ## 添加端点 [服务器端] > #### 注意 > > 要在创建 PaymentIntent 之前显示 PaymentSheet,请参阅[收集支付详情后再创建 Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=payment)。 该集成使用三个 Stripe API 对象: 1. [PaymentIntent](https://docs.stripe.com/api/payment_intents.md):Stripe 用它来表示您从客户收款的意图,跟踪您的扣款尝试及整个过程中付款状态的变化情况。 1. (可选) [客户配置的 Account](https://docs.stripe.com/api/v2/core/accounts/object.md#v2_account_object-applied_configurations) 或 [Customer](https://docs.stripe.com/api/customers.md) 对象:若要设置用于后续支付的支付方式,必须将其关联至客户。当客户在您的业务平台创建账户时,新建一个对象来代表该客户。如果客户以访客身份进行支付,您可在支付前创建一个 `Account` 对象或 `Customer` 对象,并在后续将其与您内部系统中的客户账户记录相关联。 1. (可选) [CustomerSession](https://docs.stripe.com/api/customer_sessions.md):用于表示客户的对象信息属于敏感数据,无法从应用端直接获取。`CustomerSession` 会为 SDK 提供针对 `Account` 或 `Customer` 对象的临时、受限访问权限,并提供额外的配置选项。请查看完整的 [配置选项](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components) 列表。 出于安全原因,您的应用无法创建这些对象。相反,在服务器上会添加一个端点,其功能如下: 1. 检索 `Account` 或 `Customer`,或者创建一个新的对象。 1. 为 `Account` 或 `Customer` 创建 [CustomerSession](https://docs.stripe.com/api/customer_sessions.md)。 1. 创建一个 `PaymentIntent`,其中包含 [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount)、[currency](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-currency)、 [setup_future_usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage), 以及 [customer_account](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer_account) 或 [customer](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer)。 1. 将 `PaymentIntent` 的 *客户端私钥* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer))、`CustomerSession` 的 `client_secret`、`Account` 或 `Customer` 的 ID 以及您的 [可发布密钥](https://dashboard.stripe.com/apikeys) 返回给您的应用。 > 移动端 Payment Element 仅支持拥有卡和美国银行账户的 `setup_future_usage`。 在结账过程中显示给客户的支付方式也包含在 PaymentIntent 中。您可以让 Stripe 从管理平台设置中提取支付方式,也可以手动列出它们。无论选择哪种方式,都要知道在 PaymentIntent 中传递的货币会过滤显示给客户的支付方式。例如,如果您在 PaymentIntent 中传递 `eur`,并且在管理平台中启用了 OXXO,则不会向客户显示 OXXO,因为 OXXO 不支持 `eur` 支付。 除非您的集成需要基于代码的选项来提供支付方式,否则 Stripe 建议使用自动选项。这是因为 Stripe 会评估货币、支付方式限制和其他参数,以确定支持的支付方式列表。优先显示可提高转化率且与货币和客户所在地最相关的支付方式。 #### 从管理平台管理支付方式 您可以从[管理平台](https://dashboard.stripe.com/settings/payment_methods)管理支付方式。Stripe 根据交易金额、货币和支付流程等因素处理符合条件的支付方式的退货。PaymentIntent 是用您在管理平台中配置的支付方式创建的。如不想使用管理平台或想手动指定支付方式,可通过 `payment_method_types` 属性将其列出。 #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "setup_future_usage"="off_session" \ -d "automatic_payment_methods[enabled]"=true \ ``` #### 手动列出支付方式 #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "setup_future_usage"="off_session" \ -d "payment_method_types[]"="card" \ ``` > 每个支付方式都要支持在 PaymentIntent 中传递的货币,且您的公司必须要位于各支付方式支持的某个国家/地区。查看[支付方式集成选项](https://docs.stripe.com/payments/payment-methods/integration-options.md)页面,查看具体支持哪些。 ## 收集付款详情 [客户端] 显示移动端 Payment Element 前,您的结账页面应: - 显示购买的产品和总金额 - 用 [Address Element](https://docs.stripe.com/elements/address-element.md?platform=android) 收集所需的配送信息 - 包含一个结账按钮来展示 Stripe 的 UI #### Jetpack Compose [初始化](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-builder/index.html)您的结账活动的 `onCreate` 内的一个 `PaymentSheet` 实例,从而传递一个支付方式来处理结果。 ```kotlin import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult @Composable fun App() { val paymentSheet = remember { PaymentSheet.Builder(::onPaymentSheetResult) }.build() } private fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } ``` 接下来,从您在上一步中创建的端点中获取 PaymentIntent 客户端私钥、Customer Session 客户端私钥、客户 ID 和可发布私钥。使用 `PaymentConfiguration` 设置可发布私钥,并存储其他内容,以便在您展示 PaymentSheet 时使用。 ```kotlin import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberimport androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import com.stripe.android.PaymentConfiguration import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult @Composable fun App() { val paymentSheet = remember { PaymentSheet.Builder(::onPaymentSheetResult) }.build()val context = LocalContext.current var customerConfig by remember { mutableStateOf(null) } varpaymentIntentClientSecret by remember { mutableStateOf(null) } LaunchedEffect(context) { // Make a request to your own server and retrieve payment configurations val networkResult = ... if (networkResult.isSuccess) {paymentIntentClientSecret = networkResult.paymentIntent customerConfig = PaymentSheet.CustomerConfiguration.createWithCustomerSession( id = networkResult.customer, clientSecret = networkResult.customerSessionClientSecret )PaymentConfiguration.init(context, networkResult.publishableKey)} } } private fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } ``` 当客户点击您的结账按钮时,调用 [presentWithPaymentIntent](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html#1814490530%2FFunctions%2F2002900378) 来显示支付表单。客户完成付款后,表单将消失,然后 [PaymentSheetResult](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result/index.html) 将调用 [PaymentSheetResultCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result-callback/index.html)。 ```kotlin import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import com.stripe.android.PaymentConfiguration import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult @Composable fun App() { val paymentSheet = remember { PaymentSheet.Builder(::onPaymentSheetResult) }.build() val context = LocalContext.current var customerConfig by remember { mutableStateOf(null) } var paymentIntentClientSecret by remember { mutableStateOf(null) } LaunchedEffect(context) { // Make a request to your own server and retrieve payment configurations val networkResult = ... if (networkResult.isSuccess) { paymentIntentClientSecret = networkResult.paymentIntent customerConfig = PaymentSheet.CustomerConfiguration.createWithCustomerSession( id = networkResult.customer, clientSecret = networkResult.customerSessionClientSecret ) PaymentConfiguration.init(context, networkResult.publishableKey) } }Button( onClick = { val currentConfig = customerConfig val currentClientSecret =paymentIntentClientSecret if (currentConfig != null && currentClientSecret != null) { presentPaymentSheet(paymentSheet, currentConfig, currentClientSecret) } } ) { Text("Checkout") } }private fun presentPaymentSheet( paymentSheet: PaymentSheet, customerConfig: PaymentSheet.CustomerConfiguration,paymentIntentClientSecret: String ) { paymentSheet.presentWithPaymentIntent(paymentIntentClientSecret, PaymentSheet.Configuration.Builder(merchantDisplayName = "My merchant name") .customer(customerConfig) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. .allowsDelayedPaymentMethods(true) .build() ) } private fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {when(paymentSheetResult) { is PaymentSheetResult.Canceled -> { print("Canceled") } is PaymentSheetResult.Failed -> { print("Error: ${paymentSheetResult.error}") } is PaymentSheetResult.Completed -> { // Display for example, an order confirmation screen print("Completed") } } } ``` #### 视图(经典) [初始化](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html#-394860221%2FConstructors%2F2002900378)您的结账活动的 `onCreate` 内的 `PaymentSheet` 实例,传递一个支付方式来处理结果。 #### Kotlin ```kotlin import com.stripe.android.paymentsheet.PaymentSheet class CheckoutActivity : AppCompatActivity() { lateinit var paymentSheet: PaymentSheet override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) paymentSheet = PaymentSheet.Builder(::onPaymentSheetResult).build(this) } fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } } ``` 接下来,从您在上一步中创建的端点中获取 PaymentIntent 客户端私钥、Customer Session 客户端私钥、客户 ID 和可发布私钥。使用 `PaymentConfiguration` 设置可发布私钥,并存储其他内容,以便在您展示 PaymentSheet 时使用。 #### Kotlin ```kotlin import com.stripe.android.paymentsheet.PaymentSheet class CheckoutActivity : AppCompatActivity() { lateinit var paymentSheet: PaymentSheetlateinit var customerConfig: PaymentSheet.CustomerConfiguration lateinit varpaymentIntentClientSecret: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) paymentSheet = PaymentSheet.Builder(::onPaymentSheetResult).build(this)lifecycleScope.launch { // Make a request to your own server and retrieve payment configurations val networkResult = MyBackend.getPaymentConfig() if (networkResult.isSuccess) {paymentIntentClientSecret = networkResult.paymentIntent customerConfig = PaymentSheet.CustomerConfiguration.createWithCustomerSession( id = networkResult.customer, clientSecret = networkResult.customerSessionClientSecret )PaymentConfiguration.init(context, networkResult.publishableKey)} } } fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) { // implemented in the next steps } } ``` 当客户点击您的结账按钮时,调用 [presentWithPaymentIntent](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html#1814490530%2FFunctions%2F2002900378) 来显示支付表单。客户完成付款后,表单将消失,然后 [PaymentSheetResult](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result/index.html) 将调用 [PaymentSheetResultCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result-callback/index.html)。 #### Kotlin ```kotlin // ... class CheckoutActivity : AppCompatActivity() { lateinit var paymentSheet: PaymentSheet lateinit var customerConfig: PaymentSheet.CustomerConfiguration lateinit var paymentIntentClientSecret: String // ...fun presentPaymentSheet() { paymentSheet.presentWithPaymentIntent(paymentIntentClientSecret, PaymentSheet.Configuration.Builder(merchantDisplayName = "My merchant name") .customer(customerConfig) // Set `allowsDelayedPaymentMethods` to true if your business handles // delayed notification payment methods like US bank accounts. .allowsDelayedPaymentMethods(true) .build() ) } fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {when(paymentSheetResult) { is PaymentSheetResult.Canceled -> { print("Canceled") } is PaymentSheetResult.Failed -> { print("Error: ${paymentSheetResult.error}") } is PaymentSheetResult.Completed -> { // Display for example, an order confirmation screen print("Completed") } } } } ``` 将 `allowsDelayedPaymentMethods` 设置为 true,以允许[延迟通知型](https://docs.stripe.com/payments/payment-methods.md#payment-notification)支付方式,例如美国银行账户。对于这些支付方式,只有当 `PaymentSheet` 完成后才能知道最终的付款状态是成功还是失败。如果您支持这些类型的支付方式,请告知客户他们的订单已被确认,并且仅在付款成功时履行订单(例如,为他们安排发货)。 ## 处理付款后事件 [服务器端] 付款完成时,Stripe 会发送一个 [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) 事件。使用 [管理平台 Webhook 工具](https://dashboard.stripe.com/webhooks)、或按照 [Webhook 指南](https://docs.stripe.com/webhooks/quickstart.md)来接收这些事件并运行操作,例如,向客户发送订单确认邮件、在数据库中记录订单,或启动配送流程。 侦听这些事件,而不是等待客户端回调。在客户端,客户可能会在执行回调之前关闭浏览器窗口或退出应用程序,并且恶意客户端可能会操纵响应。设置您的集成来侦听异步事件,这样才能用单一集成用用接受[不同类型的支付方式](https://stripe.com/payments/payment-methods-guide)。 除了处理 `payment_intent.succeeded` 事件外,建议在使用 Payment Element 收款时也处理其他的这些事件: | 事件 | 描述 | 操作 | | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.succeeded) | 客户成功完成付款时发送。 | 向客户发送订单确认通知,并*履行* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected)他们的订单。 | | [payment_intent.processing](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.processing) | 当客户成功发起付款但并未完成时发送。当客户发起银行借记时,通常会发送此事件。之后将会出现 `payment_intent.succeeded` 或 `payment_intent.payment_failed` 事件。 | 向客户发送订单确认,告知他们的付款正等待处理。对于数字商品,您可能想先履行订单,然后再等付款完成。 | | [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.payment_failed) | 在客户尝试付款但付款失败时发送。 | 如果一笔付款从 `processing` 变为 `payment_failed`,则让客户再尝试一次。 | ## 以后对保存的 Payment Method 扣款 [服务器端] > #### 合规 > > 保存客户的支付详情时,您有责任遵守所有适用的法律、法规和卡组织规则。向您的最终客户呈现之前用过的支付方式以供未来购物使用时,确保您所列出的支付方式已从客户那里收集保存支付方式详情以供将来具体使用的同意书。对于绑定到客户的支付方式,要区分哪些可以哪些不可以作为保存的支付方式供未来购物使用,请使用 [allow_redisplay](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-allow_redisplay) 参数。 要查找可用于扣款的支付方式,请列出与客户关联的支付方式。此示例列出了银行卡,但您可以列出任何受支持的[类型](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-type)。 > #### 使用 Accounts v2 API 表示客户 > > Accounts v2 API 通常面向 Connect 用户开放,并对其他 Stripe 用户开放公开预览。如果您参与了 Accounts v2 预览,您需要在代码中[指定预览版本](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning)。 > > 如需申请 Accounts v2 预览版的访问权限, > > 在大多数应用场景下,我们建议[将您的客户建模为客户配置的 Account 对象](https://docs.stripe.com/accounts-v2/use-accounts-as-customers.md),而不是使用 [Customer](https://docs.stripe.com/api/customers.md) 对象。 #### Accounts v2 ```curl curl -G https://api.stripe.com/v1/payment_methods \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d type=card ``` #### Customers v1 ```curl curl -G https://api.stripe.com/v1/payment_methods \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" \ -d type=card ``` 当您准备在*离线会话* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information)期间向客户扣款时,请使用 `Customer` 或客户配置的 `Account` 的 ID,以及 `PaymentMethod` 的 ID,配合支付金额和币种来创建 `PaymentIntent`。同时设置其他几个参数以完成离线会话支付: - 将 [off_session](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-off_session) 设置为 true,表示客户当前不在您的结账流程中,因此无法响应任何身份验证请求。如果在结账流程中,合作方(如发卡行或银行)要求进行身份验证,Stripe 会使用之前*会话内* (A payment is described as on-session if it occurs while the customer is actively in your checkout flow and able to authenticate the payment method)交易中的客户信息来申请豁免。若不符合豁免条件,`PaymentIntent` 可能会抛出错误。 - 将 [confirm](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-confirm) 设置为 true,以便在创建 `PaymentIntent` 时立即触发确认。 - 将 [payment_method](https://docs.stripe.com/api.md#create_payment_intent-payment_method) 设置为 `PaymentMethod` 的 ID。 - 根据您在集成中如何代表客户,请将 [customer_account](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer_account) 设为客户配置型 `Account` 的 ID,或将 [customer](https://docs.stripe.com/api.md#create_payment_intent-customer) 设为 `Customer` 的 ID。 #### 账户 v2 ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]=true" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d payment_method={{PAYMENT_METHOD_ID}} \ --data-urlencode "return_url=https://example.com/order/123/complete" \ -d off_session=true \ -d confirm=true ``` #### 客户 v1 ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "automatic_payment_methods[enabled]=true" \ -d "customer={{CUSTOMER_ID}}" \ -d payment_method={{PAYMENT_METHOD_ID}} \ --data-urlencode "return_url=https://example.com/order/123/complete" \ -d off_session=true \ -d confirm=true ``` ## 测试整合情况 #### 银行卡 | 支付方式 | 场景 | 如何测试 | | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | | 信用卡 | 银行卡设置成功,不要求*验证* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase)。 | 填写我们的信用卡表单,卡号是 `4242 4242 4242 4242`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | | 信用卡 | 该卡在初始设置时需要身份验证,在后续付款时会直接成功。 | 填写我们的信用卡表单,卡号是 `4000 0025 0000 3155`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | | 信用卡 | 该卡在初始设置时需要身份验证,在后续付款时也需要身份验证。 | 填写我们的信用卡表单,卡号是 `4000 0027 6000 3184`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | | 信用卡 | 设置过程中卡被拒绝了。 | 填写我们的信用卡表单,卡号是 `4000 0000 0000 9995`,有效期、CVC(银行卡安全码)以及邮编可任意填写。 | ## Optional: 启用 Google Pay ### 设置您的集成 要使用 Google Pay,先将以下内容添加到您的 **AndroidManifest.xml** 的 ``标签,来启用 Google Pay API: ```xml ... ``` 更多详情,请参见 Google Pay 针对 Android 设备编写的[设置 Google Pay API](https://developers.google.com/pay/api/android/guides/setup) 指南。 ### 添加 Google Pay 要向您的集成添加 Google Pay,初始化 [PaymentSheet.Configuration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/index.html) 时,传递您的 Google Pay 环境(生产或测试)下的 [PaymentSheet.GooglePayConfiguration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-google-pay-configuration/index.html) 和[贵公司的国家/地区代码](https://dashboard.stripe.com/settings/account)。 #### Kotlin ```kotlin val googlePayConfiguration = PaymentSheet.GooglePayConfiguration( environment = PaymentSheet.GooglePayConfiguration.Environment.Test, countryCode = "US", currencyCode = "USD" // Required for Setup Intents, optional for Payment Intents ) val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "My merchant name") .googlePay(googlePayConfiguration) .build() ``` ### 测试 Google Pay Google 允许您通过其[测试卡套件](https://developers.google.com/pay/api/android/guides/resources/test-card-suite)进行测试付款。该测试套件支持使用 Stripe [测试卡](https://docs.stripe.com/testing.md)。 您必须在支持 Google Pay 的国家/地区使用 Android 实体设备(而不是模拟设备)测试 Google Pay。使用保存到 Google 钱包的真实银行卡登录测试设备上的 Google 账户。 ## Optional: 自定义表单 所有自定义操作均用 [PaymentSheet.Configuration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/index.html) 对象来配置。 ### 外观 使用 [Appearance API](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=android) 自定义颜色、字体等,使其与应用程序的视觉风格相匹配。 ### 支付方式布局 使用 [paymentMethodLayout](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/-builder/index.html#2123253356%2FFunctions%2F2002900378) 配置表单中支付方式的布局。可以水平、垂直显示,也可以让 Stripe 自动优化布局。 ![](https://b.stripecdn.com/docs-statics-srv/assets/android-mpe-payment-method-layouts.3bcfe828ceaad1a94e0572a22d91733f.png) #### Kotlin ```kotlin PaymentSheet.Configuration.Builder("Example, Inc.") .paymentMethodLayout(PaymentSheet.PaymentMethodLayout.Automatic) .build() ``` ### 收集用户地址 用 [Address Element](https://docs.stripe.com/elements/address-element.md?platform=android) 收集客户的本地和国际收货地址或账单地址。 ### 商家显示名称 通过设置 [merchantDisplayName](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-configuration/index.html#-191101533%2FProperties%2F2002900378) 来指定一个向客户显示的商家名称。默认情况下,使用的是您的应用的名称。 #### Kotlin ```kotlin PaymentSheet.Configuration.Builder( merchantDisplayName = "My app, Inc." ).build() ``` ### 暗色模式 默认情况下,`PaymentSheet` 自动适应用户的整个系统的外观设置(明暗模式)。可通过在您的应用上设置亮色或暗色模式来更改: #### Kotlin ```kotlin // force dark AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) // force light AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) ``` ### 默认账单详情 要为支付表单中收集的账单详情设置默认值,请配置 `defaultBillingDetails` 属性。`paymentSheet` 会用您提供的值预先填充其字段。 #### Kotlin ```kotlin val address = PaymentSheet.Address(country = "US") val billingDetails = PaymentSheet.BillingDetails( address = address, email = "foo@bar.com" ) val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "Merchant, Inc.") .defaultBillingDetails(billingDetails) .build() ``` ### 配置账单详情的收集 使用 `BillingDetailsCollectionConfiguration` 指定您希望如何在 PaymentSheet 中收集账单详情。 可以收集客户的姓名、邮件地址、电话号码和地址。 如果希望将默认账单详情关联到 PaymentMethod 对象(即使 UI 中未收集这些字段),请将 `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` 设置为 `true`。 #### Kotlin ```kotlin val billingDetails = PaymentSheet.BillingDetails( email = "foo@bar.com" ) val billingDetailsCollectionConfiguration = BillingDetailsCollectionConfiguration( attachDefaultsToPaymentMethod = true, name = BillingDetailsCollectionConfiguration.CollectionMode.Always, email = BillingDetailsCollectionConfiguration.CollectionMode.Never, address = BillingDetailsCollectionConfiguration.AddressCollectionMode.Full, ) val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "Merchant, Inc.") .defaultBillingDetails(billingDetails) .billingDetailsCollectionConfiguration(billingDetailsCollectionConfiguration) .build() ``` > 请咨询律师,了解与收集信息有关的法律。仅在需要收集号码来完成交易时,才收集手机号码。 ## Optional: 在您的用户界面完成付款 您可以在出示支付表单时仅收集支付方式详情,然后再在您的应用的用户界面上完成付款。如果您使用的是自定义购买按钮或在收集了付款详情后要求额外的步骤,这会非常有用。 ![](https://b.stripecdn.com/docs-statics-srv/assets/android-multi-step.84d8a0a44b1baa596bda491322b6d9fd.png) > 集成示例参见 [GitHub](https://github.com/stripe/stripe-android/blob/master/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/samples/ui/paymentsheet/custom_flow/CustomFlowActivity.kt)。 1. 首先,用某个 [Builder](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/-builder/index.html) 方法初始化 [PaymentSheet.FlowController](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html),而非 `PaymentSheet`。 #### Android (Kotlin) ```kotlin class CheckoutActivity : AppCompatActivity() { private lateinit var flowController: PaymentSheet.FlowController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val flowController = PaymentSheet.FlowController.Builder( resultCallback = ::onPaymentSheetResult, paymentOptionResultCallback = ::onPaymentOption, ).build(this) } } ``` 1. 然后,用从您的后端获取的 Stripe 对象密钥调用 `configureWithPaymentIntent`,并用[getPaymentOption()](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html#-2091462043%2FFunctions%2F2002900378) 在回调中更新您的用户界面。这包含一个表示客户当前选择的支付方式的图片和标签。 #### Android (Kotlin) ```kotlin flowController.configureWithPaymentIntent( paymentIntentClientSecret = paymentIntentClientSecret, configuration = PaymentSheet.Configuration.Builder("Example, Inc.") .customer(PaymentSheet.CustomerConfiguration( id = customerId, ephemeralKeySecret = ephemeralKeySecret )) .build() ) { isReady, error -> if (isReady) { // Update your UI using `flowController.getPaymentOption()` } else { // handle FlowController configuration failure } } ``` 1. 然后,调用 [presentPaymentOptions](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html#449924733%2FFunctions%2F2002900378) 来收集付款详情。客户完成后,表单被丢弃,并调用之前在 `create` 中传入的 [paymentOptionCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-option-callback/index.html)。实施该方法,用返回的 `paymentOption` 更新您的 UI。 #### Android (Kotlin) ```kotlin // ... flowController.presentPaymentOptions() // ... private fun onPaymentOption(paymentOptionResult: PaymentOptionResult) { val paymentOption = paymentOptionResult.paymentOption if (paymentOption != null) { paymentMethodButton.text = paymentOption.label paymentMethodButton.setCompoundDrawablesRelativeWithIntrinsicBounds( paymentOption.drawableResourceId, 0, 0, 0 ) } else { paymentMethodButton.text = "Select" paymentMethodButton.setCompoundDrawablesRelativeWithIntrinsicBounds( null, null, null, null ) } } ``` 1. 最后,调用 [confirm](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/-flow-controller/index.html#-479056656%2FFunctions%2F2002900378),完成付款。客户完成后,表单被丢弃,并调用之前在 `create` 中创建的 [paymentResultCallback](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet-result-callback/index.html#237248767%2FFunctions%2F2002900378)。 #### Android (Kotlin) ```kotlin // ... flowController.confirmPayment() // ... private fun onPaymentSheetResult( paymentSheetResult: PaymentSheetResult ) { when (paymentSheetResult) { is PaymentSheetResult.Canceled -> { // Payment canceled } is PaymentSheetResult.Failed -> { // Payment Failed. See logcat for details or inspect paymentSheetResult.error } is PaymentSheetResult.Completed -> { // Payment Complete } } } ``` 将 `allowsDelayedPaymentMethods` 设置为 true,以允许[延迟通知型](https://docs.stripe.com/payments/payment-methods.md#payment-notification)支付方式,例如美国银行账户。对于这些支付方式,只有当 `PaymentSheet` 完成后才能知道最终的付款状态是成功还是失败。如果您支持这些类型的支付方式,请告知客户他们的订单已被确认,并且仅在付款成功时履行订单(例如,为他们安排发货)。 # React Native > This is a React Native for when platform is react-native and mobile-ui is payment-sheet. View the full page at https://docs.stripe.com/payments/mobile/save-during-payment?platform=react-native&mobile-ui=payment-sheet. 用 [Payment Intents API](https://docs.stripe.com/api/payment_intents.md) 保存购物时输入的付款详情。有几个用例: - 对客户的网上订单扣款并存储支付信息,用于以后的购物。 - 发起一系列经常性付款中的第一笔付款。 - 收取押金并存储详情,便于以后收取完整金额。 > #### 有卡交易 > > 有卡交易(例如通过 Stripe Terminal 支付)使用不同的流程来保存支付方式。有关详情,请查看 [Terminal 文档](https://docs.stripe.com/terminal/features/saving-payment-details/save-after-payment.md)。 ## 合规 在保存客户的支付详情以备将来使用时,您有责任遵守所有适用的法律、法规和网络规则,比如在结账流程中向客户显示其支付方式以便未来购买,或在客户未主动使用您的网站或应用程序时向他们收费。在保存或向客户的支付方式收费之前,请确保您: - 在您的网站或应用中添加说明您计划如何保存支付方式详情的条款,例如: - 客户协议允许您代表他们针对指定交易发起支付或一系列支付。 - 预期的付款时间和频率(例如,收款是计划的分期付款、订阅付款还是计划外充值)。 - 如何确定付款金额。 - 如果支付方式是用于支付订阅服务,那即同意您的取消政策。 - 仅出于条款中所述的目的,使用保存的支付方式。 - 为此特定用途收集客户的明确同意。例如,可以添加一个“保存我的支付方式以备将来使用”的复选框。 - 记录客户对您的条款的书面同意。 ## 设置 Stripe [服务器端] [客户端] 首先,您需要一个 Stripe 账户。[立即注册](https://dashboard.stripe.com/register)。 ### 服务器端 该集成要求您的服务器上的端点与 Stripe API 通信。用官方库从您的服务器访问 Stripe API: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ### 客户端 [React Native SDK](https://github.com/stripe/stripe-react-native) 是开源的,有完整的文档。在内部,它利用的是[原生 iOS](https://github.com/stripe/stripe-ios) 和 [Android](https://github.com/stripe/stripe-android) SDK。要安装 Stripe 的 React Native SDK,在您的项目目录中运行以下某个指令(取决于您使用的软件包管理器)。 #### yarn ```bash yarn add @stripe/stripe-react-native ``` #### npm ```bash npm install @stripe/stripe-react-native ``` 然后,安装一些其他必要的依赖项: - 对于 iOS,请转到 **ios** 目录并运行 `pod install` 以确保同时安装了所需的本地依赖项。 - 对于 Android,无需安装其他依赖项。 > 建议按照[官方 TypeScript 指南](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project)添加 TypeScript 支持。 ### Stripe 初始化 要在您的 React Native 应用中初始化 Stripe,使用 `StripeProvider` 组件包裹您的支付界面,或者使用 `initStripe` 初始化方法。只需要 `publishableKey` 中的 API [公钥](https://docs.stripe.com/keys.md#obtain-api-keys)。下例显示的是用 `StripeProvider` 组件初始化 Stripe 的方式。 ```jsx import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( {/* Your app code here */} ); } ``` > 测试与开发时使用 API [测试模式](https://docs.stripe.com/keys.md#obtain-api-keys),发布时使用[真实模式](https://docs.stripe.com/keys.md#test-live-modes)密钥。 ## 启用支付方式 银行卡付款默认启用。查看您的[支付方式设置](https://dashboard.stripe.com/settings/payment_methods),启用您想支持的更多支付方式。 ## 添加端点 [服务器端] > #### 注意 > > 要在创建 PaymentIntent 之前显示 PaymentSheet,请参阅[收集支付详情后再创建 Intent](https://docs.stripe.com/payments/accept-a-payment-deferred.md?type=payment)。 该集成使用三个 Stripe API 对象: 1. [PaymentIntent](https://docs.stripe.com/api/payment_intents.md):Stripe 用它来表示您从客户收款的意图,跟踪您的扣款尝试及整个过程中付款状态的变化情况。 1. (可选) [客户配置的 Account](https://docs.stripe.com/api/v2/core/accounts/object.md#v2_account_object-applied_configurations) 或 [Customer](https://docs.stripe.com/api/customers.md) 对象:若要设置用于后续支付的支付方式,必须将其关联至客户。当客户在您的业务平台创建账户时,新建一个对象来代表该客户。如果客户以访客身份进行支付,您可在支付前创建一个 `Account` 对象或 `Customer` 对象,并在后续将其与您内部系统中的客户账户记录相关联。 1. (可选) [CustomerSession](https://docs.stripe.com/api/customer_sessions.md):用于表示客户的对象信息属于敏感数据,无法从应用端直接获取。`CustomerSession` 会为 SDK 提供针对 `Account` 或 `Customer` 对象的临时、受限访问权限,并提供额外的配置选项。请查看完整的 [配置选项](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components) 列表。 出于安全原因,您的应用无法创建这些对象。相反,在服务器上会添加一个端点,其功能如下: 1. 检索 `Account` 或 `Customer`,或者创建一个新的对象。 1. 为 `Account` 或 `Customer` 创建 [CustomerSession](https://docs.stripe.com/api/customer_sessions.md)。 1. 创建一个 `PaymentIntent`,其中包含 [amount](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-amount)、[currency](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-currency)、 [setup_future_usage](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-setup_future_usage), 以及 [customer_account](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer_account) 或 [customer](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer)。 1. 将 `PaymentIntent` 的 *客户端私钥* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer))、`CustomerSession` 的 `client_secret`、`Account` 或 `Customer` 的 ID 以及您的 [可发布密钥](https://dashboard.stripe.com/apikeys) 返回给您的应用。 > 移动端 Payment Element 仅支持拥有卡和美国银行账户的 `setup_future_usage`。 在结账过程中显示给客户的支付方式也包含在 PaymentIntent 中。您可以让 Stripe 从管理平台设置中提取支付方式,也可以手动列出它们。无论选择哪种方式,都要知道在 PaymentIntent 中传递的货币会过滤显示给客户的支付方式。例如,如果您在 PaymentIntent 中传递 `eur`,并且在管理平台中启用了 OXXO,则不会向客户显示 OXXO,因为 OXXO 不支持 `eur` 支付。 除非您的集成需要基于代码的选项来提供支付方式,否则 Stripe 建议使用自动选项。这是因为 Stripe 会评估货币、支付方式限制和其他参数,以确定支持的支付方式列表。优先显示可提高转化率且与货币和客户所在地最相关的支付方式。 #### 从管理平台管理支付方式 您可以从[管理平台](https://dashboard.stripe.com/settings/payment_methods)管理支付方式。Stripe 根据交易金额、货币和支付流程等因素处理符合条件的支付方式的退货。PaymentIntent 是用您在管理平台中配置的支付方式创建的。如不想使用管理平台或想手动指定支付方式,可通过 `payment_method_types` 属性将其列出。 #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "setup_future_usage"="off_session" \ -d "automatic_payment_methods[enabled]"=true \ ``` #### 手动列出支付方式 #### curl ```bash # Create a Customer (use an existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" \ -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}" # Create an CustomerSession for the Customer curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[mobile_payment_element][enabled]"=true \ -d "components[mobile_payment_element][features][payment_method_save]"=enabled \ -d "components[mobile_payment_element][features][payment_method_redisplay]"=enabled \ -d "components[mobile_payment_element][features][payment_method_remove]"=enabled # Create a PaymentIntent curl https://api.stripe.com/v1/payment_intents \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="eur" \ -d "setup_future_usage"="off_session" \ -d "payment_method_types[]"="card" \ ``` > 每个支付方式都要支持在 PaymentIntent 中传递的货币,且您的公司必须要位于各支付方式支持的某个国家/地区。查看[支付方式集成选项](https://docs.stripe.com/payments/payment-methods/integration-options.md)页面,查看具体支持哪些。 ## 收集付款详情 [客户端] 显示移动端 Payment Element 前,您的结账页面应: - 显示购买的产品和总金额 - 收集所需的配送信息 - 包含一个结账按钮来展示 Stripe 的 UI 在您的应用的结账表单内,向上一步中创建的后端端点发送网络请求,从 `useStripe` hook 调用 `initPaymentSheet`。 #### Accounts v2 ```javascript export default function CheckoutScreen() { const { initPaymentSheet, presentPaymentSheet } = useStripe(); const [loading, setLoading] = useState(false); const fetchPaymentSheetParams = async () => { const response = await fetch(`${API_URL}/payment-sheet`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, }); const { paymentIntent, ephemeralKey, customer_account } = await response.json(); return { paymentIntent, ephemeralKey, customer_account, }; }; const initializePaymentSheet = async () => { const { paymentIntent, ephemeralKey, customer_account, } = await fetchPaymentSheetParams(); const { error } = await initPaymentSheet({ merchantDisplayName: "Example, Inc.", customerAccountId: customer_account, customerEphemeralKeySecret: ephemeralKey, paymentIntentClientSecret: paymentIntent, // Set `allowsDelayedPaymentMethods` to true if your business accepts payment // methods that complete payment after a delay, like SEPA Debit and Sofort. allowsDelayedPaymentMethods: true, defaultBillingDetails: { name: 'Jane Doe', } }); if (!error) { setLoading(true); } }; const openPaymentSheet = async () => { // see below }; useEffect(() => { initializePaymentSheet(); }, []); return (