# Manage payment methods in settings Use the Payment Method Settings Sheet to let your customers manage their payment methods in your app settings page. > The Payment Method Settings Sheet is intended for use on an app settings page. For checkout and payments, use the [In-app Payments](https://docs.stripe.com/payments/mobile.md), which also has built-in support for saving and displaying payment methods and supports more payment methods than the Payment Method Settings Sheet. > In code, this component is referenced as `CustomerSheet` for historical reasons. Throughout the documentation, when you see `CustomerSheet` in code examples, this refers to the Payment Method Settings Sheet. The Payment Method Settings Sheet is a prebuilt UI component that lets your customers manage their saved payment methods. You can use the Payment Method Settings Sheet UI outside of a checkout flow, and the appearance and styling is customizable to match the appearance and aesthetic of your app. Customers can add and remove payment methods, which get saved to the customer object, and set their default payment method stored locally on the device. Use both the In-app Payments and the Payment Method Settings Sheet to provide customers a consistent end-to-end solution for saved payment methods. ![Screenshot of Payment Method Settings Sheet presenting multiple saved payment methods in an iOS app.](https://b.stripecdn.com/docs-statics-srv/assets/ios-landing.6c4969968fd6efe3d39fe673628f8284.png) The [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) object grants the SDK temporary access to the Customer and provides additional configuration options. These configuration options allow you to customize the behavior of CustomerSheet. A complete list of features exposed on the CustomerSession are in our [API docs](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components). ## 设置 Stripe 首先,您需要有一个 Stripe 账户。[立即注册](https://dashboard.stripe.com/register)。 [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)。 在应用程序启动时使用您的 Stripe [公钥](https://dashboard.stripe.com/test/apikeys) 配置 SDK。这样可使您的应用程序向 Stripe API 发出请求。 #### Swift ```swift import UIKitimportStripePaymentSheet @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {StripeAPI.defaultPublishableKey = "<>" // do any other necessary launch configuration return true } } ``` > 测试时使用您的[测试密钥](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),启用您想支持的支付方式。您至少需要启用一个支付方式才能在下一步中创建 *SetupIntent* (The Setup Intents API lets you build dynamic flows for collecting payment method details for future payments. It tracks the lifecycle of a payment setup flow and can trigger additional authentication steps if required by law or by the payment method)。 默认情况下,Stripe 支持信用卡和其他常见的支付方式,可以帮助您获得更多客户,但建议您开启与您的业务和客户相关的其他支付方式。查看[支付方式支持](https://docs.stripe.com/payments/payment-methods/payment-method-support.md),了解支持的产品和支付方式,并查看我们的[定价页面](https://stripe.com/pricing/local-payment-methods)了解费用。 > CustomerSheet only supports cards, US bank accounts, and SEPA Direct Debit. ## Add Customer endpoints [服务器端] If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Create two endpoints on your server: one for fetching a CustomerSession client secret, and one to create a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) for saving a new payment method to the [Customer](https://docs.stripe.com/api/customers.md). 1. Create an endpoint to return a [Customer](https://docs.stripe.com/api/customers.md) ID and a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) client secret. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[customer_sheet][enabled]"=true \ -d "components[customer_sheet][features][payment_method_remove]"=enabled ``` > Integrations with legacy customer ephemeral keys results in saved payment methods having an `allow_redisplay` value of `unspecified`. To display these payment methods in addition to payment methods saved while using Customer Sessions, set `payment_method_allow_redisplay_filters` to `["unspecified", "always"]`. For more information, see [CustomerSessions](https://docs.stripe.com/api/customer_sessions.md). 1. Create an endpoint to return a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) configured with the [Customer](https://docs.stripe.com/api/customers.md) ID. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/setup_intents \ -u <>: \ -d "customer"="{{CUSTOMER_ID}}" \ ``` If you only plan to use the payment method for future payments when your customer is present during the checkout flow, set the [usage](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-usage) parameter to *on\_session* (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) to improve authorization rates. ## Configure the sheet Next, configure the Payment Method Settings Sheet using the `CustomerSheet` class with an `IntentConfiguration`, `CustomerSessionClientSecretProvider` and a [CustomerSheet.Configuration](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/customersheet/configuration/). ```swift var configuration = CustomerSheet.Configuration() // Configure settings for the CustomerSheet here. For example: configuration.headerTextForSelectionScreen = "Manage your payment method" let intentConfiguration = CustomerSheet.IntentConfiguration(setupIntentClientSecretProvider: { let json = try await myBackend.createSetupIntent() return json["setupIntentClientSecret"]! }) let customerSheet = CustomerSheet( configuration: configuration, intentConfiguration: intentConfiguration, customerSessionClientSecretProvider: { let json = try await myBackend.createCustomerSessionClientSecret() return .init(customerId: json["customerId"]!, clientSecret: json["customerSessionClientSecret"]!) }) ``` ## Present the sheet #### UIKit Present the Payment Method Settings Sheet using `CustomerSheet`. When the customer dismisses the sheet, the `CustomerSheet` calls the completion block with a `CustomerSheet.SheetResult`. #### iOS (Swift) ```swift import StripePaymentSheet customerSheet.present(from: self, completion: { result in switch result { case .canceled(let paymentOption), .selected(let paymentOption): // Configure your UI based on the payment option self.paymentLabel.text = paymentOption?.displayData().label ?? "None" // Optional: Send the selected payment method ID to your backend for advanced use cases // like charging a customer when not present in your app if let paymentOption = paymentOption { switch paymentOption { case .paymentMethod(let paymentMethod, let paymentOptionDisplayData): MyBackend.setDefaultPaymentMethod(paymentMethod.stripeId) case .applePay(paymentOptionDisplayData: let paymentOptionDisplayData): MyBackend.setDefaultPaymentMethodIsApplePay() } } case .error(let error): // Show the error in your UI } }) ``` - If the customer selects a payment method, the result is `.selected(PaymentOptionSelection?)`. The associated value is the selected [PaymentOptionSelection](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/customersheet/paymentoptionselection), or `nil` if the user deleted the previously-selected payment method. You can find the full payment method details in the PaymentOptionSelection’s `paymentMethod` associated value. - If the user cancels the sheet, the result is `.canceled`. The associated value is the original payment method selected prior to opening the customer sheet, as long as that payment method is still available. - If an error occurs, the result is `.error(Error)`. Learn more about how to [enable Apple Pay](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=mobile&platform=ios#ios-apple-pay). #### SwiftUI Create an `ObservableObject` model for your screen presenting the Payment Method Settings Sheet. This model maintains an instance to the [CustomerSheet](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/customersheet). ```swift import StripePaymentSheet import SwiftUI class YourAccountViewModel: ObservableObject { var customerSheet: CustomerSheet } ``` Use the `.customerSheet` ViewModifier to present the Payment Method Settings Sheet. ```swift struct YourAccountView: View { @State private var showingCustomerSheet = false @ObservedObject var model = YourAccountViewModel() var body: some View { VStack { Button(action: { showingCustomerSheet = true }) { Text("Present Customer Sheet") }.customerSheet( isPresented: $showingCustomerSheet, customerSheet: model.customerSheet, onCompletion: model.onCompletion) } } } ``` Add a `customerSheetResult` to store the result of presenting the Payment Method Settings Sheet in your `ObservableObject`. ```swift class YourAccountViewModel: ObservableObject { var customerSheet: CustomerSheet @Published var customerSheetResult: CustomerSheet.CustomerSheetResult? func onCompletion(result: CustomerSheet.CustomerSheetResult) { self.customerSheetResult = result } } ``` Use the `customerSheetResult` to render the selected payment method in your UI: ```swift struct YourAccountView: View { @State private var showingCustomerSheet = false @ObservedObject var model = MyBackendCustomerSheetModel() var body: some View { VStack { Button(action: { showingCustomerSheet = true }) { Text("Present Customer Sheet") }.customerSheet( isPresented: $showingCustomerSheet, customerSheet: model.customerSheet, onCompletion: model.onCompletion)if let customerSheetResult = model.customerSheetResult { ExampleCustomerSheetPaymentMethodView(customerSheetResult: customerSheetResult) } } } } ``` - If the customer selects a payment method, the result is `.selected(PaymentOptionSelection?)`. The associated value is the selected [PaymentOptionSelection](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/customersheet/paymentoptionselection), or `nil` if the user deleted the previously-selected payment method. You can find the full payment method details in the PaymentOptionSelection’s `paymentMethod` associated value. - If the user cancels the sheet, the result is `.canceled`. The selected payment method didn’t change. - If an error occurs, the result is `.error(Error)`. Learn more about how to [enable Apple Pay](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=mobile&platform=ios#ios-apple-pay). ## Optional: 启用 ACH 付款 To enable ACH debit payments: 1. Include `StripeFinancialConnections` as a dependency for your app. 1. Enable US Bank Account as a payment method in the settings section of the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). ## Optional: Fetch the selected payment method To fetch the default payment method without presenting the Payment Method Settings Sheet, call `retrievePaymentOptionSelection()` on the `CustomerSheet`. ```swift let paymentMethodOption = try await customerSheet.retrievePaymentOptionSelection() // Configure your UI based on the payment option self.paymentLabel.text = paymentMethodOption?.displayData().label ?? "None" // Send the selected payment method ID to your backend switch paymentMethodOption { case .paymentMethod(paymentMethod: let paymentMethod, paymentOptionDisplayData: let paymentOptionDisplayData): try await MyBackend.setDefaultPaymentMethod(paymentMethod.stripeId) case .applePay(paymentOptionDisplayData: let paymentOptionDisplayData): try await MyBackend.setDefaultPaymentMethodIsApplePay() } ``` ## Optional: 自定义表单 ### 外观 Customize the colors, fonts, and other appearance attributes to match the look and feel of your app by using the [appearance API](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=ios). > `fetchPaymentMethods` can filter out saved payment methods from being shown, but won’t impact the type of payment methods that are addable. ### 默认账单详情 To set default values for billing details collected in the payment sheet, configure the `defaultBillingDetails` property. The `CustomerSheet` pre-populates its fields with the values that you provide. ```swift var configuration = CustomerSheet.Configuration() configuration.defaultBillingDetails.address.country = "US" configuration.defaultBillingDetails.email = "foo@bar.com" ``` ### 收集账单详情 用 `billingDetailsCollectionConfiguration` 来指定您希望如何在支付表单中收集账单详情。 可以收集客户的姓名、邮件地址、电话号码和地址。 To attach values that aren’t collected by `CustomerSheet`, add them to the `defaultBillingDetails` property and set `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` to `true`. Make sure that you complete this step if you don’t plan to collect values required by the payment method. ```swift var configuration = CustomerSheet.Configuration() configuration.defaultBillingDetails.email = "foo@bar.com" configuration.billingDetailsCollectionConfiguration.name = .always configuration.billingDetailsCollectionConfiguration.email = .never configuration.billingDetailsCollectionConfiguration.address = .full configuration.billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod = true ``` > Consult with your legal team regarding laws that apply to collecting information. Only collect phone numbers if you need them for the transaction. > The Payment Method Settings Sheet is intended for use on an app settings page. For checkout and payments, use the [In-app Payments](https://docs.stripe.com/payments/mobile.md), which also has built-in support for saving and displaying payment methods and supports more payment methods than the Payment Method Settings Sheet. > In code, this component is referenced as `CustomerSheet` for historical reasons. Throughout the documentation, when you see `CustomerSheet` in code examples, this refers to the Payment Method Settings Sheet. The Payment Method Settings Sheet is a prebuilt UI component that lets your customers manage their saved payment methods. You can use the Payment Method Settings Sheet UI outside of a checkout flow, and the appearance and styling is customizable to match the appearance and aesthetic of your app. Customers can add and remove payment methods, which get saved to the customer object, and set their default payment method stored locally on the device. Use both the In-app Payments and the Payment Method Settings Sheet to provide customers a consistent end-to-end solution for saved payment methods. ![Screenshot of Payment Method Settings Sheet presenting multiple saved payment methods in an Android app.](https://b.stripecdn.com/docs-statics-srv/assets/ios-landing.6c4969968fd6efe3d39fe673628f8284.png) The [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) object grants the SDK temporary access to the Customer and provides additional configuration options. These configuration options allow you to customize the behavior of `CustomerSheet`. A complete list of features exposed on the `CustomerSession` are in our [API docs](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components). ## Set up Stripe First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). 安装 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.2.0") // Include the financial connections SDK to support US bank account as a payment method implementation("com.stripe:financial-connections:23.2.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)。 用您的 Stripe [公钥](https://dashboard.stripe.com/apikeys)配置 SDK,以便它可以向 Stripe API 发送请求,例如在您的 `Application` 子类中: #### Kotlin ```kotlin import com.stripe.android.PaymentConfiguration class MyApp : Application() { override fun onCreate() { super.onCreate() PaymentConfiguration.init( applicationContext, "<>" ) } } ``` > 测试时使用您的[测试密钥](https://docs.stripe.com/keys.md#obtain-api-keys),发布应用时使用[真实模式](https://docs.stripe.com/keys.md#test-live-modes)密钥。 ## Enable payment methods 查看您的[支付方式设置](https://dashboard.stripe.com/settings/payment_methods),启用您想支持的支付方式。您至少需要启用一个支付方式才能在下一步中创建 *SetupIntent* (The Setup Intents API lets you build dynamic flows for collecting payment method details for future payments. It tracks the lifecycle of a payment setup flow and can trigger additional authentication steps if required by law or by the payment method)。 默认情况下,Stripe 支持信用卡和其他常见的支付方式,可以帮助您获得更多客户,但建议您开启与您的业务和客户相关的其他支付方式。查看[支付方式支持](https://docs.stripe.com/payments/payment-methods/payment-method-support.md),了解支持的产品和支付方式,并查看我们的[定价页面](https://stripe.com/pricing/local-payment-methods)了解费用。 > At this time, Payment Method Settings Sheet only supports cards and US bank accounts. ## Add Customer endpoints [Server-side] If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Create two endpoints on your server: one for fetching a CustomerSession client secret, and one to create a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) for saving a new payment method to the [Customer](https://docs.stripe.com/api/customers.md). 1. Create an endpoint to return a [Customer](https://docs.stripe.com/api/customers.md) ID and a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) client secret. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[customer_sheet][enabled]"=true \ -d "components[customer_sheet][features][payment_method_remove]"=enabled ``` > Integrations with legacy customer ephemeral keys results in saved payment methods having an `allow_redisplay` value of `unspecified`. To display these payment methods in addition to payment methods saved while using Customer Sessions, set `payment_method_allow_redisplay_filters` to `["unspecified", "always"]`. For more information, see [CustomerSessions](https://docs.stripe.com/api/customer_sessions.md). 1. Create an endpoint to return a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) configured with the [Customer](https://docs.stripe.com/api/customers.md) ID. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/setup_intents \ -u <>: \ -d "customer"="{{CUSTOMER_ID}}" \ ``` If you only plan to use the payment method for future payments when your customer is present during the checkout flow, set the [usage](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-usage) parameter to *on\_session* (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) to improve authorization rates. ## Create a Customer session provider [Client-side] A `CustomerSessionProvider` enables a `CustomerSheet` to communicate with Stripe using [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) objects. On the client, create a `CustomerSessionProvider` that can create a `CustomerSession` client secret and a `SetupIntent` client secret from your server. ```kotlin import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.ExperimentalCustomerSheetApi @OptIn(ExperimentalCustomerSheetApi::class) class MyCustomerSessionProvider : CustomerSheet.CustomerSessionProvider() { val myBackend = // .... override suspend fun providesCustomerSessionClientSecret(): Result { return myBackend.getCustomerSessionClientSecret().fold( onSuccess = { response -> Result.success( CustomerSessionClientSecret.create( customerId = response.customerId, clientSecret = response.customerSessionClientSecret, ) ) }, onFailure = { exception -> Result.failure(exception) } ) } override suspend fun provideSetupIntentClientSecret(customerId: String): Result { return myBackend.getSetupIntentClientSecret(customerId).fold( onSuccess = { response -> Result.success(response.setupIntentClientSecret) }, onFailure = { exception -> Result.failure(exception) } ) } } ``` ```kotlin import android.app.Application import androidx.lifecycle.AndroidViewModel class CheckoutViewModel( application: Application ) : AndroidViewModel(application) { val customerSessionProvider = MyCustomerSessionProvider() } ``` ## Configure the sheet Next, initialize the Payment Method Settings Sheet using the `CustomerSheet` class with your `CustomerSessionProvider` then call `configure` with a [CustomerSheet.Configuration](https://github.com/stripe/stripe-android/blob/master/paymentsheet/src/main/java/com/stripe/android/customersheet/CustomerSheet.kt). Always call `configure` before calling `present` and `retrievePaymentOptionSelection`. ```kotlin import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModels import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.ExperimentalCustomerSheetApi import com.stripe.android.customersheet.rememberCustomerSheet @OptIn(ExperimentalCustomerSheetApi::class) class CheckoutActivity : ComponentActivity() { private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val configuration = CustomerSheet.Configuration.builder(merchantDisplayName = "{{YOUR BUSINESS NAME}}") .build() setContent { val customerSheet = rememberCustomerSheet( customerSessionProvider = viewModel.customerSessionProvider, callback = viewModel::handleResult // Implemented in next step ) LaunchedEffect(customerSheet) { customerSheet.configure(configuration = configuration) } } } } ``` ## Present the sheet Present the Payment Method Settings Sheet using `CustomerSheet`. When the customer dismisses the sheet, the `CustomerSheet` calls the completion block with a `CustomerSheetResult`. ```kotlin import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModelsimport androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.ExperimentalCustomerSheetApi import com.stripe.android.customersheet.rememberCustomerSheetimport com.stripe.android.uicore.image.rememberDrawablePainter @OptIn(ExperimentalCustomerSheetApi::class) class CheckoutActivity : ComponentActivity() {private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val configuration = CustomerSheet.Configuration.builder(merchantDisplayName = "{{YOUR BUSINESS NAME}}") .headerTextForSelectionScreen("Manage your payment method") .build() setContent { val customerSheet = rememberCustomerSheet( customerSessionProvider = viewModel.customerSessionProvider, callback = viewModel::handleResult ) LaunchedEffect(customerSheet) { customerSheet.configure(configuration = configuration)viewModel.handleResult(customerSheet.retrievePaymentOptionSelection()) }val paymentOption by viewModel.paymentOption.collectAsState() Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, ) { val icon = paymentOption?.icon() if (icon != null) { Image( painter = rememberDrawablePainter( drawable = icon ), contentDescription = "Payment Method Icon", modifier = Modifier.height(32.dp) ) } TextButton( onClick = { customerSheet.present() } ) { Text( text = paymentOption?.label ?: "Select" ) } } } } } ``` ```kotlin import android.app.Application import androidx.lifecycle.AndroidViewModel import com.stripe.android.customersheet.ExperimentalCustomerSheetApiimport com.stripe.android.paymentsheet.model.PaymentOption import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update @OptIn(ExperimentalCustomerSheetApi::class) class CheckoutViewModel( application: Application ) : AndroidViewModel(application) { val customerSessionProvider = // ... private val _paymentOption = MutableStateFlow(null) val paymentOption: StateFlow = _paymentOption fun handleResult(result: CustomerSheetResult) { when (result) { is CustomerSheetResult.Selected -> { // Configure your UI based on the payment option _paymentOption.update { result.selection?.paymentOption } } is CustomerSheetResult.Canceled -> { // Configure your UI based on the payment option _paymentOption.update { result.selection?.paymentOption } } is CustomerSheetResult.Failed -> { // Show the error in your UI } } } } ``` - If the customer selects a payment method, the result is `CustomerSheetResult.Selected`. The associated value is the selected `PaymentOptionSelection`, or null if the user deleted the previously-selected payment method. The full payment method details are available in the `PaymentOptionSelection`’s `paymentMethod` value. - If the customer cancels the sheet, the result is `CustomerSheetResult.Canceled`. The associated value is the customer’s original `PaymentOptionSelection`, or null if the customer hasn’t selected a payment method before or has deleted the originally selected payment method. - If an error occurs, the result is `CustomerSheetResult.Failed`. ## Optional: 启用 Google Pay ### 设置您的集成 要使用 Google Pay,先将以下内容添加到您的 **AndroidManifest.xml** 的 ``标签,来启用 Google Pay API: ```xml ... ``` 更多详情,请参见 Google Pay 针对 Android 设备编写的[设置 Google Pay API](https://developers.google.com/pay/api/android/guides/setup) 指南。 ### 添加 Google Pay To add Google Pay to your integration, pass `true` to [googlePayEnabled](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/google-pay-enabled.html) when initializing [CustomerSheet.Configuration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/index.html) with [CustomerSheet.Configuration.Builder](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html). #### Kotlin ```kotlin val configuration = CustomerSheet.Configuration.Builder() .googlePayEnabled(true) .build() ``` ## Optional: Enable ACH payments 要启用 ACH 借记付款,请将 Financial Connections 作为您的应用的依赖项。 [Stripe Android SDK](https://github.com/stripe/stripe-android) 是开源的,且[有完整的文档](https://stripe.dev/stripe-android/)。 安装 SDK 时,将 `financial-connections` 添加到您的 [app/build.gradle](https://developer.android.com/studio/build/dependencies) 文件的 `dependencies` 块中: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Financial Connections Android SDK implementation("com.stripe:financial-connections:23.2.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)。 ## Optional: Fetch the selected payment method To fetch the default payment method without presenting the Payment Method Settings Sheet, call `retrievePaymentOptionSelection()` on `CustomerSheet`. ```kotlin class CheckoutActivity : ComponentActivity() { private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val configuration = ... setContent { val customerSheet = ... LaunchedEffect(Unit) { customerSheet.configure(configuration = configuration) val result = customerSheet.retrievePaymentOptionSelection() viewModel.handleResult(result) } ... } } } ``` ## Optional: Customize the sheet ### Appearance Customize the colors, fonts, and other appearance attributes to match the look and feel of your app by using the [appearance API](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=android). > `retrievePaymentMethods` can filter out saved payment methods from being shown, but won’t impact the type of payment methods that are addable. ### Default billing details To set default values for billing details collected in the customer sheet, configure the [defaultBillingDetails](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html#-1446247975%2FFunctions%2F2002900378) property. The `CustomerSheet` pre-populates its fields with the values that you provide. ```kotlin val configuration = CustomerSheet.Configuration.Builder() .defaultBillingDetails( PaymentSheet.BillingDetails( address = PaymentSheet.Address( country = "US" ), email = "foo@bar.com" ) ) .build() ``` ### Billing details collection Use [billingDetailsCollectionConfiguration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html#1512634376%2FFunctions%2F2002900378) to specify how you want to collect billing details in the payment sheet. You can collect your customer’s name, email, phone number, and address. To attach values that aren’t collected by `CustomerSheet`, add them to the [defaultBillingDetails](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html#-1446247975%2FFunctions%2F2002900378) property and set `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` to `true`. Make sure that you complete this step if you don’t plan to collect values required by the payment method. ```kotlin val configuration = CustomerSheet.Configuration.Builder() .defaultBillingDetails( PaymentSheet.BillingDetails( email = "foo@bar.com" ) ) .billingDetailsCollectionConfiguration( PaymentSheet.BillingDetailsCollectionConfiguration( name = PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Always, email = PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Never, address = PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Full, attachDefaultsToPaymentMethod = true, ) ) .build() ``` > Consult with your legal team regarding laws that apply to you collecting information. Only collect phone numbers if you need them for the transaction. > The Payment Method Settings Sheet is intended for use on an app settings page. For checkout and payments, use the [In-app Payments](https://docs.stripe.com/payments/mobile.md), which also has built-in support for saving and displaying payment methods and supports more payment methods than the Payment Method Settings Sheet. > In code, this component is referenced as `CustomerSheet` for historical reasons. Throughout the documentation, when you see `CustomerSheet` in code examples, this refers to the Payment Method Settings Sheet. The Payment Method Settings Sheet is a prebuilt UI component that lets your customers manage their saved payment methods. You can use the Payment Method Settings Sheet UI outside of a checkout flow, and the appearance and styling is customizable to match the appearance and aesthetic of your app. Customers can add and remove payment methods, which get saved to the customer object, and set their default payment method stored locally on the device. Use both the In-app Payments and the Payment Method Settings Sheet to provide customers a consistent end-to-end solution for saved payment methods. ![Screenshot of Payment Method Settings Sheet presenting multiple saved payment methods in an iOS app.](https://b.stripecdn.com/docs-statics-srv/assets/ios-landing.6c4969968fd6efe3d39fe673628f8284.png) ## 设置 Stripe 首先,您需要一个 Stripe 账户。[立即注册](https://dashboard.stripe.com/register)。 [React Native SDK](https://github.com/stripe/stripe-react-native) 是开源的,有完整的文档。在内部,它利用的是[原生 iOS](https://github.com/stripe/stripe-ios) 和 [Android](https://github.com/stripe/stripe-android) SDK。要安装 Stripe 的 React Native SDK,在您的项目目录中运行以下某个指令(取决于您使用的软件包管理器)。 #### yarn ```bash yarn add @stripe/stripe-react-native ``` #### npm ```bash npm install @stripe/stripe-react-native ``` 然后,安装一些其他必要的依赖项: - 对于 iOS,请转到 **ios** 目录并运行 `pod install` 以确保同时安装了所需的本地依赖项。 - 对于 Android,无需安装其他依赖项。 > 建议按照[官方 TypeScript 指南](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project)添加 TypeScript 支持。 ### Stripe 初始化 要在您的 React Native 应用中初始化 Stripe,使用 `StripeProvider` 组件包裹您的支付界面,或者使用 `initStripe` 初始化方法。只需要 `publishableKey` 中的 API [公钥](https://docs.stripe.com/keys.md#obtain-api-keys)。下例显示的是用 `StripeProvider` 组件初始化 Stripe 的方式。 ```jsx import { useState, useEffect } from 'react'; import { StripeProvider } from '@stripe/stripe-react-native'; function App() { const [publishableKey, setPublishableKey] = useState(''); const fetchPublishableKey = async () => { const key = await fetchKey(); // fetch key from your server here setPublishableKey(key); }; useEffect(() => { fetchPublishableKey(); }, []); return ( {/* Your app code here */} ); } ``` > 测试与开发时使用 API [测试模式](https://docs.stripe.com/keys.md#obtain-api-keys),发布时使用[真实模式](https://docs.stripe.com/keys.md#test-live-modes)密钥。 ## 启用支付方式 查看您的[支付方式设置](https://dashboard.stripe.com/settings/payment_methods),启用您想支持的支付方式。您至少需要启用一个支付方式才能在下一步中创建 *SetupIntent* (The Setup Intents API lets you build dynamic flows for collecting payment method details for future payments. It tracks the lifecycle of a payment setup flow and can trigger additional authentication steps if required by law or by the payment method)。 默认情况下,Stripe 支持信用卡和其他常见的支付方式,可以帮助您获得更多客户,但建议您开启与您的业务和客户相关的其他支付方式。查看[支付方式支持](https://docs.stripe.com/payments/payment-methods/payment-method-support.md),了解支持的产品和支付方式,并查看我们的[定价页面](https://stripe.com/pricing/local-payment-methods)了解费用。 > CustomerSheet only supports cards and US bank accounts. ## Add Customer endpoints [服务器端] If your integration uses [customer-configured Accounts](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), replace `Customer` and event references in the code examples with the equivalent Accounts v2 API references. For more information, see [Represent customers with Account objects](https://docs.stripe.com/connect/use-accounts-as-customers.md). Create two endpoints on your server: one for fetching a CustomerSession client secret, and one to create a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) for saving a new payment method to the [Customer](https://docs.stripe.com/api/customers.md). 1. Create an endpoint to return a [Customer](https://docs.stripe.com/api/customers.md) ID and a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) client secret. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[customer_sheet][enabled]"=true \ -d "components[customer_sheet][features][payment_method_remove]"=enabled ``` > Integrations with legacy customer ephemeral keys results in saved payment methods having an `allow_redisplay` value of `unspecified`. To display these payment methods in addition to payment methods saved while using Customer Sessions, set `payment_method_allow_redisplay_filters` to `["unspecified", "always"]`. For more information, see [CustomerSessions](https://docs.stripe.com/api/customer_sessions.md). 1. Create an endpoint to return a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) configured with the [Customer](https://docs.stripe.com/api/customers.md) ID. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/setup_intents \ -u <>: \ -d "customer"="{{CUSTOMER_ID}}" \ ``` If you only plan to use the payment method for future payments when your customer is present during the checkout flow, set the [usage](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-usage) parameter to *on\_session* (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) to improve authorization rates. ## Initialize the sheet Create a `ClientSecretProvider` object that implements two methods. `CustomerSheet` needs it to communicate with Stripe using `CustomerSession` objects and the endpoints you created earlier. ```jsx import {ClientSecretProvider, CustomerSessionClientSecret} from '@stripe/stripe-react-native'; const clientSecretProvider: ClientSecretProvider = { // Must return an object with customerId and clientSecret async provideCustomerSessionClientSecret(): Promise { const result = await MyBackend.createCustomerSession(); return { customerId: result.customer, clientSecret: result.customerSessionClientSecret, }; }, // Must return a string async provideSetupIntentClientSecret(): Promise { const result = await MyBackend.createSetupIntent(); return result.setupIntent; } }; ``` Next, configure the Payment Method Settings Sheet using the `CustomerSheet` class, by providing your desired settings to `CustomerSheet.initialize`. ```jsx import {CustomerSheet} from '@stripe/stripe-react-native'; const {error} = await CustomerSheet.initialize({ // You must provide intentConfiguration and clientSecretProvider intentConfiguration: { paymentMethodTypes: ['card'], }, clientSecretProvider: clientSecretProvider, headerTextForSelectionScreen: 'Manage your payment method', returnURL: 'my-return-url://', }); ``` ## Present the sheet #### 功能性 Cookie Present the Payment Method Settings Sheet using `CustomerSheet`. When the customer dismisses the sheet, the promise resolves with a `CustomerSheetResult`. #### Using functions directly ```jsx import {CustomerSheet} from '@stripe/stripe-react-native'; const {error, paymentOption, paymentMethod} = await CustomerSheet.present(); if (error) { if (error.code === CustomerSheetError.Canceled) { // Customer dismissed the sheet without changing their payment option } else { // Show the error in your UI } } else { if (paymentOption) { // Configure your UI based on the payment option MyBackend.setDefaultPaymentMethod(paymentMethod.id); } if (paymentMethod) { console.log(JSON.stringify(paymentMethod, null, 2)); } } ``` - If the customer selects a payment method, the result contains a `paymentOption`. The associated value is the selected [PaymentOption](https://stripe.dev/stripe-react-native/api-reference/interfaces/PaymentSheet.PaymentOption.html), or `nil` if the user deleted the previously-selected payment method. You can find the full payment method details in the `paymentMethod` field. - If the user cancels the sheet, the result contains an `error` with the `error.code === CustomerSheetError.Canceled`. The selected payment method doesn’t change. - If an error occurs, the details are included in `error`. Learn more about how to [enable Apple Pay](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=mobile&platform=ios#ios-apple-pay). #### Component Create a state variable to control presentation of the Payment Method Settings Sheet (`CustomerSheet`). ```jsx import {CustomerSheet, ClientSecretProvider, CustomerSessionClientSecret} from '@stripe/stripe-react-native'; export default function MyScreen() { const [customerSheetVisible, setCustomerSheetVisible] = React.useState(false); const clientSecretProvider: ClientSecretProvider = { async provideCustomerSessionClientSecret(): Promise { const result = await MyBackend.createCustomerSession(); return { customerId: result.customer, clientSecret: result.customerSessionClientSecret, }; }, async provideSetupIntentClientSecret(): Promise { const result = await MyBackend.createSetupIntent(); return result.setupIntent; } }; return (