Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -417,14 +417,24 @@ internal class CheckoutWebView private constructor(
return when {
uri == null -> false
uri.isContactLink() || uri.isDeepLink() -> {
when (val result = ExternalUriLauncher.launchExternalApp(context, uri)) {
is ExternalUriLauncher.Result.Launched ->
log.d(LOG_TAG, "Deep link intercepted: ${uri.redactedForLogging()} — allowed")
is ExternalUriLauncher.Result.Rejected ->
log.d(
LOG_TAG,
"Deep link intercepted: ${uri.redactedForLogging()} — rejected (${result.reason})"
)
log.d(LOG_TAG, "Raw navigation link intercepted: ${uri.redactedForLogging()}")
when (listener.onCheckoutLinkClicked(CheckoutLink(uri))) {
CheckoutLinkAction.Open -> {
log.d(LOG_TAG, "Raw navigation link delegated to SDK default handler")
when (val result = ExternalUriLauncher.launchExternalApp(context, uri)) {
is ExternalUriLauncher.Result.Launched ->
log.d(LOG_TAG, "Raw navigation link opened with SDK default handler")
is ExternalUriLauncher.Result.Rejected ->
log.d(
LOG_TAG,
"Raw navigation link rejected by SDK default handler: ${result.reason}"
)
}
}
CheckoutLinkAction.Handled ->
log.d(LOG_TAG, "Raw navigation link handled by host")
CheckoutLinkAction.Cancel ->
log.d(LOG_TAG, "Raw navigation link canceled by host")
}
true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class CheckoutWebViewClientTest {
// no activity resolves the intent. Robolectric defaults to silently recording the
// intent instead — turning on checkActivities aligns the shadow with production.
shadowOf(activity.application).checkActivities(true)
whenever(mockListener.onCheckoutLinkClicked(any())).thenReturn(CheckoutLinkAction.Open)
}

@After
Expand Down Expand Up @@ -104,6 +105,50 @@ class CheckoutWebViewClientTest {
assertThat(shadowOf(activity).nextStartedActivity).isNotNull
}

@Test
fun `delegates deep links to the listener before opening them`() {
val uri = Uri.parse("geo:40.712776,-74.005974?q=Statue+of+Liberty")
registerResolverFor(uri)
val mockRequest = mockWebRequest(uri)

val view = viewWithProcessor(activity)
val overridden = view.CheckoutWebViewClient().shouldOverrideUrlLoading(view, mockRequest)

assertThat(overridden).isTrue
val link = argumentCaptor<CheckoutLink>()
verify(mockListener).onCheckoutLinkClicked(link.capture())
assertThat(link.firstValue.url).isEqualTo(uri)
assertThat(shadowOf(activity).nextStartedActivity).isNotNull
}

@Test
fun `does not open a deep link handled by the listener`() {
val listener = mock<CheckoutListener>()
whenever(listener.onCheckoutLinkClicked(any())).thenReturn(CheckoutLinkAction.Handled)
val uri = Uri.parse("myapp://path")
val view = viewWithProcessor(activity, CheckoutWebViewListener(listener))

val overridden = view.CheckoutWebViewClient().shouldOverrideUrlLoading(view, mockWebRequest(uri))

assertThat(overridden).isTrue
verify(listener).onCheckoutLinkClicked(any())
assertThat(shadowOf(activity).peekNextStartedActivityForResult()).isNull()
}

@Test
fun `does not open a deep link canceled by the listener`() {
val listener = mock<CheckoutListener>()
whenever(listener.onCheckoutLinkClicked(any())).thenReturn(CheckoutLinkAction.Cancel)
val uri = Uri.parse("myapp://path")
val view = viewWithProcessor(activity, CheckoutWebViewListener(listener))

val overridden = view.CheckoutWebViewClient().shouldOverrideUrlLoading(view, mockWebRequest(uri))

assertThat(overridden).isTrue
verify(listener).onCheckoutLinkClicked(any())
assertThat(shadowOf(activity).peekNextStartedActivityForResult()).isNull()
}

@Test
fun `overrides url loading for unresolvable deep link but launches no intent`() {
val mockRequest = mockWebRequest(Uri.parse("myapp://path"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,13 @@ class CartViewModel(
activity: ComponentActivity,
handler: WindowOpenHandler,
): CheckoutLinkAction {
recordSdkEvent("Checkout link clicked", mapOf("url" to link.url.toString()))
// Returning Open keeps Checkout Kit's Custom Tab and non-web intent handling.
if (handler == WindowOpenHandler.Default) return CheckoutLinkAction.Open
if (handler == WindowOpenHandler.Default) {
recordSdkEvent("Checkout link delegated to Checkout Kit", mapOf("url" to link.url.toString()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we print the url above so probably dont need to print it here too

return CheckoutLinkAction.Open
}

recordSdkEvent("Checkout link clicked", mapOf("url" to link.url.toString()))
return try {
val intent = Intent(Intent.ACTION_VIEW, link.url).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.startActivity(intent)
Expand Down
Loading