Stripe Payment API 与 Jetpack Compose 集成

2023-12-07

我不明白如何将 Stripe API 集成到 Compose 应用程序中

这是 Stripe 提供的代码片段

    class CheckoutActivity : AppCompatActivity() {
  lateinit var paymentSheet: PaymentSheet

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    paymentSheet = PaymentSheet(this, ::onPaymentSheetResult)
  }

  fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {
    // implemented in the next steps
  }
}

就我而言,我不知道该放在哪里paymentSheet = PaymentSheet(this,::onPaymentSheetResult)在撰写代码中,它表明:不能使用提供的参数调用以下函数.

(ComponentActivity, PaymentSheetResultCallback) 在 com.stripe.android. paymentsheet.PaymentSheet 中定义

(Fragment, PaymentSheetResultCallback) 在 com.stripe.android. paymentsheet.PaymentSheet 中定义

class MainActivity : ComponentActivity() {
    lateinit var paymentSheet: PaymentSheet
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            PayTheme {
                LoginUi()
            }
        }

        fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {
            // implemented in the next steps
        }
    }
}

首先,你可以在github上查看stripe compose示例stripe-android (ComposeExampleActivity.kt).

添加条带依赖

implementation "com.stripe:stripe-android:20.17.0"

初始化条带PaymentConfiguration在应用程序类中

@HiltAndroidApp
class BookstoreApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        PaymentConfiguration.init(applicationContext, BuildConfig.STRIPE_PUBLISHABLE_KEY)
    }
}

Stripe 提供了多种在应用程序中实现支付的方式。让我们考虑使用付款确认PaymentSheetContract and PaymentLauncher.

示例#1:使用确认付款PaymentSheetContract

In this case, we should use rememberLauncherForActivityResult() with PaymentSheetContract() to launch stripe payment form.

PaymentScreen.kt (Compose)

@Composable
fun PaymentScreen(
    viewModel: PaymentViewModel = hiltViewModel()
) {
    val stripeLauncher = rememberLauncherForActivityResult(
        contract = PaymentSheetContract(),
        onResult = {
            viewModel.handlePaymentResult(it)
        }
    )
    val clientSecret by viewModel.clientSecret.collectAsStateWithLifecycle()
    clientSecret?.let {
        val args = PaymentSheetContract.Args.createPaymentIntentArgs(it)
        stripeLauncher.launch(args)
        viewModel.onPaymentLaunched()
    }
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Button(
            onClick = {
                viewModel.makePayment()
            }
        ) {
            Text(text = "Confirm payment")
        }
    }
}

PaymentViewModel.kt

@HiltViewModel
class PaymentViewModel @Inject constructor(
    private val repository: PaymentRepository
) : ViewModel() {
    private val _clientSecret = MutableStateFlow<String?>(null)
    val clientSecret = _clientSecret.asStateFlow()

    fun makePayment() {
        val paymentIntent = repository.createPaymentIntent()
        _clientSecret.update { paymentIntent.clientSecret }
    }

    fun onPaymentLaunched() {
        _clientSecret.update { null }
    }

    fun handlePaymentResult(result: PaymentSheetResult) {
        when(result) {
            PaymentSheetResult.Canceled -> TODO()
            PaymentSheetResult.Completed -> TODO()
            is PaymentSheetResult.Failed -> TODO()
        }
    }
}

示例#2:使用确认付款PaymentLauncher

In this case, we should use rememberLauncherForActivityResult() with PaymentSheetContract() to launch stripe payment form.

PaymentScreen.kt (Compose)

@Composable
fun PaymentScreen(
    viewModel: PaymentViewModel = hiltViewModel()
) {
    val paymentLauncher = rememberPaymentLauncher(viewModel::handlePaymentResult)
    val confirmPaymentParams by viewModel.confirmPaymentParams.collectAsStateWithLifecycle()
    confirmPaymentParams?.let { payment ->
        paymentLauncher.confirm(payment)
        viewModel.onPaymentLaunched()
    }
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Button(
            onClick = {
                viewModel.makePayment()
            }
        ) {
            Text(text = "Confirm payment")
        }
    }
}

@Composable
fun rememberPaymentLauncher(
    callback: PaymentLauncher.PaymentResultCallback
): PaymentLauncher {
    val config = PaymentConfiguration.getInstance(LocalContext.current)
    return PaymentLauncher.rememberLauncher(
        publishableKey = config.publishableKey,
        stripeAccountId = config.stripeAccountId,
        callback = callback
    )
}

PaymentViewModel.kt

