From 59153413d87549964b885ad3ed84473acf4b70df Mon Sep 17 00:00:00 2001 From: millermk Date: Tue, 10 Sep 2024 21:01:54 -0600 Subject: [PATCH] fix(android): error loading resource redirects webview to resource url (#1354) * Add check for main frame * add change files, fix redirect --------- Co-authored-by: Lucas Nogueira --- ...fix-android-error-handling-page-visible.md | 5 +++ .../fix-request-error-handling-android.md | 5 +++ src/android/kotlin/RustWebViewClient.kt | 36 +++++++++++++------ 3 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 .changes/fix-android-error-handling-page-visible.md create mode 100644 .changes/fix-request-error-handling-android.md diff --git a/.changes/fix-android-error-handling-page-visible.md b/.changes/fix-android-error-handling-page-visible.md new file mode 100644 index 000000000..a14836c4f --- /dev/null +++ b/.changes/fix-android-error-handling-page-visible.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Fixes Android webview error page flashing when a redirect to the app is performed. diff --git a/.changes/fix-request-error-handling-android.md b/.changes/fix-request-error-handling-android.md new file mode 100644 index 000000000..c182ba7fb --- /dev/null +++ b/.changes/fix-request-error-handling-android.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +Fix navigation error handling to trigger custom protocol on Android. diff --git a/src/android/kotlin/RustWebViewClient.kt b/src/android/kotlin/RustWebViewClient.kt index 843451c39..402feebd1 100644 --- a/src/android/kotlin/RustWebViewClient.kt +++ b/src/android/kotlin/RustWebViewClient.kt @@ -8,12 +8,15 @@ import android.net.Uri import android.webkit.* import android.content.Context import android.graphics.Bitmap +import android.os.Handler +import android.os.Looper import androidx.webkit.WebViewAssetLoader class RustWebViewClient(context: Context): WebViewClient() { private val interceptedState = mutableMapOf() var currentUrl: String = "about:blank" - var lastInterceptedUrl: Uri? = null + private var lastInterceptedUrl: Uri? = null + private var pendingUrlRedirect: String? = null private val assetLoader = WebViewAssetLoader.Builder() .setDomain(assetLoaderDomain()) @@ -24,6 +27,14 @@ class RustWebViewClient(context: Context): WebViewClient() { view: WebView, request: WebResourceRequest ): WebResourceResponse? { + pendingUrlRedirect?.let { + Handler(Looper.getMainLooper()).post { + view.loadUrl(it) + } + pendingUrlRedirect = null + return null + } + lastInterceptedUrl = request.url return if (withAssetLoader()) { assetLoader.shouldInterceptRequest(request.url) @@ -53,7 +64,7 @@ class RustWebViewClient(context: Context): WebViewClient() { } override fun onPageFinished(view: WebView, url: String) { - return onPageLoaded(url) + onPageLoaded(url) } override fun onReceivedError( @@ -61,14 +72,19 @@ class RustWebViewClient(context: Context): WebViewClient() { request: WebResourceRequest, error: WebResourceError ) { - // we get a net::ERR_CONNECTION_REFUSED when an external URL redirects to a custom protocol - // e.g. oauth flow, because shouldInterceptRequest is not called on redirects - // so we must force retry here with loadUrl() to get a chance of the custom protocol to kick in - if (error.errorCode == ERROR_CONNECT && request.url != lastInterceptedUrl) { - view.loadUrl(request.url.toString()) - } else { - super.onReceivedError(view, request, error) - } + // we get a net::ERR_CONNECTION_REFUSED when an external URL redirects to a custom protocol + // e.g. oauth flow, because shouldInterceptRequest is not called on redirects + // so we must force retry here with loadUrl() to get a chance of the custom protocol to kick in + if (error.errorCode == ERROR_CONNECT && request.isForMainFrame && request.url != lastInterceptedUrl) { + // prevent the default error page from showing + view.stopLoading() + // without this initial loadUrl the app is stuck + view.loadUrl(request.url.toString()) + // ensure the URL is actually loaded - for some reason there's a race condition and we need to call loadUrl() again later + pendingUrlRedirect = request.url.toString() + } else { + super.onReceivedError(view, request, error) + } } companion object {