compose-webview-multiplatform
compose-webview-multiplatform copied to clipboard
Add a way to override URL loading
The android implementation of WebViewClient
contains a method that can be used to intercept and override URLs being loaded by the webview: https://developer.android.com/reference/android/webkit/WebViewClient#shouldOverrideUrlLoading(android.webkit.WebView,%20android.webkit.WebResourceRequest)
It would be nice to have something similar here. :)
Didn't look at PRs, but looks like there is one for something like this here: https://github.com/KevinnZou/compose-webview-multiplatform/pull/52 (although it says "do not merge").
@rhappe Thank you for your feedback! We have begun working on supporting this feature, but we have encountered some issues. One problem we have encountered is that shouldOverrideUrlLoading does not intercept the first request. Could you please clarify what you specifically want to use shouldOverrideUrlLoading for? You can also check this issue for more information. Thanks!
@KevinnZou certainly! We have a WebView component in our compose multi-platform app which can list out different resources which we'd like to have launched in an external app (e.g. google docs/external browser). Another use case is the ability to sign out the user from a link/button in the webview, where we'd want the app to reactively navigate to the logged out app state.
It's great news that work has started on a feature like this. Can't wait to see it! I'll take a look at the issue thread you linked to get more context.
@rhappe Thanks for your explanation! I understand your needs, and it is also a capability we hope to support. However, I am currently facing some strange issues that may prevent us from supporting this feature in the short term.
The main problem is as follows: on the Android side, I attempted to override shouldOverrideUrlLoading to intercept WebView requests. However, during testing, I found that it can only intercept a very small portion of requests, which is completely different from the behavior I observed in native WebView testing. On the iOS side, I also encountered strange issues. I inherited WKNavigationDelegateProtocol and overrode decidePolicyForNavigationAction to intercept requests. However, it behaves similarly to Android, only randomly intercepting a small portion of requests.
I have been trying to resolve these issues for the past two weeks, but so far, I have made no progress. The only possible reason could be related to using it in Compose, but there is no substantial evidence to prove this yet. In this situation, I may need to invest my time in other tasks and return to researching this problem once they are resolved.
I have pushed my test code to this branch, and if you're interested, you can test it there. You are welcome to post any new discoveries here, and I would greatly appreciate it.
If I understand correctly, the objective of this is to override what is being loaded. I have been able to make that work reliably on Android for everything except the video tag preloading and post requests:
https://github.com/UstadMobile/UstadMobile/blob/primary/core/src/androidMain/kotlin/com/ustadmobile/core/domain/contententry/server/ContentEntryVersionServerWebClient.kt
I think the function shouldOverrideUrlLoading is deceptively named. I only use shouldOverrideUrlLoading as a means of catching link clicks. It is only triggered when the url of the webview itself is about to change (not called when scripts/css/images etc load). It also doesn't get called when the url change is via the hash.
I haven't found any need to override shouldOverrideUrlLoading. I just used shouldInterceptRequest.
@mikedawson Thanks for your suggestions! Yes, shouldInterceptRequest
does work for most URLs. However, it intercepts all the requests including resources. Furthermore, it does not support us in rejecting the URL loading like shouldOverrideUrlLoading
does. We actually have discussed this issue before and concluded that shouldOverrideUrlLoading
would be a better choice.
Our goal is to intercept URL requests and provide developers with the option to Accept, Modify, or Reject them. The shouldOverrideUrlLoading
method fulfills this requirement effectively in a raw Android project. However, it does not work properly in a Compose environment when intercepting most URL requests. If the reason for this issue cannot be identified, I think we can consider using the shouldInterceptRequest
method as a backup plan.
@KevinnZou is it possible in this case to resend headers when we navigate inside the webview? For my case I need to send an header to specify my website that I come from an mobile app. It works for the first webview, but not for the webview I open when I click inside a button or a link in my first webview.
@vivaCoda54 I understand your need. Unfortunately, we cannot add headers for the following navigation before we support shouldOverrideUrlLoading
. However, you can try using customUserAgentString
in WebSettings
to meet your needs. I apologize for any inconvenience caused. Please let me know if you encounter any further issues.
What is status of shouldOverrideUrlLoading?
@rhappe Thanks for your explanation! I understand your needs, and it is also a capability we hope to support. However, I am currently facing some strange issues that may prevent us from supporting this feature in the short term.
The main problem is as follows: on the Android side, I attempted to override shouldOverrideUrlLoading to intercept WebView requests. However, during testing, I found that it can only intercept a very small portion of requests, which is completely different from the behavior I observed in native WebView testing. On the iOS side, I also encountered strange issues. I inherited WKNavigationDelegateProtocol and overrode decidePolicyForNavigationAction to intercept requests. However, it behaves similarly to Android, only randomly intercepting a small portion of requests.
I have been trying to resolve these issues for the past two weeks, but so far, I have made no progress. The only possible reason could be related to using it in Compose, but there is no substantial evidence to prove this yet. In this situation, I may need to invest my time in other tasks and return to researching this problem once they are resolved.
I have pushed my test code to this branch, and if you're interested, you can test it there. You are welcome to post any new discoveries here, and I would greatly appreciate it.
@dilip640 Unfortunately, the issues mentioned above are yet to be resolved. It appears to be a problem with the Compose system, as it functions properly under the native raw Webview environment. However, without solving these issues, we cannot support shouldOverrideUrlLoading
. Thus, I am considering submitting the issue to Compose for an official solution. I apologize for the inconvenience caused by this issue. If you have a solution, please feel free to submit a PR.
FWIW, one use case for this feature request is to use the WebView for an in-app OAuth authorization flow: After the user authorized the app on the authorization provider's website, a callback url is called in the user's browser (or in this case: webview) that contains the authorization token. This callback url should not actually be loaded in the browser but passed on to the app that requested it.
Hi all, I have implemented a basic interception in the latest version 1.9.8. Please follow these instructions to conduct a test and let me know if you encounter any issues.
I migrated from a Fragment
to a Compose screen. (The code is here if you are interested)
I tested it, it works very well!, even on first try
Although, coming from the view system I find the API somewhat unintuitive - some handling is done in some LaunchedEffect
(e.g. errors), some in some interceptor class. But, I guess, one will just get used to that because that's just the Compose way.
Two remarks:
- why is the RequestInterceptor a class and not a lambda? It appears to me that the "Compose way" is to do everything with lambdas
- The documentation comment for
rememberSaveableWebViewState
states that one must use theWebViewNavigator
to actually navigate to an URL due to some Jetpack Compose reasons, I suppose. But then, I don't understand why theurl
parameter in that function is mandatory. It seems to lead to a duplication, like
val webViewState = rememberSaveableWebViewState(
url = myurl,
additionalHttpHeaders = myHttpheaders
)
val webViewNavigator = rememberWebViewNavigator()
LaunchedEffect(state) {
webViewNavigator.loadUrl(
url = myurl,
additionalHttpHeaders = myHttpheaders
)
}