-
Notifications
You must be signed in to change notification settings - Fork 648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Connect SDK] Support http/https pop-ups #9640
base: master
Are you sure you want to change the base?
Changes from all commits
94f8e64
9b43902
eab2df6
8cf612f
139fc98
8296f17
2668ce9
6e2b097
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package com.stripe.android.connect.webview | |
import android.annotation.SuppressLint | ||
import android.graphics.Bitmap | ||
import android.webkit.JavascriptInterface | ||
import android.webkit.WebResourceRequest | ||
import android.webkit.WebView | ||
import android.webkit.WebViewClient | ||
import androidx.core.view.doOnAttach | ||
|
@@ -32,13 +33,34 @@ import kotlinx.serialization.json.jsonObject | |
internal class StripeConnectWebViewClient( | ||
private val embeddedComponentManager: EmbeddedComponentManager, | ||
private val connectComponent: StripeEmbeddedComponent, | ||
private val stripeIntentLauncher: StripeIntentLauncher = StripeIntentLauncherImpl(), | ||
private val logger: Logger = Logger.getInstance(enableLogging = BuildConfig.DEBUG), | ||
private val jsonSerializer: Json = Json { | ||
ignoreUnknownKeys = true | ||
explicitNulls = false | ||
} | ||
) : WebViewClient() { | ||
|
||
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean { | ||
view ?: return false // the view shouldn't be null, but if it is then don't handle the request | ||
val url = request?.url ?: return false // if the request isn't for a url, then don't handle it | ||
|
||
return if (url.host in ALLOWLISTED_HOSTS) { | ||
// TODO - add an analytic event here to track this unexpected behavior | ||
logger.warning("(StripeConnectWebViewClient) Received pop-up for allow-listed host: $url") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a warning because we don't expect getting any of these given that messaging between windows on Android isn't supported? If this is the case, we should add a TODO here to add an analytic so we can setup alerts for it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was going off of this in the spec: Is that still accurate @mludowise-stripe? 👍 on adding an analytic here |
||
false // Allow the request to propagate so we open URL in WebView, but this is not an expected operation | ||
} else if (url.scheme == "https" || url.scheme == "http") { | ||
// open the URL in an external browser for safety and to preserve back navigation | ||
logger.debug("(StripeConnectWebViewClient) Opening URL in external browser: $url") | ||
stripeIntentLauncher.launchSecureExternalWebTab(view.context, url) | ||
true // block the request since we're opening it in a secure external tab | ||
} else { | ||
// TODO - support non-http/https schemes. | ||
logger.debug("(StripeConnectWebViewClient) Received unsupported pop-up request: $url") | ||
true // block the request as it's currently unsupported | ||
} | ||
} | ||
|
||
override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) { | ||
initJavascriptBridge(view) | ||
} | ||
|
@@ -47,6 +69,7 @@ internal class StripeConnectWebViewClient( | |
fun configureAndLoadWebView(webView: WebView) { | ||
webView.apply { | ||
webViewClient = this@StripeConnectWebViewClient | ||
webChromeClient = StripeWebChromeClient() | ||
settings.apply { | ||
javaScriptEnabled = true | ||
domStorageEnabled = true | ||
|
@@ -220,5 +243,6 @@ internal class StripeConnectWebViewClient( | |
internal companion object { | ||
private const val ANDROID_JS_INTERFACE = "Android" | ||
private const val ANDROID_JS_INTERNAL_INTERFACE = "AndroidInternal" | ||
private val ALLOWLISTED_HOSTS = setOf("connect.stripe.com", "connect-js.stripe.com") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.stripe.android.connect.webview | ||
|
||
import android.content.Context | ||
import android.net.Uri | ||
import androidx.browser.customtabs.CustomTabsIntent | ||
|
||
internal interface StripeIntentLauncher { | ||
/** | ||
* Launches [uri] in a secure external Android Custom Tab. | ||
*/ | ||
fun launchSecureExternalWebTab(context: Context, uri: Uri) | ||
} | ||
|
||
internal class StripeIntentLauncherImpl : StripeIntentLauncher { | ||
override fun launchSecureExternalWebTab(context: Context, uri: Uri) { | ||
val customTabsIntent = CustomTabsIntent.Builder().build() | ||
customTabsIntent.launchUrl(context, uri) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.stripe.android.connect.webview | ||
|
||
import android.webkit.WebChromeClient | ||
import android.webkit.WebViewClient | ||
|
||
/** | ||
* A [WebChromeClient] that provides additional functionality for Stripe Connect Embedded Component WebViews. | ||
* | ||
* This class is currently empty, but it could be used to add additional functionality in the future | ||
* Setting a [WebChromeClient] (even an empty one) is necessary for certain functionality, like | ||
* [WebViewClient.shouldOverrideUrlLoading] to work properly. | ||
*/ | ||
Comment on lines
+7
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
internal class StripeWebChromeClient : WebChromeClient() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀 this fixes a crash if any appearance id's change and can't be found anymore (something I ran into myself)