@HiltViewModel
class PaymentViewModel @Inject constructor(
    private val repository: PaymentRepository
) : ViewModel() {
    private val _confirmPaymentParams = MutableStateFlow<ConfirmPaymentIntentParams?>(null)
    val confirmPaymentParams = _confirmPaymentParams.asStateFlow()

    fun makePayment() {
        val paymentIntent = repository.createPaymentIntent()
        // For example, pay with hardcoded test card
        val configuration = ConfirmPaymentIntentParams.createWithPaymentMethodCreateParams(
            paymentMethodCreateParams = PaymentMethodCreateParams.create(
                card = PaymentMethodCreateParams.Card(
                    number = "4242424242424242",
                    expiryMonth = 1,
                    expiryYear = 24,
                    cvc = "111"
                )
            ),
            clientSecret = paymentIntent.clientSecret
        )
        _confirmPaymentParams.update { configuration }
    }

    fun onPaymentLaunched() {
        _confirmPaymentParams.update { null }
    }

    fun handlePaymentResult(result: PaymentResult) {
        when(result) {
            PaymentResult.Canceled -> TODO()
            PaymentResult.Completed -> TODO()
            is PaymentResult.Failed -> TODO()
        }
    }
}

数据层

The functions described below should be implemented somewhere on the server side. So, the client should only request some data from payment intent (client_secret for example).

请阅读条纹接受付款文档以更好地理解。
您还可以观看 YouTube 视频:如何在 Android Studio 2022 中集成 Stripe.

PaymentRepository.kt

class PaymentRepository @Inject constructor(
    private val stripeApiService: StripeApiService,
    private val paymentDao: PaymentDao
) {
    /*
        Create customer before payment (attach to app user)
     */
    suspend fun createCustomer() = withContext(Dispatchers.IO) {
        val customer = stripeApiService.createCustomer()
        // save customer in the database or preferences
        // customerId required to confirm payment
        paymentDao.insertCustomer(customer)
    }

    suspend fun refreshCustomerEphemeralKey() = withContext(Dispatchers.IO) {
        val customer = paymentDao.getCustomer()
        val key = stripeApiService.createEphemeralKey(customer.customerId)
        paymentDao.insertEphemeralKey(key)
    }

    suspend fun createPaymentIntent() = withContext(Dispatchers.IO) {
        val customer = paymentDao.getCustomer()
        refreshCustomerEphemeralKey()
        val paymentIntent = stripeApiService.createPaymentIntent(
            customerId = customer.customerId,
            amount = 1000,
            currency = "usd", // or your currency
            autoPaymentMethodsEnable = true
        )
        return@withContext paymentIntent
    }
}

StripeApiService.kt

private const val SECRET = BuildConfig.STRIPE_SECRET_KEY

interface StripeApiService {

    @Headers(
        "Authorization: Bearer $SECRET",
        "Stripe-Version: 2022-08-01"
    )
    @POST("v1/customers")
    suspend fun createCustomer() : CustomerApiModel

    @Headers(
        "Authorization: Bearer $SECRET",
        "Stripe-Version: 2022-08-01"
    )
    @POST("v1/ephemeral_keys")
    suspend fun createEphemeralKey(
        @Query("customer") customerId: String
    ): EphemeralKeyApiModel

    @Headers(
        "Authorization: Bearer $SECRET"
    )
    @POST("v1/payment_intents")
    suspend fun createPaymentIntent(
        @Query("customer") customerId: String,
        @Query("amount") amount: Int,
        @Query("currency") currency: String,
        @Query("automatic_payment_methods[enabled]") autoPaymentMethodsEnable: Boolean,
    ): PaymentIntentApiModel

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Stripe Payment API 与 Jetpack Compose 集成 的相关文章

随机推荐

  • Git post-receive 挂钩不会从 master 中删除已删除的文件

    我在我的服务器上创建了一个裸 git 存储库 并设置了以下 post receive 挂钩这个博客 bin bash while read oldrev newrev ref do branch echo ref cut d f3 if m
  • 如何在 Perl 中进行自省?

    在 Perl OOP 中 如何转储此类及其父类中的所有方法 字段 my self 我看到了很多上面的构造函数 那么 什么是 我有 Java OOP 背景 如果你的解释能够遵循Java领域 我会更容易理解 What is See perldo
  • 不在 gridview 中显示日期时间最小值

    given public class Customer public int Id get set public string FirstName get set public DateTime Birthdate get set 我有一个
  • 使用reducebykey时出错:int对象不可订阅

    我收到错误 int 对象不可订阅 执行以下脚本时 element reduceByKey lambda x y x 1 y 1 with element 是一个键值 RDD value 是一个元组 输入示例 A toto 10 A titi
  • 如何为 iPhone 设置视口元以正确处理旋转?

