# 在应用内付款期间保存付款详情

在移动应用中保存付款过程中的付款详情。

# iOS

> This is a iOS for when platform is ios and mobile-ui is payment-element. View the full page at https://docs.stripe.com/payments/mobile/save-during-payment?platform=ios&mobile-ui=payment-element.

用 [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` 属性将其列出。

#### Accounts v2

#### curl

```bash
# Create an Account with the customer configuration (use an existing Account ID if this is a returning customer)
curl https://api.stripe.com/v2/core/accounts \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "configuration[customer]"

# Create a CustomerSession for the Account
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \

  -d "automatic_payment_methods[enabled]"=true \
```

#### Customers v1

#### curl

```bash
# Create a Customer (use an existing Customer ID if this is a returning customer)
curl https://api.stripe.com/v1/customers \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}"

# Create an CustomerSession for the Customer
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer"="{{CUSTOMER_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \

  -d "automatic_payment_methods[enabled]"=true \
```

#### 手动列出支付方式

#### Accounts v2

#### curl

```bash
# Create an Account with the customer configuration (use an existing Account ID if this is a returning customer)
curl https://api.stripe.com/v2/core/accounts \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "configuration[customer]"

# Create a CustomerSession for the Account
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \
  -d "payment_method_types[]"="card" \
```

#### Customers v1

#### curl

```bash
# Create a Customer (use an existing Customer ID if this is a returning customer)
curl https://api.stripe.com/v1/customers \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}"

# Create an CustomerSession for the Customer
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -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 <<YOUR_SECRET_KEY>>: \
  -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

在您的应用结账界面中，从您在上一步中创建的端点中获取 PaymentIntent 客户端私钥、CustomerSession 客户端私钥、客户 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

为您的结账界面创建一个 `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 backend endpoint/payment-sheet")! // Your backend endpoint
  @Published var paymentSheet: PaymentSheet?
  @Published var paymentResult: PaymentSheetResult?
}
```

从您在上一步中创建的端点中获取 PaymentIntent 客户端私钥、CustomerSession 客户端私钥、客户 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 backend endpoint/payment-sheet")! // Your backend endpoint
  @Published var paymentSheet: PaymentSheet?
  @Published var paymentResult: PaymentSheetResult?
func preparePaymentSheet() {
    // MARK: Fetch thePaymentIntent and Customer information from the backend
    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 backend endpoint/payment-sheet")! // Your backend endpoint
  @Published var paymentSheet: PaymentSheet?
  @Published var paymentResult: PaymentSheetResult?

  func preparePaymentSheet() {
    // MARK: Fetch the PaymentIntent and Customer information from the backend
    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<UIOpenURLContext>) {
    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/connect/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 "<<YOUR_SECRET_KEY>>:" \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}" \
  -d type=card
```

#### Customers v1

```curl
curl -G https://api.stripe.com/v1/payment_methods \
  -u "<<YOUR_SECRET_KEY>>:" \
  -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)收款时，请使用客户 ID 与 `PaymentMethod` ID，并传入付款金额和币种参数创建 `PaymentIntent`；同时配置其余相关参数，即可完成会话外收款：

- 将 [off_session](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_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` 可能会抛出错误。
- 将 `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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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-element. View the full page at https://docs.stripe.com/payments/mobile/save-during-payment?platform=android&mobile-ui=payment-element.

用 [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.3.0")
  // Include the financial connections SDK to support US bank account as a payment method
  implementation("com.stripe:financial-connections:23.3.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` 属性将其列出。

#### Accounts v2

#### curl

```bash
# Create an Account with the customer configuration (use an existing Account ID if this is a returning customer)
curl https://api.stripe.com/v2/core/accounts \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "configuration[customer]"

# Create a CustomerSession for the Account
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \

  -d "automatic_payment_methods[enabled]"=true \
```

#### Customers v1

#### curl

```bash
# Create a Customer (use an existing Customer ID if this is a returning customer)
curl https://api.stripe.com/v1/customers \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}"

# Create an CustomerSession for the Customer
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer"="{{CUSTOMER_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \

  -d "automatic_payment_methods[enabled]"=true \
```

#### 手动列出支付方式

#### Accounts v2

#### curl

```bash
# Create an Account with the customer configuration (use an existing Account ID if this is a returning customer)
curl https://api.stripe.com/v2/core/accounts \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "configuration[customer]"

# Create a CustomerSession for the Account
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \
  -d "payment_method_types[]"="card" \
```

#### Customers v1

#### curl

```bash
# Create a Customer (use an existing Customer ID if this is a returning customer)
curl https://api.stripe.com/v1/customers \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}"

# Create an CustomerSession for the Customer
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -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 <<YOUR_SECRET_KEY>>: \
  -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<PaymentSheet.CustomerConfiguration?>(null) }
  varpaymentIntentClientSecret by remember { mutableStateOf<String?>(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<PaymentSheet.CustomerConfiguration?>(null) }
  var paymentIntentClientSecret by remember { mutableStateOf<String?>(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/connect/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 "<<YOUR_SECRET_KEY>>:" \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}" \
  -d type=card
```

#### Customers v1

```curl
curl -G https://api.stripe.com/v1/payment_methods \
  -u "<<YOUR_SECRET_KEY>>:" \
  -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)收款时，请使用客户 ID 与 `PaymentMethod` ID，并传入付款金额和币种参数创建 `PaymentIntent`；同时配置其余相关参数，即可完成会话外收款：

- 将 [off_session](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_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` 可能会抛出错误。
- 将 `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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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** 的 `<application>`标签，来启用 Google Pay API：

```xml
<application>
  ...
  <meta-data
    android:name="com.google.android.gms.wallet.api.enabled"
    android:value="true" />
</application>
```

更多详情，请参见 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-element. View the full page at https://docs.stripe.com/payments/mobile/save-during-payment?platform=react-native&mobile-ui=payment-element.

用 [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 (
    <StripeProvider
      publishableKey={publishableKey}
      merchantIdentifier="merchant.identifier" // required for Apple Pay
      urlScheme="your-url-scheme" // required for 3D Secure and bank redirects
    >
      {/* Your app code here */}
    </StripeProvider>
  );
}
```

> 测试与开发时使用 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` 属性将其列出。

#### Accounts v2

#### curl

```bash
# Create an Account with the customer configuration (use an existing Account ID if this is a returning customer)
curl https://api.stripe.com/v2/core/accounts \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "configuration[customer]"

# Create a CustomerSession for the Account
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \

  -d "automatic_payment_methods[enabled]"=true \
```

#### Customers v1

#### curl

```bash
# Create a Customer (use an existing Customer ID if this is a returning customer)
curl https://api.stripe.com/v1/customers \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}"

# Create an CustomerSession for the Customer
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer"="{{CUSTOMER_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \

  -d "automatic_payment_methods[enabled]"=true \
```

#### 手动列出支付方式

#### Accounts v2

#### curl

```bash
# Create an Account with the customer configuration (use an existing Account ID if this is a returning customer)
curl https://api.stripe.com/v2/core/accounts \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "configuration[customer]"

# Create a CustomerSession for the Account
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_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 <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -d "customer_account"="{{CUSTOMER_ACCOUNT_ID}}" \
  -d "amount"=1099 \
  -d "currency"="eur" \
  -d "setup_future_usage"="off_session" \
  -d "payment_method_types[]"="card" \
```

#### Customers v1

#### curl

```bash
# Create a Customer (use an existing Customer ID if this is a returning customer)
curl https://api.stripe.com/v1/customers \
  -u <<YOUR_SECRET_KEY>>: \
  -X "POST" \
  -H "Stripe-Account: {{CONNECTED_ACCOUNT_ID}}"

# Create an CustomerSession for the Customer
curl https://api.stripe.com/v1/customer_sessions \
  -u <<YOUR_SECRET_KEY>>: \
  -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 <<YOUR_SECRET_KEY>>: \
  -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 (
    <Screen>
      <Button
        variant="primary"
        disabled={!loading}
        title="Checkout"
        onPress={openPaymentSheet}
      />
    </Screen>
  );
}
```

#### Customers v1

```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 } = await response.json();

    return {
      paymentIntent,
      ephemeralKey,
      customer,
    };
  };

  const initializePaymentSheet = async () => {
    const {
      paymentIntent,
      ephemeralKey,
      customer,
    } = await fetchPaymentSheetParams();

    const { error } = await initPaymentSheet({
      merchantDisplayName: "Example, Inc.",
      customerId: customer,
      customerEphemeralKeySecret: ephemeralKey,
      paymentIntentClientSecret: paymentIntent,
      // Set `allowsDelayedPaymentMethods` to true if your business can handle 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 (
    <Screen>
      <Button
        variant="primary"
        disabled={!loading}
        title="Checkout"
        onPress={openPaymentSheet}
      />
    </Screen>
  );
}
```

当客户点击 **Checkout** 按钮时，调用 `presentPaymentSheet()` 来打开表单。客户完成付款后，表单关闭，通过一个可选的 `StripeError<PaymentSheetError>` 解析 promise。

```javascript
export default function CheckoutScreen() {
  // continued from above

  const openPaymentSheet = async () => {
    const { error } = await presentPaymentSheet();

    if (error) {
      Alert.alert(`Error code: ${error.code}`, error.message);
    } else {
      Alert.alert('Success', 'Your order is confirmed!');
    }
  };

  return (
    <Screen>
      <Button
        variant="primary"
        disabled={!loading}
        title="Checkout"
        onPress={openPaymentSheet}
      />
    </Screen>
  );
}
```

如果发生错误，则通知用户他们已完成（例如，显示订单确认界面）。

将 `allowsDelayedPaymentMethods` 设置为 true，以允许[延迟通知型](https://docs.stripe.com/payments/payment-methods.md#payment-notification)支付方式，例如美国银行账户。对于这些支付方式，只有当 `PaymentSheet` 完成后才能知道最终的付款状态是成功还是失败。如果您支持这些类型的支付方式，请告知客户他们的订单已被确认，并且仅在付款成功时履行订单（例如，为他们安排发货）。

## 设置返回 URL（仅 iOS） [客户端]

当客户退出您的应用时（例如，在 Safari 浏览器或其银行应用程序中进行验证），为他们提供一种方式，以便他们自动返回到您的应用程序。很多支付方式类型_要求_提供一个返回 URL。如果您不提供这样一个 URL，我们就无法向您的用户显示需要返回 URL 的支付方式，即使您已启用了这些支付方式。

要提供返回 URL，请执行以下操作：

1. [注册](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app#Register-your-URL-scheme) 自定义 URL。不支持通用链接。
1. [配置](https://reactnative.dev/docs/linking) 您的自定义 URL。
1. 设置您的根组件，将 URL 转发到 Stripe SDK，如下所示。

> 如果您在使用 Expo，则在 `app.json` 文件中[设置您的协议](https://docs.expo.io/guides/linking/#in-a-standalone-app)。

```jsx
import { useEffect, useCallback } from 'react';
import { Linking } from 'react-native';
import { useStripe } from '@stripe/stripe-react-native';

export default function MyApp() {
  const { handleURLCallback } = useStripe();

  const handleDeepLink = useCallback(
    async (url: string | null) => {
      if (url) {
        const stripeHandled = await handleURLCallback(url);
        if (stripeHandled) {
          // This was a Stripe URL - you can return or add extra handling here as you see fit
        } else {
          // This was NOT a Stripe URL – handle as you normally would
        }
      }
    },
    [handleURLCallback]
  );

  useEffect(() => {
    const getUrlAsync = async () => {
      const initialUrl = await Linking.getInitialURL();
      handleDeepLink(initialUrl);
    };

    getUrlAsync();

    const deepLinkListener = Linking.addEventListener(
      'url',
      (event: { url: string }) => {
        handleDeepLink(event.url);
      }
    );

    return () => deepLinkListener.remove();
  }, [handleDeepLink]);

  return (
    <View>
      <AwesomeAppComponent />
    </View>
  );
}
```

此外，调用 `initPaymentSheet` 方式时设置 `returnURL`：

```js
await initPaymentSheet({
  ...
  returnURL: 'your-app://stripe-redirect',
  ...
});
```

有关 Native URL Scheme（页面内跳转协议）的更多信息，请参考 [Android](https://developer.android.com/training/app-links/deep-linking) 和 [iOS](https://developer.apple.com/documentation/xcode/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app) 文档。

## 处理付款后事件

付款完成时，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/connect/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 "<<YOUR_SECRET_KEY>>:" \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}" \
  -d type=card
```

#### Customers v1

```curl
curl -G https://api.stripe.com/v1/payment_methods \
  -u "<<YOUR_SECRET_KEY>>:" \
  -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)收款时，请使用客户 ID 与 `PaymentMethod` ID，并传入付款金额和币种参数创建 `PaymentIntent`；同时配置其余相关参数，即可完成会话外收款：

- 将 [off_session](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_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` 可能会抛出错误。
- 将 `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 "<<YOUR_SECRET_KEY>>:" \
  -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 "<<YOUR_SECRET_KEY>>:" \
  -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 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

#### 一次性付款

创建 `StripeProvider` 时传递您的商家 ID：

```javascript
import { StripeProvider } from '@stripe/stripe-react-native';

function App() {
  return (
    <StripeProvider
      publishableKey="<<YOUR_PUBLISHABLE_KEY>>"
      merchantIdentifier="MERCHANT_ID"
    >
      {/* Your app code here */}
    </StripeProvider>
  );
}
```

调用 `initPaymentSheet` 时，传入您的 [ApplePayParams](https://stripe.dev/stripe-react-native/api-reference/modules/PaymentSheet.html#ApplePayParams)：

```javascript
await initPaymentSheet({
  // ...
  applePay: {
    merchantCountryCode: 'US',
  },
});
```

#### 经常性付款

调用 `initPaymentSheet` 时，传入一个 [ApplePayParams](https://stripe.dev/stripe-react-native/api-reference/modules/PaymentSheet.html#ApplePayParams)，将 `merchantCountryCode` 设置为您的业务所在国家/地区的代码。

根据[Apple 的指南](https://developer.apple.com/design/human-interface-guidelines/apple-pay#Supporting-subscriptions)中关于经常性付款的规定，您还必须设置一个 `cardItems`，其中包含一个 [RecurringCartSummaryItem](https://stripe.dev/stripe-react-native/api-reference/modules/ApplePay.html#RecurringCartSummaryItem)，并注明您打算收取的金额（例如，“每月 59.95 美元”）。

还可以通过在将 `request` 的 `type` 设置为 `PaymentRequestType.Recurring` 来采用[商家令牌](https://developer.apple.com/apple-pay/merchant-tokens/)。

要了解有关如何通过 Apple Pay 使用经常性付款的更多信息，请参阅 [Apple 的 PassKit 文档](https://developer.apple.com/documentation/passkit/pkpaymentrequest)。

#### iOS (React Native)

```javascript
const initializePaymentSheet = async () => {
  const recurringSummaryItem = {
    label: 'My Subscription',
    amount: '59.99',
    paymentType: 'Recurring',
    intervalCount: 1,
    intervalUnit: 'month',
    // Payment starts today
    startDate: new Date().getTime() / 1000,

    // Payment ends in one year
    endDate: new Date().getTime() / 1000 + 60 * 60 * 24 * 365,
  };

  const {error} = await initPaymentSheet({
    // ...
    applePay: {
      merchantCountryCode: 'US',
      cartItems: [recurringSummaryItem],
      request: {
        type: PaymentRequestType.Recurring,
        description: 'Recurring',
        managementUrl: 'https://my-backend.example.com/customer-portal',
        billing: recurringSummaryItem,
        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.'",
      },
    },
  });
};
```

### 订单跟踪

在 iOS 16 或更高版本中添加[订单跟踪](https://developer.apple.com/design/human-interface-guidelines/technologies/wallet/designing-order-tracking)信息时，请配置一个 `setOrderTracking` 回调函数。Stripe 会在支付完成后调用您实施的程序，但该操作在 iOS 关闭 Apple Pay 表单之前进行。

在您实施的 `setOrderTracking` 回调函数的程序中，从您的服务器获取已完成订单的订单详情，并将该详情传递给提供的 `completion` 函数。

要了解有关订单跟踪的更多信息，请参阅 [Apple 钱包订单文档](https://developer.apple.com/documentation/walletorders)。

#### iOS (React Native)

```javascript
await initPaymentSheet({
  // ...
  applePay: {
    // ...
    setOrderTracking: async complete => {
      const apiEndpoint =
        Platform.OS === 'ios'
          ? 'http://localhost:4242'
          : 'http://10.0.2.2:4567';
      const response = await fetch(
        `${apiEndpoint}/retrieve-order?orderId=${orderId}`,
        {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
          },
        },
      );
      if (response.status === 200) {
        const orderDetails = await response.json();
        // orderDetails should include orderIdentifier, orderTypeIdentifier,
        // authenticationToken and webServiceUrl
        complete(orderDetails);
      }
    },
  },
});
```

## Optional: 启用 Google Pay

### 设置您的集成

要使用 Google Pay，先将以下内容添加到您的 **AndroidManifest.xml** 的 `<application>`标签，来启用 Google Pay API：

```xml
<application>
  ...
  <meta-data
    android:name="com.google.android.gms.wallet.api.enabled"
    android:value="true" />
</application>
```

更多详情，请参见 Google Pay 针对 Android 设备编写的[设置 Google Pay API](https://developers.google.com/pay/api/android/guides/setup) 指南。

### 添加 Google Pay

初始化 `PaymentSheet` 时，将 `merchantCountryCode` 设置为您的业务所在的国家/地区的代码 并将 `googlePay` 设置为 true。

您还可以通过传递 `testEnv` 参数来使用测试环境。您只能在实物 Android 设备上测试 Google Pay。遵循 [React Native 文档](https://reactnative.dev/docs/running-on-device)中的说明，在真实设备上测试您的应用。

```javascript
const { error, paymentOption } = await initPaymentSheet({
  // ...
  googlePay: {
    merchantCountryCode: 'US',
    testEnv: true, // use test environment
  },
});
```

## 启用银行卡扫描 [客户端]

> Apple iOS 应用程序审核流程要求启用卡片扫描功能。Android 应用程序审核流程不要求启用卡片扫描功能，但我们建议启用。

### iOS

若要在 iOS 上启用卡片扫描支持，请在应用程序的 `Info.plist` 中设置 `NSCameraUsageDescription`（**隐私 - 相机使用说明**），并提供访问相机的原因（例如，“用于扫描卡片”）。

### (Optional) Android

若要启用银行卡扫描支持，需在 [Google Pay & Wallet Console](https://pay.google.com/business/console?utm_source=devsite&utm_medium=devsite&utm_campaign=devsite) 中请求 Google Pay API 的[生产访问权限](https://developers.google.com/pay/api/android/guides/test-and-deploy/request-prod-access)。

- 如果您已启用 Google Pay，银行卡扫描功能会在符合条件的设备上自动在我们的用户界面中提供。想了解更多符合条件的设备，请参见[Google Pay API 限制](https://developers.google.com/pay/payment-card-recognition/debit-credit-card-recognition)
- **重要提示：**银行卡扫描功能仅在与 [Google Pay & Wallet Console](https://pay.google.com/business/console) 中注册的签名密钥相同的构建中显示。使用不同签名密钥进行测试或调试的构建（例如通过Firebase App Tester 分发的构建）不会显示**扫描银行卡**选项。要在预发布构建中测试银行卡扫描功能，您必须采取以下措施之一：
  - 使用生产签名密钥对您的测试构建进行签名
  - 将您的测试签名密钥指纹添加到 Google Pay & Wallet Console

## Optional: 自定义表单 [客户端]

所有自定义操作均用 `initPaymentSheet` 来配置。

### 外观

通过使用[外观 API](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=react-native)，自定义颜色、字体等样式，以匹配您应用的外观和风格。

### 商家显示名称

通过设置 `merchantDisplayName` 来指定向客户显示的商业名称。默认情况下，使用的是您的应用的名称。

```javascript
await initPaymentSheet({
  // ...
  merchantDisplayName: 'Example Inc.',
});
```

### 暗色模式

默认情况下，`PaymentSheet` 自动适应用户的整个系统的外观设置（明暗模式）。您可以通过在 iOS 上将 `style` 属性设置为 `alwaysLight` 或 `alwaysDark` 来更改。

```javascript
await initPaymentSheet({
  // ...
  style: 'alwaysDark',
});
```

在您 Android 应用上，设置亮色或暗色模式：

```
// force dark
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
// force light
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
```

### 默认账单详情

要为 PaymentSheet 中收集的账单详情设置默认值，请配置 `defaultBillingDetails` 属性。`PaymentSheet` 会用您提供的值预先填充其字段。

```javascript
await initPaymentSheet({
  // ...
  defaultBillingDetails: {
      email: 'foo@bar.com',
      address: {
        country: 'US',
      },
  },
});
```

### 收集账单详情

用 `billingDetailsCollectionConfiguration` 指定您希望如何在 PaymentSheet 中收集账单详情。

可以收集客户的姓名、邮件地址、电话号码和地址。

如果您不打算收集支付方式需要的值，则必须进行以下操作：

1. 将 `PaymentSheet` 未收集的值附到 `defaultBillingDetails` 属性。
1. 将 `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` 设置为 `true`。

```javascript
await initPaymentSheet({
  // ...
  defaultBillingDetails: {
    email: 'foo@bar.com',
  },
  billingDetailsCollectionConfiguration: {
    name: PaymentSheet.CollectionMode.ALWAYS,
    email: PaymentSheet.CollectionMode.NEVER,
    address: PaymentSheet.AddressCollectionMode.FULL,
    attachDefaultsToPaymentMethod: true
  },
});
```

> 请咨询律师，了解与收集信息有关的法律。仅在需要收集号码来完成交易时，才收集手机号码。

## Optional: 在您的用户界面完成付款

您可以在出示支付表单时仅收集支付方式详情，然后再在您的应用的用户界面上调用 `confirm` 方法来完成付款。如果您使用自定义购买按钮，或在收集了付款详情后需要额外的步骤，这会非常有用。
![](https://b.stripecdn.com/docs-statics-srv/assets/react-native-multi-step.84d8a0a44b1baa596bda491322b6d9fd.png)

> [可在我们的 GitHub](https://github.com/stripe/stripe-react-native/blob/master/example/src/screens/PaymentsUICustomScreen.tsx) 上查看示例集成。

1. 首先，调用 `initPaymentSheet` 并传递 `customFlow: true`。`initPaymentSheet` 通过一个初始支付选项解析，该选项包含显示客户的支付方式的图片和标签。用这些详情更新您的用户界面。

```javascript
const {
  initPaymentSheet,
  presentPaymentSheet,
  confirmPaymentSheetPayment,
} = useStripe()

const { error, paymentOption } = await initPaymentSheet({
  customerId: customer,
  customerEphemeralKeySecret: ephemeralKey,
  paymentIntentClientSecret: paymentIntent,
  customFlow: true,
  merchantDisplayName: 'Example Inc.',
});
// Update your UI with paymentOption
```

1. 用 `presentPaymentSheet` 收集支付详情。客户完成后，表单自行关闭，并解析 promise。用选择的支付方式详情更新您的用户界面。

```javascript
const { error, paymentOption } = await presentPaymentSheet();
```

1. 用 `confirmPaymentSheetPayment` 确认付款。这会通付款结果来解析。

```javascript
const { error } = await confirmPaymentSheetPayment();

if (error) {
  Alert.alert(`Error code: ${error.code}`, error.message);
} else {
  Alert.alert(
    'Success',
    'Your order is confirmed!'
  );
}
```

将 `allowsDelayedPaymentMethods` 设置为 true，以允许[延迟通知型](https://docs.stripe.com/payments/payment-methods.md#payment-notification)支付方式，例如美国银行账户。对于这些支付方式，只有当 `PaymentSheet` 完成后才能知道最终的付款状态是成功还是失败。如果您支持这些类型的支付方式，请告知客户他们的订单已被确认，并且仅在付款成功时履行订单（例如，为他们安排发货）。

