Skip to content

Commit

Permalink
Update handling of deeplinks in PaymentAuthWebViewClient (#3035)
Browse files Browse the repository at this point in the history
Attempt to start the deeplink Intent with `Activity#startActivity()`
and catch any exception (notably `ActivityNotFoundException`) that is
thrown. `resolveActivity()` will not be usable starting in Android 11.

See https://developer.android.com/training/basics/intents/package-visibility-use-cases
for more details.
  • Loading branch information
mshafrir-stripe authored Nov 11, 2020
1 parent 5c38ffa commit 50669c5
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 18 deletions.
26 changes: 15 additions & 11 deletions stripe/src/main/java/com/stripe/android/view/PaymentAuthWebView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import android.annotation.TargetApi
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.util.AttributeSet
Expand Down Expand Up @@ -46,7 +45,6 @@ internal class PaymentAuthWebView @JvmOverloads constructor(
) {
val webViewClient = PaymentAuthWebViewClient(
activity,
activity.packageManager,
logger,
progressBar,
clientSecret,
Expand Down Expand Up @@ -110,7 +108,6 @@ internal class PaymentAuthWebView @JvmOverloads constructor(

internal class PaymentAuthWebViewClient(
private val activity: Activity,
private val packageManager: PackageManager,
private val logger: Logger,
private val progressBar: ProgressBar,
private val clientSecret: String,
Expand Down Expand Up @@ -189,17 +186,24 @@ internal class PaymentAuthWebView @JvmOverloads constructor(
}
}

/**
* See https://developer.android.com/training/basics/intents/package-visibility-use-cases
* for more details on app-to-app interaction.
*/
private fun openIntent(intent: Intent) {
logger.debug("PaymentAuthWebViewClient#openIntent()")
if (intent.resolveActivity(packageManager) != null) {

runCatching {
activity.startActivity(intent)
} else if (intent.scheme != "alipays") {
// complete auth if the deep-link can't be opened unless it is Alipay.
// The Alipay web view tries to open the Alipay app as soon as it is opened
// irrespective of whether or not the app is installed.
// If this intent fails to resolve, we should still let the user
// continue on the mobile site.
onAuthCompleted()
}.onFailure {
if (intent.scheme != "alipays") {
// complete auth if the deep-link can't be opened unless it is Alipay.
// The Alipay web view tries to open the Alipay app as soon as it is opened
// irrespective of whether or not the app is installed.
// If this intent fails to resolve, we should still let the user
// continue on the mobile site.
onAuthCompleted()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.stripe.android.view

import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.webkit.WebView
import android.widget.ProgressBar
import com.nhaarman.mockitokotlin2.KArgumentCaptor
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.argumentCaptor
import com.nhaarman.mockitokotlin2.eq
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import com.stripe.android.FakeLogger
import org.junit.runner.RunWith
import org.mockito.Mockito.never
Expand All @@ -24,7 +25,6 @@ class PaymentAuthWebViewTest {
private val activity: Activity = mock()
private val progressBar: ProgressBar = mock()
private val webView: WebView = mock()
private val packageManager: PackageManager = mock()

private val intentArgumentCaptor: KArgumentCaptor<Intent> = argumentCaptor()

Expand Down Expand Up @@ -112,6 +112,9 @@ class PaymentAuthWebViewTest {

@Test
fun shouldOverrideUrlLoading_withUnsupportedDeeplink_shouldFinish() {
whenever(activity.startActivity(any()))
.thenThrow(ActivityNotFoundException())

val url = "deep://link"
val paymentAuthWebViewClient = createWebViewClient("pi_123_secret_456")
paymentAuthWebViewClient.shouldOverrideUrlLoading(webView, url)
Expand All @@ -128,12 +131,14 @@ class PaymentAuthWebViewTest {

@Test
fun shouldOverrideUrlLoading_withIntentUri_shouldParseUri() {
whenever(activity.startActivity(any()))
.thenThrow(ActivityNotFoundException())

val deepLink = "intent://example.com/#Intent;scheme=https;action=android.intent.action.VIEW;end"
val paymentAuthWebViewClient = createWebViewClient("pi_123_secret_456")
paymentAuthWebViewClient.shouldOverrideUrlLoading(webView, deepLink)
verify(packageManager).resolveActivity(
intentArgumentCaptor.capture(),
eq(PackageManager.MATCH_DEFAULT_ONLY)
verify(activity).startActivity(
intentArgumentCaptor.capture()
)
val intent = intentArgumentCaptor.firstValue
assertEquals("https://example.com/", intent.dataString)
Expand Down Expand Up @@ -165,7 +170,6 @@ class PaymentAuthWebViewTest {
): PaymentAuthWebView.PaymentAuthWebViewClient {
return PaymentAuthWebView.PaymentAuthWebViewClient(
activity,
packageManager,
FakeLogger(),
progressBar,
clientSecret,
Expand Down

0 comments on commit 50669c5

Please sign in to comment.