    所以我一直在使用 让我的 HTML 内容在 iPhone 上完美显示 它工作得很好 直到用户 将设备旋转到横向模式 其中显示仍限制为 320 像素 有没有一种简单的方法来指定一个视口 该视口会随着用户更改而变化 设备方向 或者我必须求助于
  • 对于终端应用程序来说,什么是好的 Java 类诅咒库? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 我想编写一个进行屏幕操作的 Java 终端应用程序 是否有任何好的库可以让您像 nix C 世界中的诅咒一样操作屏幕 我正在寻找的最小功能是窗口和用
  • 对多个任意过滤条件使用 tidy eval

    我想用整齐的评价编写多个完全灵活的过滤条件 一个相关但不太复杂的问题已解决在这个 Stackoverflow 问题中 以下代码 改编自上述其他问题 正在运行 它将两个过滤条件应用于gapminder数据集 并返回过滤后的数据 library
  • GAE 通过 app.yaml、python 装饰器或 users.get_current_user 强制登录?

    我在 GAE 应用程序的 app yaml 配置文件中使用 登录 选项 看起来像这样 url admin script myapp app login admin url script myapp app login required 更新
  • Pandas 用最后一个已知值填充空尾随值

    我有几个具有不同结束时间段的专栏 需要用最后一个已知值填充空数据 有没有一种 Pandas 方法可以做到这一点 而无需在结束日期上循环 我需要过去 4 个月的 Gain sum y 等于 57129 0 gain sum x gain su
  • JSF - @PostConstruct 可以使用 ajax 调用来阻止 setter 方法吗?

    我想这个问题从标题就已经很清楚了 这是我真正的豆子 ManagedBean name selector RequestScoped public class Selector private String profilePage PostC
  • “静态只读”与“常量”

    我读过有关const and static readonly字段 我们有一些只包含常量值的类 它们用于我们系统中的各种事物 所以我想知道我的观察是否正确 这些常数值是否应该始终是static readonly对于所有公开的事情 并且只使用c
  • 将选项卡名称和 ConqueShell 与 Vim 会话一起保存

    有没有办法让 vim 保存选项卡名称 通过分配选项卡名称脚本 和 或终端仿真器 通过设置康克外壳脚本 发出后 mksession fileName 命令 观察下面 放大 我在左侧有一个工作会话 并且通过vim S fileName命令 在右
  • Spark.sql.shuffle.partitions 到底指什么?

    到底是做什么的spark sql shuffle partitions参考 我们谈论的是宽变换结果的分区数量 还是中间发生的事情 例如宽变换结果分区之前的某种中间分区 因为根据我的理解 根据广泛的转变 我们有 Parents RDDs gt
  • 无法推导出模板参数(向量、std::function)

    我创建了一个模板化函数 我试图自动推导模板参数 MCVE 编译它 template
  • 当隔离被杀死时,颤振隔离内的计时器不会停止

    我有一个应用程序使用 API 调用将操纵杆位置数据上传到网络服务器 当操纵杆移动时会调用此方法 如果操纵杆不在中心 它将停止任何先前运行的隔离并启动新的隔离 void onJoystickMoved double angle double
  • 在 FormFlows - Bot Framework 中添加另一个 Quit 关键字

    是否可以使用 Bot Framework 更改 FormDialog 中退出突击队的关键字 我想在键入某个单词时抛出 FormCanceledException 不使用英语作为语言 如果我可以更改关键字 或者添加另一个与退出相同的关键字 那
  • 安卓图像按钮

    如何创建一个没有文本且图像水平居中的按钮 我不想使用图像按钮 因为我想定义不同的背景图像 您只需使用 ImageButton 并将背景设置为您想要的任何内容并将图标设置为 src
  • Tinder 像泛 iOS

    对于 iOS 中的 Tinder 应用程序 我假设他们在图像视图上使用平移手势识别器 为什么用户开始移动的图像下方会显示另一张图像 他们是否有另一个图像视图 并且在手势识别器完成后 动态设置图像视图手势识别器 最后在下面创建另一个图像视图
  • 使用自定义名称创建 Python 动态函数

    如果这个问题已经提出并得到回答 我们深表歉意 我需要做的概念非常简单 但不幸的是我无法在网上找到答案 我需要在运行时使用自定义名称在 Python Python2 7 中创建动态函数 每个函数的主体也需要在运行时构造 但对于所有函数来说 几
  • Stripe Payment API 与 Jetpack Compose 集成

    我不明白如何将 Stripe API 集成到 Compose 应用程序中 这是 Stripe 提供的代码片段 class CheckoutActivity AppCompatActivity lateinit var paymentShee