Skip to content

Commit

Permalink
Add support for app deep-links in PaymentAuthWebView (#1523)
Browse files Browse the repository at this point in the history
ANDROID-409
  • Loading branch information
mshafrir-stripe authored Sep 11, 2019
1 parent f857507 commit a333ccb
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.stripe.android.SetupIntentResult
import com.stripe.android.Stripe
import com.stripe.android.model.ConfirmPaymentIntentParams
import com.stripe.android.model.ConfirmSetupIntentParams
import com.stripe.android.model.PaymentMethodCreateParams
import com.stripe.example.R
import com.stripe.example.Settings
import com.stripe.example.module.RetrofitFactory
Expand Down Expand Up @@ -82,11 +83,10 @@ class PaymentAuthActivity : AppCompatActivity() {

private fun confirmPaymentIntent(paymentIntentClientSecret: String) {
statusTextView.append("\n\nStarting payment authentication")
stripe.confirmPayment(this,
ConfirmPaymentIntentParams.createWithPaymentMethodId(
PAYMENT_METHOD_3DS2_REQUIRED,
paymentIntentClientSecret,
RETURN_URL))
stripe.confirmPayment(
this,
create3ds2ConfirmParams(paymentIntentClientSecret)
)
}

private fun confirmSetupIntent(setupIntentClientSecret: String) {
Expand Down Expand Up @@ -189,7 +189,7 @@ class PaymentAuthActivity : AppCompatActivity() {
}

private fun createPaymentIntentParams(stripeAccountId: String?): HashMap<String, Any> {
val params = hashMapOf<String, Any>(
val params = hashMapOf(
"payment_method_types[]" to "card",
"amount" to 1000,
"currency" to "usd"
Expand Down Expand Up @@ -247,9 +247,35 @@ class PaymentAuthActivity : AppCompatActivity() {
/**
* See https://stripe.com/docs/payments/3d-secure#three-ds-cards for more options.
*/
private const val PAYMENT_METHOD_3DS2_REQUIRED = "pm_card_threeDSecure2Required"
private const val PAYMENT_METHOD_3DS_REQUIRED = "pm_card_threeDSecureRequired"
private const val PAYMENT_METHOD_AUTH_REQUIRED_ON_SETUP = "pm_card_authenticationRequiredOnSetup"
private const val PAYMENT_METHOD_AUTH_REQUIRED_ON_SETUP =
"pm_card_authenticationRequiredOnSetup"

private fun create3ds2ConfirmParams(
paymentIntentClientSecret: String
): ConfirmPaymentIntentParams {
return ConfirmPaymentIntentParams.createWithPaymentMethodId(
"pm_card_threeDSecure2Required",
paymentIntentClientSecret,
RETURN_URL
)
}

private fun create3ds1ConfirmParams(
paymentIntentClientSecret: String
): ConfirmPaymentIntentParams {
return ConfirmPaymentIntentParams.createWithPaymentMethodCreateParams(
PaymentMethodCreateParams.create(
PaymentMethodCreateParams.Card.Builder()
.setNumber("4000000000003063")
.setExpiryMonth(1)
.setExpiryYear(2025)
.setCvc("123")
.build()
),
paymentIntentClientSecret,
RETURN_URL
)
}

private const val RETURN_URL = "stripe://payment_auth"

Expand Down
25 changes: 22 additions & 3 deletions stripe/src/main/java/com/stripe/android/view/PaymentAuthWebView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.util.AttributeSet
import android.view.View
import android.webkit.URLUtil
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
Expand Down Expand Up @@ -78,12 +80,29 @@ internal class PaymentAuthWebView : WebView {

override fun shouldOverrideUrlLoading(view: WebView, urlString: String): Boolean {
val uri = Uri.parse(urlString)
if (isReturnUrl(uri)) {
return if (isReturnUrl(uri)) {
onAuthCompleted()
return true
true
} else if (!URLUtil.isNetworkUrl(urlString)) {
openNonNetworkUrlDeeplink(uri)
true
} else {
super.shouldOverrideUrlLoading(view, urlString)
}
}

return super.shouldOverrideUrlLoading(view, urlString)
/**
* Non-network URLs are likely deep-links into banking apps. If the deep-link can be opened
* via an Intent, start it. Otherwise, stop the authentication attempt.
*/
private fun openNonNetworkUrlDeeplink(uri: Uri) {
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(activity.packageManager) != null) {
activity.startActivity(intent)
} else {
// complete auth if the deep-link can't be opened
onAuthCompleted()
}
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import android.webkit.WebView;
import android.widget.ProgressBar;

import androidx.test.core.app.ApplicationProvider;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand All @@ -13,6 +15,7 @@

import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(RobolectricTestRunner.class)
public class PaymentAuthWebViewTest {
Expand All @@ -24,6 +27,8 @@ public class PaymentAuthWebViewTest {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mActivity.getPackageManager())
.thenReturn(ApplicationProvider.getApplicationContext().getPackageManager());
}

@Test
Expand Down Expand Up @@ -122,4 +127,14 @@ public void shouldOverrideUrlLoading_withOpaqueUri_shouldNotCrash() {
"pi_123_secret_456", null);
paymentAuthWebViewClient.shouldOverrideUrlLoading(mWebView, deepLink);
}

@Test
public void shouldOverrideUrlLoading_withUnsupportedDeeplink_shouldFinish() {
final String deepLink = "deep://link";
final PaymentAuthWebView.PaymentAuthWebViewClient paymentAuthWebViewClient =
new PaymentAuthWebView.PaymentAuthWebViewClient(mActivity, mProgressBar,
"pi_123_secret_456", null);
paymentAuthWebViewClient.shouldOverrideUrlLoading(mWebView, deepLink);
verify(mActivity).finish();
}
}

0 comments on commit a333ccb

Please sign in to comment.