androidwebviewandroid-webviewwebviewclientwebviewchromium

WebViewClient.shouldOverrideUrlLoading() documentation clarification


Referring to the API level 24+ only version of shouldOverrideUrlLoading, the documentation clearly states:

Note: Do not call WebView#loadUrl(String) with the request's URL and then return true. This unnecessarily cancels the current load and starts a new load with the same URL. The correct way to continue loading a given URL is to simply return false, without calling WebView#loadUrl(String).

However, in my app I have to perform some extra activities before loading the URL that could only be done in MyWebView#loadUrl(String) and so I do call MyWebView#loadUrl from within MyWebViewClient#shouldOverrideUrlLoading then return true;.

This seems to work fine but I now have some doubts:

Does this warning about "the correct way to continue loading a given URL" mean that if I am not following it, this code could break

In what scenarios (e.g. frames, iframes, 301/302 redirects) this return true; scheme could break proper URL loading?


Solution

  • Based on Handle Custom URLs portion of WebView docs

    It is unlikely that your method will directly break with normal URLs as long as they're valid URLs that conform to RFC 3986.

    The primary concern with calling loadURL inside shouldOverrideUrlLoading is it makes your app inefficient and leads to excessive web traffic (and in most cases is unnecessary if you're not actually modifying the URL or calling a different web page based on some kind of custom input format.

    A way to rephrase would be to say, "If you're not changing the URL in shouldOverrideUrlLoading, then don't call loadURL again."

    Basically, you're calling a web request twice when you don't need to.

    In terms of returning true from shouldOverrideUrlLoading, the examples list a case where they return true because modification of the input URL was necessary, since they're using a custom format, that needs to be handled differently.

    // The URL scheme should be non-hierarchical (no trailing slashes)
    private static final String APP_SCHEME = "example-app:";
    
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith(APP_SCHEME)) {
            urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
            respondToData(urlData);
            return true;
        }
        return false;
    }
    

    In the above example, they're only overriding the behavior because they're using a custom format: <a href="example-app:showProfile">

    So the app says "its this weird custom developer defined format, rather than a normal URL, so the app should instead use this custom respondToData(urlData);"

    The issues you run into with WebView are like this question where you make your own custom URL, except then the implementation of WebView expects something different (namely, a valid URL based on web standards)

    This can be especially tricky if you are using a custom URL scheme or a base URL, that is not a valid URL that conforms to RFC 3986. In those cases you may not properly trigger the shouldOverrideUrlLoading() callback.

    You can also run into issues with URI Normalization if you're not expecting that behavior.

    As long as frames, iframes, and/or 301/302 redirects represent valid URL addresses and formats, then there should not be an issue. However, in those cases, as long as you're not changing the URL within shouldOverrideUrlLoading or using some type of custom response to the URL, then you don't need to call WebView#loadURL again.