From e5eba229455db2781b35be14e990a32c547f9518 Mon Sep 17 00:00:00 2001 From: "Bruno R. Nunes" Date: Wed, 14 Sep 2022 13:13:11 -0700 Subject: [PATCH 1/4] Fix Alipay --- example/AndroidManifest.xml | 1 + example/build.gradle | 3 + example/res/values/strings.xml | 4 + .../example/activity/AlipayPaymentActivity.kt | 101 ++++++++++++++++++ .../example/activity/LauncherActivity.kt | 4 + .../example/activity/StripeIntentActivity.kt | 2 +- .../IdentityDocumentScanFragment.kt | 4 +- .../android/networking/StripeApiRepository.kt | 5 +- .../android/networking/StripeRepository.kt | 4 +- .../networking/AbsFakeStripeRepository.kt | 4 +- .../networking/StripeApiRepositoryTest.kt | 22 ++++ 11 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt diff --git a/example/AndroidManifest.xml b/example/AndroidManifest.xml index 4fff83498f6..f704d417194 100644 --- a/example/AndroidManifest.xml +++ b/example/AndroidManifest.xml @@ -72,6 +72,7 @@ + diff --git a/example/build.gradle b/example/build.gradle index 2a187a96ff4..cb0b28dfa2d 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -32,6 +32,9 @@ def getAccountId() { dependencies { implementation project(':payments') implementation project(':financial-connections') + + implementation("com.alipay.sdk:alipaysdk-android:15.8.11") + implementation "androidx.appcompat:appcompat:$androidxAppcompatVersion" implementation "androidx.recyclerview:recyclerview:$androidxRecyclerviewVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$androidxLifecycleVersion" diff --git a/example/res/values/strings.xml b/example/res/values/strings.xml index 8a0b3eb706c..dc7f33a8320 100644 --- a/example/res/values/strings.xml +++ b/example/res/values/strings.xml @@ -87,6 +87,10 @@ Confirm with Affirm Affirm Payment Intent Example + Tapping the button below will create a PaymentIntent and then use Alipay to confirm it + Confirm with Alipay + Alipay Payment Intent Example + By providing your IBAN and confirming this payment, you are authorizing EXAMPLE COMPANY NAME and Stripe, our payment service provider, to send instructions to your bank to debit your account and your bank to debit your account in accordance with those instructions. You are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited. IBAN diff --git a/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt b/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt new file mode 100644 index 00000000000..c82bbc847ba --- /dev/null +++ b/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt @@ -0,0 +1,101 @@ +package com.stripe.example.activity + +import android.os.Bundle +import android.view.View +import androidx.lifecycle.Observer +import com.alipay.sdk.app.PayTask +import com.stripe.android.ApiResultCallback +import com.stripe.android.PaymentConfiguration +import com.stripe.android.PaymentIntentResult +import com.stripe.android.Stripe +import com.stripe.android.model.ConfirmPaymentIntentParams +import com.stripe.android.model.MandateDataParams +import com.stripe.android.model.PaymentMethodCreateParams +import com.stripe.android.model.StripeIntent +import com.stripe.example.R +import com.stripe.example.databinding.PaymentExampleActivityBinding +import org.json.JSONObject + +class AlipayPaymentActivity : StripeIntentActivity() { + + private val viewBinding: PaymentExampleActivityBinding by lazy { + PaymentExampleActivityBinding.inflate(layoutInflater) + } + + private val stripe: Stripe by lazy { + Stripe( + applicationContext, + PaymentConfiguration.getInstance(applicationContext).publishableKey + ) + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(viewBinding.root) + + viewBinding.confirmWithPaymentButton.text = + resources.getString(R.string.confirm_alipay_button) + viewBinding.paymentExampleIntro.text = + resources.getString(R.string.alipay_example_intro) + + viewModel.inProgress.observe(this) { enableUi(!it) } + viewModel.status.observe(this, Observer(viewBinding.status::setText)) + + viewBinding.confirmWithPaymentButton.setOnClickListener { + createAndConfirmPaymentIntent( + country = "US", + paymentMethodCreateParams = PaymentMethodCreateParams.createAlipay(), + supportedPaymentMethods = "alipay" + ) + } + } + + override fun handleCreatePaymentIntentResponse( + responseData: JSONObject, + params: PaymentMethodCreateParams?, + shippingDetails: ConfirmPaymentIntentParams.Shipping?, + stripeAccountId: String?, + existingPaymentMethodId: String?, + mandateDataParams: MandateDataParams?, + onPaymentIntentCreated: (String) -> Unit + ) { + val secret = responseData.getString("secret") + onPaymentIntentCreated(secret) + viewModel.status.value += + "\n\nStarting PaymentIntent confirmation" + + ( + stripeAccountId?.let { + " for $it" + } ?: "" + ) + + stripe.confirmAlipayPayment( + confirmPaymentIntentParams = ConfirmPaymentIntentParams.createAlipay(secret), + authenticator = { data -> + PayTask(this).payV2(data, true) + }, + callback = object : ApiResultCallback { + override fun onSuccess(result: PaymentIntentResult) { + val paymentIntent = result.intent + val status = paymentIntent.status + when (status) { + StripeIntent.Status.Succeeded -> + viewModel.status.value += "\n\nPayment succeeded" + StripeIntent.Status.RequiresAction -> + stripe.handleNextActionForPayment(this@AlipayPaymentActivity, secret) + else -> viewModel.status.value += "\n\nPayment failed or canceled" + } + } + + override fun onError(e: Exception) { + viewModel.status.value += "\n\nError: ${e.message}" + } + } + ) + } + + private fun enableUi(enable: Boolean) { + viewBinding.progressBar.visibility = if (enable) View.INVISIBLE else View.VISIBLE + viewBinding.confirmWithPaymentButton.isEnabled = enable + } +} diff --git a/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt b/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt index 6e7e1db3c52..7d33266bf85 100644 --- a/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt +++ b/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt @@ -109,6 +109,10 @@ class LauncherActivity : AppCompatActivity() { activity.getString(R.string.confirm_with_affirm), AffirmPaymentActivity::class.java ), + Item( + activity.getString(R.string.confirm_with_alipay), + AlipayPaymentActivity::class.java + ), Item( activity.getString(R.string.becs_debit_example), BecsDebitPaymentMethodActivity::class.java diff --git a/example/src/main/java/com/stripe/example/activity/StripeIntentActivity.kt b/example/src/main/java/com/stripe/example/activity/StripeIntentActivity.kt index c15f1397794..607732b0e84 100644 --- a/example/src/main/java/com/stripe/example/activity/StripeIntentActivity.kt +++ b/example/src/main/java/com/stripe/example/activity/StripeIntentActivity.kt @@ -127,7 +127,7 @@ abstract class StripeIntentActivity : AppCompatActivity() { } } - private fun handleCreatePaymentIntentResponse( + open fun handleCreatePaymentIntentResponse( responseData: JSONObject, params: PaymentMethodCreateParams?, shippingDetails: ConfirmPaymentIntentParams.Shipping?, diff --git a/identity/src/main/java/com/stripe/android/identity/navigation/IdentityDocumentScanFragment.kt b/identity/src/main/java/com/stripe/android/identity/navigation/IdentityDocumentScanFragment.kt index 6b8423110a1..8749a60bad0 100644 --- a/identity/src/main/java/com/stripe/android/identity/navigation/IdentityDocumentScanFragment.kt +++ b/identity/src/main/java/com/stripe/android/identity/navigation/IdentityDocumentScanFragment.kt @@ -251,7 +251,9 @@ internal abstract class IdentityDocumentScanFragment( notSubmitBlock = if (verificationPage.requireSelfie()) { ({ findNavController().navigate(R.id.action_global_selfieFragment) }) - } else null + } else { + null + } ) }.onFailure { throwable -> Log.e( diff --git a/payments-core/src/main/java/com/stripe/android/networking/StripeApiRepository.kt b/payments-core/src/main/java/com/stripe/android/networking/StripeApiRepository.kt index 4013097331a..f50d2fb98f5 100644 --- a/payments-core/src/main/java/com/stripe/android/networking/StripeApiRepository.kt +++ b/payments-core/src/main/java/com/stripe/android/networking/StripeApiRepository.kt @@ -92,7 +92,6 @@ import com.stripe.android.payments.core.injection.PRODUCT_USAGE import com.stripe.android.utils.StripeUrlUtils import kotlinx.coroutines.Dispatchers import org.json.JSONException -import org.json.JSONObject import java.io.IOException import java.net.HttpURLConnection import java.security.Security @@ -1112,7 +1111,7 @@ class StripeApiRepository @JvmOverloads internal constructor( override suspend fun retrieveObject( url: String, requestOptions: ApiRequest.Options - ): JSONObject { + ): StripeResponse { if (!StripeUrlUtils.isStripeUrl(url)) { throw IllegalArgumentException("Unrecognized domain: $url") } @@ -1125,7 +1124,7 @@ class StripeApiRepository @JvmOverloads internal constructor( fireAnalyticsRequest(PaymentAnalyticsEvent.StripeUrlRetrieve) } - return response.responseJson() + return response } /** diff --git a/payments-core/src/main/java/com/stripe/android/networking/StripeRepository.kt b/payments-core/src/main/java/com/stripe/android/networking/StripeRepository.kt index 6185f4da2ba..2a443ba0395 100644 --- a/payments-core/src/main/java/com/stripe/android/networking/StripeRepository.kt +++ b/payments-core/src/main/java/com/stripe/android/networking/StripeRepository.kt @@ -10,6 +10,7 @@ import com.stripe.android.core.exception.InvalidRequestException import com.stripe.android.core.model.StripeFile import com.stripe.android.core.model.StripeFileParams import com.stripe.android.core.networking.ApiRequest +import com.stripe.android.core.networking.StripeResponse import com.stripe.android.exception.CardException import com.stripe.android.model.BankStatuses import com.stripe.android.model.CardMetadata @@ -40,7 +41,6 @@ import com.stripe.android.model.StripeIntent import com.stripe.android.model.Token import com.stripe.android.model.TokenParams import org.json.JSONException -import org.json.JSONObject import java.util.Locale /** @@ -391,7 +391,7 @@ abstract class StripeRepository { internal abstract suspend fun retrieveObject( url: String, requestOptions: ApiRequest.Options - ): JSONObject + ): StripeResponse internal abstract suspend fun createRadarSession( requestOptions: ApiRequest.Options diff --git a/payments-core/src/test/java/com/stripe/android/networking/AbsFakeStripeRepository.kt b/payments-core/src/test/java/com/stripe/android/networking/AbsFakeStripeRepository.kt index 790c1dc8b02..bb8322db052 100644 --- a/payments-core/src/test/java/com/stripe/android/networking/AbsFakeStripeRepository.kt +++ b/payments-core/src/test/java/com/stripe/android/networking/AbsFakeStripeRepository.kt @@ -5,6 +5,7 @@ import com.stripe.android.core.exception.APIException import com.stripe.android.core.model.StripeFile import com.stripe.android.core.model.StripeFileParams import com.stripe.android.core.networking.ApiRequest +import com.stripe.android.core.networking.StripeResponse import com.stripe.android.model.BankStatuses import com.stripe.android.model.BinFixtures import com.stripe.android.model.CardMetadata @@ -34,7 +35,6 @@ import com.stripe.android.model.Stripe3ds2AuthResultFixtures import com.stripe.android.model.StripeIntent import com.stripe.android.model.Token import com.stripe.android.model.TokenParams -import org.json.JSONObject import java.util.Locale internal abstract class AbsFakeStripeRepository : StripeRepository() { @@ -279,7 +279,7 @@ internal abstract class AbsFakeStripeRepository : StripeRepository() { override suspend fun retrieveObject( url: String, requestOptions: ApiRequest.Options - ) = JSONObject() + ) = StripeResponse(1, "response") override suspend fun createRadarSession( requestOptions: ApiRequest.Options diff --git a/payments-core/src/test/java/com/stripe/android/networking/StripeApiRepositoryTest.kt b/payments-core/src/test/java/com/stripe/android/networking/StripeApiRepositoryTest.kt index adf0e33aedd..b4ad5754808 100644 --- a/payments-core/src/test/java/com/stripe/android/networking/StripeApiRepositoryTest.kt +++ b/payments-core/src/test/java/com/stripe/android/networking/StripeApiRepositoryTest.kt @@ -1223,6 +1223,28 @@ internal class StripeApiRepositoryTest { verifyAnalyticsRequest(PaymentAnalyticsEvent.FileCreate) } + @Test + fun retrieveObject_shouldFireExpectedRequestsAndNotParseResult() = runTest { + val responseBody = "not a valid json" + whenever(stripeNetworkClient.executeRequest(any())) + .thenReturn( + StripeResponse( + 200, + responseBody, + emptyMap() + ) + ) + + val response = create().retrieveObject( + StripeApiRepository.paymentMethodsUrl, + DEFAULT_OPTIONS + ) + + verify(stripeNetworkClient).executeRequest(any()) + assertThat(response.body).isEqualTo(responseBody) + verifyAnalyticsRequest(PaymentAnalyticsEvent.StripeUrlRetrieve) + } + @Test fun apiRequest_withErrorResponse_onUnsupportedSdkVersion_shouldNotBeTranslated() = runTest { From 7b0f200cca38d3391c17e61ab5d862676353d766 Mon Sep 17 00:00:00 2001 From: "Bruno R. Nunes" Date: Wed, 14 Sep 2022 13:19:05 -0700 Subject: [PATCH 2/4] CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ede5227e8f..8bd1a316945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## X.X.X - 2022-XX-XX +### Payments + +* [FIXED][5554](https://github.com/stripe/stripe-android/pull/5554) Fix Alipay integration when using the Alipay SDK. + ## 20.12.0 - 2022-09-13 This release upgrades `compileSdkVersion` to 33, updates Google Pay button to match the new brand guidelines and fixes some bugs in `FlowController`. From 484f3440a8639c5ccb00d841486c2881ac5173fd Mon Sep 17 00:00:00 2001 From: "Bruno R. Nunes" Date: Wed, 14 Sep 2022 14:52:07 -0700 Subject: [PATCH 3/4] Reset status when payment completed --- .../example/activity/AlipayPaymentActivity.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt b/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt index c82bbc847ba..a55de9523e4 100644 --- a/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt +++ b/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt @@ -77,23 +77,27 @@ class AlipayPaymentActivity : StripeIntentActivity() { callback = object : ApiResultCallback { override fun onSuccess(result: PaymentIntentResult) { val paymentIntent = result.intent - val status = paymentIntent.status - when (status) { + when (paymentIntent.status) { StripeIntent.Status.Succeeded -> - viewModel.status.value += "\n\nPayment succeeded" + updateStatus("\n\nPayment succeeded") StripeIntent.Status.RequiresAction -> stripe.handleNextActionForPayment(this@AlipayPaymentActivity, secret) - else -> viewModel.status.value += "\n\nPayment failed or canceled" + else -> updateStatus("\n\nPayment failed or canceled") } } override fun onError(e: Exception) { - viewModel.status.value += "\n\nError: ${e.message}" + updateStatus("\n\nError: ${e.message}") } } ) } + private fun updateStatus(appendMessage: String) { + viewModel.status.value += appendMessage + viewModel.inProgress.postValue(false) + } + private fun enableUi(enable: Boolean) { viewBinding.progressBar.visibility = if (enable) View.INVISIBLE else View.VISIBLE viewBinding.confirmWithPaymentButton.isEnabled = enable From 2386350ebb3985c9dae4fa1ff427dd19d710289e Mon Sep 17 00:00:00 2001 From: "Bruno R. Nunes" Date: Fri, 16 Sep 2022 15:15:07 -0700 Subject: [PATCH 4/4] Add web example --- example/AndroidManifest.xml | 3 +- example/res/values/strings.xml | 3 +- ...vity.kt => AlipayPaymentNativeActivity.kt} | 45 ++++-- .../activity/AlipayPaymentWebActivity.kt | 130 ++++++++++++++++++ .../example/activity/LauncherActivity.kt | 8 +- 5 files changed, 173 insertions(+), 16 deletions(-) rename example/src/main/java/com/stripe/example/activity/{AlipayPaymentActivity.kt => AlipayPaymentNativeActivity.kt} (70%) create mode 100644 example/src/main/java/com/stripe/example/activity/AlipayPaymentWebActivity.kt diff --git a/example/AndroidManifest.xml b/example/AndroidManifest.xml index f704d417194..c5ad89b71e1 100644 --- a/example/AndroidManifest.xml +++ b/example/AndroidManifest.xml @@ -72,7 +72,8 @@ - + + diff --git a/example/res/values/strings.xml b/example/res/values/strings.xml index dc7f33a8320..78d961505ca 100644 --- a/example/res/values/strings.xml +++ b/example/res/values/strings.xml @@ -89,7 +89,8 @@ Tapping the button below will create a PaymentIntent and then use Alipay to confirm it Confirm with Alipay - Alipay Payment Intent Example + Alipay Payment Intent Native Example + Alipay Payment Intent Web Example By providing your IBAN and confirming this payment, you are authorizing EXAMPLE COMPANY NAME and Stripe, our payment service provider, to send instructions to your bank to debit your account and your bank to debit your account in accordance with those instructions. You are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited. diff --git a/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt b/example/src/main/java/com/stripe/example/activity/AlipayPaymentNativeActivity.kt similarity index 70% rename from example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt rename to example/src/main/java/com/stripe/example/activity/AlipayPaymentNativeActivity.kt index a55de9523e4..98bc189b821 100644 --- a/example/src/main/java/com/stripe/example/activity/AlipayPaymentActivity.kt +++ b/example/src/main/java/com/stripe/example/activity/AlipayPaymentNativeActivity.kt @@ -16,7 +16,7 @@ import com.stripe.example.R import com.stripe.example.databinding.PaymentExampleActivityBinding import org.json.JSONObject -class AlipayPaymentActivity : StripeIntentActivity() { +class AlipayPaymentNativeActivity : StripeIntentActivity() { private val viewBinding: PaymentExampleActivityBinding by lazy { PaymentExampleActivityBinding.inflate(layoutInflater) @@ -29,6 +29,9 @@ class AlipayPaymentActivity : StripeIntentActivity() { ) } + private var clientSecret: String? = null + private var confirmed = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(viewBinding.root) @@ -42,11 +45,19 @@ class AlipayPaymentActivity : StripeIntentActivity() { viewModel.status.observe(this, Observer(viewBinding.status::setText)) viewBinding.confirmWithPaymentButton.setOnClickListener { - createAndConfirmPaymentIntent( - country = "US", - paymentMethodCreateParams = PaymentMethodCreateParams.createAlipay(), - supportedPaymentMethods = "alipay" - ) + clientSecret?.let { + // If we already loaded the Payment Intent and haven't confirmed, try again + if (!confirmed) { + updateStatus("\n\nPayment Intent already created, trying to confirm") + confirmPayment(it) + } + } ?: run { + createAndConfirmPaymentIntent( + country = "US", + paymentMethodCreateParams = PaymentMethodCreateParams.createAlipay(), + supportedPaymentMethods = "alipay" + ) + } } } @@ -59,8 +70,6 @@ class AlipayPaymentActivity : StripeIntentActivity() { mandateDataParams: MandateDataParams?, onPaymentIntentCreated: (String) -> Unit ) { - val secret = responseData.getString("secret") - onPaymentIntentCreated(secret) viewModel.status.value += "\n\nStarting PaymentIntent confirmation" + ( @@ -69,8 +78,14 @@ class AlipayPaymentActivity : StripeIntentActivity() { } ?: "" ) + clientSecret = responseData.getString("secret").also { + confirmPayment(it) + } + } + + private fun confirmPayment(clientSecret: String) { stripe.confirmAlipayPayment( - confirmPaymentIntentParams = ConfirmPaymentIntentParams.createAlipay(secret), + confirmPaymentIntentParams = ConfirmPaymentIntentParams.createAlipay(clientSecret), authenticator = { data -> PayTask(this).payV2(data, true) }, @@ -78,11 +93,17 @@ class AlipayPaymentActivity : StripeIntentActivity() { override fun onSuccess(result: PaymentIntentResult) { val paymentIntent = result.intent when (paymentIntent.status) { - StripeIntent.Status.Succeeded -> + StripeIntent.Status.Succeeded -> { + confirmed = true updateStatus("\n\nPayment succeeded") + } StripeIntent.Status.RequiresAction -> - stripe.handleNextActionForPayment(this@AlipayPaymentActivity, secret) - else -> updateStatus("\n\nPayment failed or canceled") + updateStatus("\n\nUser canceled confirmation") + else -> + updateStatus( + "\n\nPayment failed or canceled." + + "\nStatus: ${paymentIntent.status}" + ) } } diff --git a/example/src/main/java/com/stripe/example/activity/AlipayPaymentWebActivity.kt b/example/src/main/java/com/stripe/example/activity/AlipayPaymentWebActivity.kt new file mode 100644 index 00000000000..edfefbd3426 --- /dev/null +++ b/example/src/main/java/com/stripe/example/activity/AlipayPaymentWebActivity.kt @@ -0,0 +1,130 @@ +package com.stripe.example.activity + +import android.content.Intent +import android.os.Bundle +import android.view.View +import androidx.lifecycle.Observer +import com.stripe.android.ApiResultCallback +import com.stripe.android.PaymentConfiguration +import com.stripe.android.PaymentIntentResult +import com.stripe.android.Stripe +import com.stripe.android.model.ConfirmPaymentIntentParams +import com.stripe.android.model.MandateDataParams +import com.stripe.android.model.PaymentMethodCreateParams +import com.stripe.android.model.StripeIntent +import com.stripe.example.R +import com.stripe.example.databinding.PaymentExampleActivityBinding +import org.json.JSONObject + +class AlipayPaymentWebActivity : StripeIntentActivity() { + + private val viewBinding: PaymentExampleActivityBinding by lazy { + PaymentExampleActivityBinding.inflate(layoutInflater) + } + + private val stripe: Stripe by lazy { + Stripe( + applicationContext, + PaymentConfiguration.getInstance(applicationContext).publishableKey + ) + } + + private var clientSecret: String? = null + private var confirmed = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(viewBinding.root) + + viewBinding.confirmWithPaymentButton.text = + resources.getString(R.string.confirm_alipay_button) + viewBinding.paymentExampleIntro.text = + resources.getString(R.string.alipay_example_intro) + + viewModel.inProgress.observe(this) { enableUi(!it) } + viewModel.status.observe(this, Observer(viewBinding.status::setText)) + + viewBinding.confirmWithPaymentButton.setOnClickListener { + clientSecret?.let { + // If we already loaded the Payment Intent and haven't confirmed, try again + if (!confirmed) { + updateStatus("\n\nPayment Intent already created, trying to confirm") + confirmPayment(it) + } + } ?: run { + createAndConfirmPaymentIntent( + country = "US", + paymentMethodCreateParams = PaymentMethodCreateParams.createAlipay(), + supportedPaymentMethods = "alipay" + ) + } + } + } + + override fun handleCreatePaymentIntentResponse( + responseData: JSONObject, + params: PaymentMethodCreateParams?, + shippingDetails: ConfirmPaymentIntentParams.Shipping?, + stripeAccountId: String?, + existingPaymentMethodId: String?, + mandateDataParams: MandateDataParams?, + onPaymentIntentCreated: (String) -> Unit + ) { + viewModel.status.value += + "\n\nStarting PaymentIntent confirmation" + + ( + stripeAccountId?.let { + " for $it" + } ?: "" + ) + + clientSecret = responseData.getString("secret").also { + confirmPayment(it) + } + } + + private fun confirmPayment(clientSecret: String) { + stripe.confirmPayment(this, ConfirmPaymentIntentParams.createAlipay(clientSecret)) + } + + private fun updateStatus(appendMessage: String) { + viewModel.status.value += appendMessage + viewModel.inProgress.postValue(false) + } + + private fun enableUi(enable: Boolean) { + viewBinding.progressBar.visibility = if (enable) View.INVISIBLE else View.VISIBLE + viewBinding.confirmWithPaymentButton.isEnabled = enable + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + + // Handle the result of stripe.confirmPayment + stripe.onPaymentResult( + requestCode, + data, + object : ApiResultCallback { + override fun onSuccess(result: PaymentIntentResult) { + val paymentIntent = result.intent + val status = paymentIntent.status + when (status) { + StripeIntent.Status.Succeeded -> + updateStatus("\n\nPayment succeeded") + StripeIntent.Status.RequiresAction -> + updateStatus("\n\nUser canceled confirmation") + else -> + updateStatus( + "\n\nPayment failed or canceled." + + "\nStatus: ${paymentIntent.status}" + ) + } + } + + override fun onError(e: Exception) { + updateStatus("\n\nError: ${e.message}") + } + } + ) + } +} diff --git a/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt b/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt index 7d33266bf85..ee2b64cca34 100644 --- a/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt +++ b/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt @@ -110,8 +110,12 @@ class LauncherActivity : AppCompatActivity() { AffirmPaymentActivity::class.java ), Item( - activity.getString(R.string.confirm_with_alipay), - AlipayPaymentActivity::class.java + activity.getString(R.string.confirm_with_alipay_native), + AlipayPaymentNativeActivity::class.java + ), + Item( + activity.getString(R.string.confirm_with_alipay_web), + AlipayPaymentWebActivity::class.java ), Item( activity.getString(R.string.becs_debit_example),