Stripe Payment API integration to Jetpack Compose



我不知道如何将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,:: onpaymentsheeresult)在compose代码中,如下所示:下列函数都不能用提供的参数调用。

(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-android (ComposeExampleActivity.kt)上的stripe-android样本

添加条带依赖

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

在Application类中初始化条带PaymentConfiguration

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

Stripe在应用中提供了许多实现支付的方法。让我们考虑使用PaymentSheetContractPaymentLauncher进行支付确认。

示例#1:使用PaymentSheetContract确认付款在本例中,我们应该使用rememberLauncherForActivityResult()PaymentSheetContract()来启动分条支付表单。

PaymentScreen。kt(组合)

@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确认付款在本例中,我们应该使用rememberLauncherForActivityResult()PaymentSheetContract()来启动分条支付表单。

PaymentScreen。kt(组合)

@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()
}
}
}
数据层

下面描述的函数应该在服务器端的某个地方实现。因此,客户端应该只从支付意图请求一些数据(例如client_secret

)。请阅读条纹接受支付文件更好地理解。
你也可以观看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
}

我发现设置Android Activity并从可组合函数启动是一种简单有效的解决方案,适用于许多类型的第三方库来启动工作表或菜单。我让它工作的步骤是创建一个StripePaymentSheetActivity文件。kt与

class StripePaymentSheetActivity(): ComponentActivity() {
lateinit var paymentSheet: PaymentSheet
lateinit var customerConfig: PaymentSheet.CustomerConfiguration
lateinit var paymentSetupIntentClientSecret: String
lateinit var paymentIntentClientSecret: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
paymentSheet = PaymentSheet(this, ::onPaymentSheetResult)
// you can retrieve strings from jetpack compose with putExtra
val customerId = getIntent().getStringExtra("customerId")
// you need to make a server call here to get your clientSecret
// and ephemeralKey here
resp = YourServerRequestToGetClientSecretAndEpheralKeyHere()
// secret will be in the form seti_*****
paymentSetupIntentClientSecret = resp.clientSecret
// Switch for making a payment and will be in the form pi_****
// paymentIntentClientSecret = resp.clientSecret
customerConfig = PaymentSheet.CustomerConfiguration(
id = customerId,
ephemeralKeySecret = resp.ephemeralKey,
)
// publishableKey is your pk_test or pk_live key you find on stripe
PaymentConfiguration.init(this, publishableKey)
// this where it is a little different from the stipe documentation.
// This method onCreate will be hit once we launch the activity but 
// there is no way to call a function after launching an activity
// in compose so we will just do it when this is activity is created.
presentPaymentSheet()
}
fun onPaymentSheetResult(paymentSheetResult: PaymentSheetResult) {
Log.d("PaymentSheet", "PaymentSheet result: $paymentSheetResult")
when(paymentSheetResult) {
is PaymentSheetResult.Canceled -> {
// this registers the callback into the compose function
setResult(RESULT_CANCELED)
finish()
}
is PaymentSheetResult.Failed -> {
// this registers the callback into the compose function
setResult(RESULT_ERROR)
finish()
}
is PaymentSheetResult.Completed -> {
// this registers the callback into the compose function
setResult(RESULT_OK)
finish()
}
}
}
fun presentPaymentSheet() {
// this is for storing payment methods like when you
// have an app that has continuous payments like Uber. 
paymentSheet.presentWithSetupIntent(
paymentSetupIntentClientSecret,
PaymentSheet.Configuration(
merchantDisplayName = "Your Merchant Name",
customer = customerConfig,
// Set `allowsDelayedPaymentMethods` to true if your business
// can handle payment methods that complete payment after a delay, like SEPA Debit and Sofort.
allowsDelayedPaymentMethods = true
)
)
// or you can use this with a payment intent
//        paymentSheet.presentWithPaymentIntent(
//            paymentIntentClientSecret,
//            PaymentSheet.Configuration(
//                merchantDisplayName = "Your Company Name",
//                customer = customerConfig,
//                allowsDelayedPaymentMethods = true
//            )
//        )
}
override public fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
}
}

然后从你的撰写函数中添加

@Composable
fun YourComposeFunctionHere(){
var intent = Intent(user.context, StripePaymentSheetActivity::class.java)
// you can send strings into your activity with something like this
// customer id should be in the form of cus_*****
intent.putExtra("customerId", customerId)
// make an activity launcher that has a callback for when the activity
// has a result ready
val stripeLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult()
){  result: ActivityResult  ->
if(result.resultCode == RESULT_OK) {
// do what you need to do if its ok
}else if(result.resultCode == RESULT_CANCELED){
// do what you need to do if its canceled 
}else if(result.resultCode == RESULT_ERROR){
// do what you need to do if its canceled 
}else{
// you shouldn't get here
}
}
// GUI Code here
TextButton(
// this will launch StripePaymentSheetActivity
// and then the method onCreate will run presentPaymentSheet()
onClick = { stripeLauncher.launch(intent) },
),
) {
Text(text = "Pay")
}
}

最后添加您的活动到您的AndroidManifest.xml

<activity android:name="com.example.myapplication.StripePaymentSheetActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" />

注意你需要添加你的特定路径到StripePaymentSheetActivity.kt

这个方法可以让你保持非常接近推荐的条纹文档,也是一个伟大的结构启动其他活动,如Facebook登录视图或Braintree付款表。

最新更新